pcmt/app/settings/settings.go

477 lines
12 KiB
Go
Raw Normal View History

2023-05-20 20:15:57 +02:00
// Copyright 2023 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: AGPL-3.0-only
package settings
import (
"os"
"time"
"git.dotya.ml/mirre-mt/pcmt/config"
"git.dotya.ml/mirre-mt/pcmt/slogging"
"golang.org/x/exp/slog"
)
type Settings struct {
host string
port int
appPath string
httpDomain string
httpSecure bool
httpGzipEnabled bool
httpGzipLevel int
httpRateLimitEnabled bool
httpRateLimit int
2023-09-08 17:48:51 +02:00
httpCSP string
isLive bool
isDevel bool
initCreateAdmin bool
initAdminPassword string
loggerJSON bool
sessionCookieName string
sessionCookieAuthSecret string
sessionCookieEncrSecret string
sessionAuthIsHex bool
sessionEncrIsHex bool
2023-08-04 18:28:56 +02:00
sessionMaxAge int
assetsPath string
templatesPath string
version string
dbConnstring string
dbType string
dbIsSetUp bool
RegistrationAllowed bool
hibpAPIKey string
dehashedAPIKey string
}
var log slogging.Slogger
// cleantgt is a list of ENV vars pertaining to pcmt.
var cleantgt = []string{
"PCMT_LIVE",
"PCMT_DEVEL",
"PCMT_CONNSTRING",
"PCMT_DBTYPE",
"PCMT_SESSION_AUTH_SECRET",
"PCMT_SESSION_ENCR_SECRET",
"PCMT_INIT_ADMIN_PASSWORD",
"PCMT_HIBP_API_KEY",
"PCMT_DEHASHED_API_KEY",
}
// New returns a new instance of the settings struct.
func New() *Settings {
return &Settings{}
}
// DefaultServerWriteTimeout returns the server default write timeout.
func (s *Settings) DefaultServerWriteTimeout() time.Duration {
return defaultServerWriteTimeout
}
// DefaultServerReadHeaderTimeout returns the server default read header timeout.
func (s *Settings) DefaultServerReadHeaderTimeout() time.Duration {
return defaultServerReadHeaderTimeout
}
// DefaultLoggerSkipAssets returns whether the logger skips reporting asset visits.
func (s *Settings) DefaultLoggerSkipAssets() bool {
return defaultLoggerSkipAssets
}
// Consolidate reconciles whatever values are set in config and via flags and
// sets it to one place that should be regarded as a single source of truth -
// the settings struct. Order of preference for values is (from higher to
// lower) as follows: flag -> Env var -> configuration file.
func (s *Settings) Consolidate(conf *config.Config, host *string, port *int, devel *bool, version string) {
log = *slogging.Logger() // have a local copy.
log.Logger = log.With(
slog.Group("pcmt extra", slog.String("module", "app/settings")),
)
log.Debug("starting to consolidate settings")
log.Debug("parsing config values")
2023-05-23 16:37:33 +02:00
if p := conf.Port; p > 0 && p < 65536 {
2023-08-20 23:01:27 +02:00
s.SetPort(conf.Port)
} else {
2023-08-04 18:31:45 +02:00
log.Warnf("port '%d', outside of bounds, setting a default of %d/tcp", p, defaultPort)
s.SetPort(defaultPort)
2023-05-23 16:37:33 +02:00
}
s.SetHost(conf.Host)
s.SetAppPath(conf.AppPath)
s.SetIsLive(conf.LiveMode)
s.SetIsDevel(conf.DevelMode)
s.SetLoggerIsJSON(conf.Logger.JSON)
if conf.HTTP.Secure {
// https://www.sjoerdlangkemper.nl/2017/02/09/cookie-prefixes/
// https://scotthelme.co.uk/tough-cookies/
// https://check-your-website.server-daten.de/prefix-cookies.html
s.SetSessionCookieName("__Host-" + conf.Session.CookieName)
} else {
s.SetSessionCookieName(conf.Session.CookieName)
}
2023-09-04 21:02:06 +02:00
s.SetSessionMaxAge(conf.Session.MaxAge)
s.SetSessionCookieAuthSecret(conf.Session.CookieAuthSecret)
s.SetSessionCookieEncrSecret(conf.Session.CookieEncrSecret)
authHex, encrHex := conf.SessionSecretsAreHex()
if authHex {
s.sessionAuthIsHex = true
}
if encrHex {
s.sessionEncrIsHex = true
}
2023-09-08 17:48:51 +02:00
if conf.Init.CreateAdmin {
s.SetInitCreateAdmin(true)
s.SetInitAdminPassword(conf.Init.AdminPassword)
}
if conf.Registration.Allowed {
s.RegistrationAllowed = true
}
if conf.HTTP.Gzip > 0 {
s.SetHTTPGzipEnabled(true)
s.SetHTTPGzipLevel(conf.HTTP.Gzip)
}
if conf.HTTP.RateLimit > 0 {
s.SetHTTPRateLimitEnabled(true)
s.SetHTTPRateLimit(conf.HTTP.RateLimit)
}
2023-09-08 17:48:51 +02:00
s.SetHTTPCSP(conf.HTTP.ContentSecurityPolicy)
s.SetHTTPDomain(conf.HTTP.Domain)
s.SetHTTPSecure(conf.HTTP.Secure)
s.setAPIKeys()
s.sortOutFlags(conf, host, port, devel)
s.SetVersion(version)
}
// Host returns the host.
func (s *Settings) Host() string {
return s.host
}
// Port returns the port.
func (s *Settings) Port() int {
return s.port
}
// AppName returns the appName.
func (s *Settings) AppName() string {
return defaultAppName
}
// AppPath returns the appPath.
func (s *Settings) AppPath() string {
return s.appPath
}
// IsLive returns the value of isLive of the receiver.
func (s *Settings) IsLive() bool {
return s.isLive
}
// IsDevel returns the value of isDevel of the receiver.
func (s *Settings) IsDevel() bool {
return s.isDevel
}
// InitCreateAdmin returns the value of initCreateAdmin of the receiver.
func (s *Settings) InitCreateAdmin() bool {
return s.initCreateAdmin
}
// InitAdminPassword returns the value of initAdminPassword of the receiver.
func (s *Settings) InitAdminPassword() string {
return s.initAdminPassword
}
// LoggerIsJSON returns whether the logger should use the JSON handler.
func (s *Settings) LoggerIsJSON() bool {
return s.loggerJSON
}
// SessionCookieName returns the name of the session cookie.
func (s *Settings) SessionCookieName() string {
return s.sessionCookieName
}
// SessionCookieAuthSecret returns the session cookie authentication secret.
func (s *Settings) SessionCookieAuthSecret() string {
return s.sessionCookieAuthSecret
}
// SessionCookieEncrSecret returns the session cookie encryption secret.
func (s *Settings) SessionCookieEncrSecret() string {
return s.sessionCookieEncrSecret
}
// SessionAuthIsHex returns whether the session cookie authentication secret is hex.
func (s *Settings) SessionAuthIsHex() bool {
return s.sessionAuthIsHex
}
// SessionEncrIsHex returns whether the session cookie encryption secret is hex.
func (s *Settings) SessionEncrIsHex() bool {
return s.sessionEncrIsHex
}
2023-08-04 18:28:56 +02:00
// SessionMaxAge returns the session cookie MaxAge value.
func (s *Settings) SessionMaxAge() int {
return s.sessionMaxAge
}
// HTTPDomain returns the httpDomain.
func (s *Settings) HTTPDomain() string {
return s.httpDomain
}
// HTTPSecure returns the httpSecure.
func (s *Settings) HTTPSecure() bool {
return s.httpSecure
}
// HTTPGzipEnabled returns the httpGzipEnabled variable.
func (s *Settings) HTTPGzipEnabled() bool {
return s.httpGzipEnabled
}
// HTTPGzipLevel returns the httpGzipLevel.
func (s *Settings) HTTPGzipLevel() int {
return s.httpGzipLevel
}
// HTTPRateLimitEnabled returns the httpRateLimitEnabled variable.
func (s *Settings) HTTPRateLimitEnabled() bool {
return s.httpRateLimitEnabled
}
// HTTPRateLimit returns the httpRateLimit.
func (s *Settings) HTTPRateLimit() int {
return s.httpRateLimit
}
2023-09-08 17:48:51 +02:00
// HTTPCSP returns the httpCSP.
func (s *Settings) HTTPCSP() string {
return s.httpCSP
}
// AssetsPath returns the assetsPath.
func (s *Settings) AssetsPath() string {
return s.assetsPath
}
// TemplatesPath returns the templatesPath.
func (s *Settings) TemplatesPath() string {
return s.templatesPath
}
// Version returns the version.
func (s *Settings) Version() string {
return s.version
}
// DbIsSetUp returns the dbIsSetUp.
func (s *Settings) DbIsSetUp() bool {
return s.dbIsSetUp
}
// APIKeyHIBP returns the hibpAPIKey.
func (s *Settings) APIKeyHIBP() string {
return s.hibpAPIKey
}
// APIKeyDehashed returns the dehashedAPIKey.
func (s *Settings) APIKeyDehashed() string {
return s.dehashedAPIKey
}
// DbConnstring returns the dbConnString.
func (s *Settings) DbConnstring() string {
return s.dbConnstring
}
// DbType returns the dbType.
func (s *Settings) DbType() string {
return s.dbType
}
// SetHost sets the host.
func (s *Settings) SetHost(host string) {
s.host = host
}
// SetPort sets the port.
func (s *Settings) SetPort(port int) {
s.port = port
}
// SetAppPath sets the appPath.
func (s *Settings) SetAppPath(appPath string) {
s.appPath = appPath
}
// SetIsLive sets the value of isLive of the receiver.
func (s *Settings) SetIsLive(live bool) {
s.isLive = live
}
// SetIsDevel sets the value of isDevel of the receiver.
func (s *Settings) SetIsDevel(devel bool) {
s.isDevel = devel
}
// SetInitCreateAdmin sets the value of initCreateAdmin of the receiver.
func (s *Settings) SetInitCreateAdmin(create bool) {
s.initCreateAdmin = create
}
// SetInitAdminPassword sets the value of initAdminPassword of the receiver.
func (s *Settings) SetInitAdminPassword(password string) {
s.initAdminPassword = password
}
// SetLoggerIsJSON sets the setting value of loggerIsJSON.
func (s *Settings) SetLoggerIsJSON(isJSON bool) {
s.loggerJSON = isJSON
}
// SetSessionCookieName sets session cookie name.
func (s *Settings) SetSessionCookieName(sessionCookieName string) {
s.sessionCookieName = sessionCookieName
}
// SetSessionCookieAuthSecret sets the session cookie authentication secret.
func (s *Settings) SetSessionCookieAuthSecret(sessionCookieAuthSecret string) {
s.sessionCookieAuthSecret = sessionCookieAuthSecret
}
// SetSessionCookieEncrSecret sets the session cookie encryption secret.
func (s *Settings) SetSessionCookieEncrSecret(sessionCookieEncrSecret string) {
s.sessionCookieEncrSecret = sessionCookieEncrSecret
}
2023-08-04 18:28:56 +02:00
// SetSessionMaxAge sets sessionMaxAge.
func (s *Settings) SetSessionMaxAge(sessionMaxAge int) {
if sessionMaxAge < 1 {
2023-09-04 21:02:06 +02:00
log.Debug("setting cookie max age to the default")
2023-08-04 18:31:45 +02:00
s.sessionMaxAge = defaultSessionMaxAge
2023-08-04 18:28:56 +02:00
} else {
2023-09-04 21:02:06 +02:00
log.Debug("setting cookie max age to a config-provided value", "maxAge", sessionMaxAge)
2023-08-04 18:28:56 +02:00
s.sessionMaxAge = sessionMaxAge
}
}
// SetHTTPDomain sets the httpDomain.
func (s *Settings) SetHTTPDomain(domain string) {
2023-08-04 17:19:06 +02:00
switch domain {
case "":
2023-08-04 18:31:45 +02:00
s.httpDomain = defaultHTTPDomain
2023-08-04 17:19:06 +02:00
default:
s.httpDomain = domain
}
}
// SetHTTPSecure sets the httpSecure.
func (s *Settings) SetHTTPSecure(secure bool) {
s.httpSecure = secure
}
// SetHTTPGzipEnabled sets the httpGzipEnabled variable.
func (s *Settings) SetHTTPGzipEnabled(enabled bool) {
s.httpGzipEnabled = enabled
}
// SetHTTPGzipLevel sets the httpGzipLevel.
func (s *Settings) SetHTTPGzipLevel(level int) {
s.httpGzipLevel = level
}
// SetHTTPRateLimitEnabled sets the httpRateLimitEnabled variable.
func (s *Settings) SetHTTPRateLimitEnabled(enabled bool) {
s.httpRateLimitEnabled = enabled
}
// SetHTTPRateLimit sets the httpRateLimit.
func (s *Settings) SetHTTPRateLimit(rateLimit int) {
s.httpRateLimit = rateLimit
}
2023-09-08 17:48:51 +02:00
// SetHTTPCSP sets the content security policy.
func (s *Settings) SetHTTPCSP(csp string) {
switch csp {
case "":
if s.isDevel {
s.httpCSP = defaultCSPDevel
} else {
s.httpCSP = defaultCSP
}
default:
s.httpCSP = csp
}
}
// SetAssetsPath sets the assetsPath.
func (s *Settings) SetAssetsPath(assetsPath string) {
s.assetsPath = assetsPath
}
// SetTemplatesPath sets the templatesPath.
func (s *Settings) SetTemplatesPath(templatesPath string) {
s.templatesPath = templatesPath
}
// SetVersion sets the version.
func (s *Settings) SetVersion(version string) {
s.version = version
}
// SetDbConnstring sets the dbConnString.
func (s *Settings) SetDbConnstring(connstring string) {
s.dbConnstring = connstring
}
// SetDbType sets the dbType.
func (s *Settings) SetDbType(dbType string) {
s.dbType = dbType
}
// SetDbIsSetUp sets the dbIsSetUp.
func (s *Settings) SetDbIsSetUp(is bool) {
s.dbIsSetUp = is
}
// SetAPIKeyHIBP sets the hibpAPIKey.
func (s *Settings) SetAPIKeyHIBP(k string) {
s.hibpAPIKey = k
}
// SetAPIKeyDehashed sets the dehashedAPIKey.
func (s *Settings) SetAPIKeyDehashed(k string) {
s.dehashedAPIKey = k
}
// EraseENVs attempts to clear environment vars pertaining to pcmt.
func (s *Settings) EraseENVs() error {
for _, v := range cleantgt {
err := os.Unsetenv(v)
if err != nil {
return err
}
}
return nil
}