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"
|
2023-08-18 19:11:20 -03:00
|
|
|
// 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
|
|
|
}
|