goshort/internal/config/config.go

224 lines
7.1 KiB
Go
Raw Permalink Normal View History

2023-09-06 13:00:56 -03:00
//nolint:forbidigo // Allow printing for prettyprint
2023-08-17 14:14:59 -03:00
package config
import (
"fmt"
"net"
"net/url"
"time"
2023-08-27 20:44:58 -03:00
errs "git.maronato.dev/maronato/goshort/internal/errs"
2023-08-17 14:14:59 -03:00
)
const (
2023-08-30 21:03:44 -03:00
DBTypeMemory = "memory"
DBTypeSQLite = "sqlite"
2023-08-17 14:14:59 -03:00
)
2023-08-26 11:47:46 -03:00
func GetDBTypeList() []string {
return []string{
DBTypeMemory,
DBTypeSQLite,
}
2023-08-17 14:14:59 -03:00
}
2023-09-06 18:43:56 -03:00
type VerboseLevel int
const (
VerboseLevelQuiet VerboseLevel = iota - 1
VerboseLevelInfo
VerboseLevelAccessLogs
VerboseLevelDebug
)
2023-08-17 14:14:59 -03:00
const (
2023-08-24 22:03:58 -03:00
// DefaultProd is the default mode.
DefaultProd = false
2023-08-17 14:14:59 -03:00
// DefaultDBType is the default type of database to use.
2023-08-24 22:03:58 -03:00
DefaultDBType = DBTypeSQLite
2023-08-17 14:14:59 -03:00
// DefaultDBURL is the default connection string for the database.
DefaultDBURL = "goshort.db"
// DefaultPort is the default port to listen on.
DefaultPort = "8080"
// DefaultHost is the default host to listen on. This is set to 0.0.0.0 when running in Docker.
DefaultHost = "localhost"
2023-08-17 14:14:59 -03:00
// DefaultUIPort is the default port to listen on for the UI.
DefaultUIPort = "3000"
// DefaultDebug is the default debug mode.
DefaultDebug = false
// DefaultSessionDuration is the default session duration.
DefaultSessionDuration = 7 * 24 * time.Hour
2023-08-17 19:55:08 -03:00
// DefaultDisableRegistration is the default value for diable registration.
DefaultDisableRegistration = false
2023-09-06 18:43:56 -03:00
// DefaultVerbose is the default verbosity level.
DefaultVerbose = VerboseLevelInfo
// DefaultQuiet is the default quiet mode.
DefaultQuiet = false
2024-03-09 06:44:22 -03:00
// DefaultDisableCredentialsLogin is the default value for diable credential login.
DefaultDisableCredentialsLogin = false
2024-03-09 07:42:36 -03:00
// DefaultOIDCIssuerName is the default name of the OIDC issuer.
DefaultOIDCIssuerName = "OpenID"
2023-08-17 14:14:59 -03:00
)
const (
// ReadTimeout is the maximum duration for reading the entire
// request, including the body.
ReadTimeout = 5 * time.Second
// WriteTimeout is the maximum duration before timing out
// writes of the response.
WriteTimeout = 10 * time.Second
// IdleTimeout is the maximum amount of time to wait for the
// next request when keep-alives are enabled.
IdleTimeout = 30 * time.Second
// ReadHeaderTimeout is the amount of time allowed to read
// request headers.
ReadHeaderTimeout = 2 * time.Second
// RequestTimeout is the maximum duration for the entire
// request.
RequestTimeout = 7 * 24 * time.Hour
)
// Config defines the default configuration for the backend.
type Config struct {
// Prod is a flag that indicates if the server is running in production mode.
2024-03-09 06:44:22 -03:00
Prod bool `json:"prod"`
2023-08-17 14:14:59 -03:00
// Debug is a flag that indicates if the server is running in debug mode.
2023-08-17 19:55:08 -03:00
Debug bool
2023-08-17 14:14:59 -03:00
// Host is the host to listen on.
2023-08-17 19:55:08 -03:00
Host string
2023-08-17 14:14:59 -03:00
// Port is the port to listen on.
2023-08-17 19:55:08 -03:00
Port string
2023-08-17 14:14:59 -03:00
// UiPort is the port to listen on for the UI.
2023-08-17 19:55:08 -03:00
UIPort string
2023-08-17 14:14:59 -03:00
// DBType is the type of database to use.
2023-08-17 19:55:08 -03:00
DBType string
2023-08-17 14:14:59 -03:00
// DBURL is the connection string for the database.
2023-08-17 19:55:08 -03:00
DBURL string
2023-08-17 14:14:59 -03:00
// SessionDuration is the duration of the session.
2023-08-17 19:55:08 -03:00
SessionDuration time.Duration
// DisableRegistration defines whether or not registration are disabled.
2024-03-09 06:44:22 -03:00
DisableRegistration bool `json:"disableRegistration"`
2023-09-06 18:43:56 -03:00
// Verbose defines the verbosity level.
2024-03-09 06:44:22 -03:00
Verbose VerboseLevel `json:"verbose"`
2023-09-06 18:43:56 -03:00
// Quiet defines whether or not the server should be quiet.
Quiet bool
2024-03-09 06:44:22 -03:00
// DisableCredentialsLogin defines whether or not the server should disable credential login.
DisableCredentialsLogin bool `json:"disableCredentialLogin"`
// OIDCIssuerURL is the URL of the OIDC issuer.
2024-03-09 07:42:36 -03:00
OIDCIssuerURL string `json:"oidcIssuerUrl"`
// OIDCIssueName is the name of the OIDC issuer.
OIDCIssuerName string
2024-03-09 06:44:22 -03:00
// OIDCClientID is the client ID for OIDC.
OIDCClientID string
// OIDCClientSecret is the client secret for OIDC.
OIDCClientSecret string
// OIDCRedirectURL is the redirect URL for OIDC.
OIDCRedirectURL string
2023-08-17 14:14:59 -03:00
}
2023-09-06 12:38:27 -03:00
func NewConfig() *Config {
return &Config{
2024-03-09 06:44:22 -03:00
Prod: DefaultProd,
Debug: DefaultDebug,
Host: DefaultHost,
Port: DefaultPort,
UIPort: DefaultUIPort,
DBType: DefaultDBType,
DBURL: DefaultDBURL,
SessionDuration: DefaultSessionDuration,
DisableRegistration: DefaultDisableRegistration,
Verbose: DefaultVerbose,
Quiet: DefaultQuiet,
DisableCredentialsLogin: DefaultDisableCredentialsLogin,
2024-03-09 07:42:36 -03:00
OIDCIssuerName: DefaultOIDCIssuerName,
2023-09-06 12:38:27 -03:00
}
}
2023-09-06 18:43:56 -03:00
// Validate validates the configuration modifies user-inaccessible fields.
2023-08-17 14:14:59 -03:00
func Validate(cfg *Config) error {
// Host and port have to be valid.
if _, err := url.ParseRequestURI("http://" + net.JoinHostPort(cfg.Host, cfg.Port)); err != nil {
2023-08-23 19:30:12 -03:00
return errs.Errorf(fmt.Sprintf("invalid host and/or port: %s", err), errs.ErrInvalidConfig)
2023-08-17 14:14:59 -03:00
}
// UI port has to be valid.
if cfg.UIPort != "" {
if _, err := url.ParseRequestURI("http://" + net.JoinHostPort(cfg.Host, cfg.UIPort)); err != nil {
2023-08-23 19:30:12 -03:00
return errs.Errorf(fmt.Sprintf("invalid UI port: %s", err), errs.ErrInvalidConfig)
2023-08-17 14:14:59 -03:00
}
}
2023-08-26 11:47:46 -03:00
2023-09-06 18:43:56 -03:00
// Verbose has to be valid.
if cfg.Verbose < VerboseLevelInfo || cfg.Verbose > VerboseLevelDebug {
return errs.Errorf(fmt.Sprintf("invalid verbosity level: %d", cfg.Verbose), errs.ErrInvalidConfig)
}
if cfg.Verbose != VerboseLevelInfo && cfg.Quiet {
return errs.Errorf("cannot set both verbose and quiet", errs.ErrInvalidConfig)
}
2023-08-17 14:14:59 -03:00
if cfg.DBType != "" {
// DB type has to be valid.
valid := false
2023-08-26 11:47:46 -03:00
for _, dbType := range GetDBTypeList() {
2023-08-17 14:14:59 -03:00
if cfg.DBType == dbType {
valid = true
2023-08-26 11:47:46 -03:00
2023-08-17 14:14:59 -03:00
break
}
}
2023-08-26 11:47:46 -03:00
2023-08-17 14:14:59 -03:00
if !valid {
2023-08-23 19:30:12 -03:00
return errs.Errorf(fmt.Sprintf("invalid database type: %s", cfg.DBType), errs.ErrInvalidConfig)
2023-08-17 14:14:59 -03:00
}
}
2023-09-06 18:43:56 -03:00
// If verbose == 2, set debug to true for backwards compatibility.
if cfg.Verbose >= VerboseLevelDebug {
cfg.Debug = true
}
// If quiet is true, set verbose to -1.
if cfg.Quiet {
cfg.Verbose = VerboseLevelQuiet
}
2024-03-09 06:44:22 -03:00
// Either OIDC or credential login has to be enabled.
if cfg.DisableCredentialsLogin && cfg.OIDCIssuerURL == "" {
return errs.Errorf("either OIDC or credential login has to be enabled", errs.ErrInvalidConfig)
}
if cfg.OIDCIssuerURL != "" {
// If OIDC is enabled, all OIDC fields have to be set.
if cfg.OIDCClientID == "" || cfg.OIDCClientSecret == "" || cfg.OIDCRedirectURL == "" {
return errs.Errorf("all OIDC fields have to be set", errs.ErrInvalidConfig)
}
// OIDC fields must be valid
if _, err := url.ParseRequestURI(cfg.OIDCIssuerURL); err != nil {
return errs.Errorf(fmt.Sprintf("invalid OIDC issuer URL: %s", err), errs.ErrInvalidConfig)
}
if _, err := url.ParseRequestURI(cfg.OIDCRedirectURL); err != nil {
return errs.Errorf(fmt.Sprintf("invalid OIDC redirect URL: %s", err), errs.ErrInvalidConfig)
}
}
2023-08-17 14:14:59 -03:00
return nil
}
2023-09-06 13:00:56 -03:00
func (c *Config) PrettyPrint() {
fmt.Println("Configuration:")
fmt.Println(" - Production mode:", c.Prod)
fmt.Println(" - Debug mode:", c.Debug)
fmt.Println(" - Host:", c.Host)
fmt.Println(" - Port:", c.Port)
fmt.Println(" - UI Port:", c.UIPort)
fmt.Println(" - Database type:", c.DBType)
fmt.Println(" - Database URL:", c.DBURL)
fmt.Println(" - Session duration:", c.SessionDuration)
fmt.Println(" - Disable registration:", c.DisableRegistration)
2023-09-06 18:43:56 -03:00
fmt.Println(" - Verbose level:", c.Verbose)
fmt.Println(" - Quiet mode:", c.Quiet)
2023-09-06 13:00:56 -03:00
}