pcmt/app/settings/settings.go

482 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
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
}
2023-08-04 18:31:45 +02:00
const (
appName = "pcmt"
defaultPort = 3000
defaultSessionMaxAge = 86400 // seconds.
defaultHTTPDomain = "localhost"
defaultServerWriteTimeout = 30 * time.Second
defaultServerReadHeaderTimeout = 30 * time.Second
defaultLoggerSkipAssets = true
2023-08-04 18:31:45 +02:00
)
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)
s.SetSessionCookieName(conf.Session.CookieName)
s.SetSessionCookieAuthSecret(conf.Session.CookieAuthSecret)
s.SetSessionCookieEncrSecret(conf.Session.CookieEncrSecret)
authHex, encrHex := conf.SessionSecretsAreHex()
if authHex {
s.sessionAuthIsHex = true
}
if encrHex {
s.sessionEncrIsHex = 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)
}
if conf.Init.CreateAdmin {
s.SetInitCreateAdmin(true)
s.SetInitAdminPassword(conf.Init.AdminPassword)
}
s.SetHTTPDomain(conf.HTTP.Domain)
s.SetHTTPSecure(conf.HTTP.Secure)
log.Debug("checking flag overrides")
overrideMsg := "overriding '%s' based on a flag: %+v"
if isFlagPassed("host") {
if h := *host; h != "unset" && h != conf.Host {
log.Debugf(overrideMsg, "host", h)
s.SetHost(h)
}
}
if isFlagPassed("port") {
2023-05-23 16:37:33 +02:00
if p := *port; p > 0 && p < 65536 {
if p != conf.Port {
log.Debugf(overrideMsg, "port", p)
s.SetPort(p)
}
} else {
log.Warnf("flag-supplied port '%d' outside of bounds, ignoring", p)
}
}
if isFlagPassed("devel") {
if d := *devel; d != conf.DevelMode {
log.Debugf(overrideMsg, "develMode", d)
s.SetIsDevel(d)
}
}
if conf.Registration.Allowed {
s.RegistrationAllowed = true
}
s.setAPIKeys()
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 appName
}
// 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
}
// 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-08-04 18:31:45 +02:00
s.sessionMaxAge = defaultSessionMaxAge
2023-08-04 18:28:56 +02:00
} else {
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
}
// 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
}