mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-28 04:03:32 -06:00
[chore] Global server configuration overhaul (#575)
* move config flag names and usage to config package, rewrite config package to use global Configuration{} struct
Signed-off-by: kim <grufwub@gmail.com>
* improved code comment
Signed-off-by: kim <grufwub@gmail.com>
* linter
Signed-off-by: kim <grufwub@gmail.com>
* fix unmarshaling
Signed-off-by: kim <grufwub@gmail.com>
* remove kim's custom go compiler changes
Signed-off-by: kim <grufwub@gmail.com>
* generate setter and flag-name functions, implement these in codebase
Signed-off-by: kim <grufwub@gmail.com>
* update deps
Signed-off-by: kim <grufwub@gmail.com>
* small change
Signed-off-by: kim <grufwub@gmail.com>
* appease the linter...
Signed-off-by: kim <grufwub@gmail.com>
* move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync
Signed-off-by: kim <grufwub@gmail.com>
* lint
Signed-off-by: kim <grufwub@gmail.com>
* update code comments
Signed-off-by: kim <grufwub@gmail.com>
* fix merge issue
Signed-off-by: kim <grufwub@gmail.com>
* fix merge issue
Signed-off-by: kim <grufwub@gmail.com>
* improved version string (removes time + go version)
Signed-off-by: kim <grufwub@gmail.com>
* fix version string build to pass test script + consolidate logic in func
Signed-off-by: kim <grufwub@gmail.com>
* add license text, update config.Defaults comment
Signed-off-by: kim <grufwub@gmail.com>
* add license text to generated config helpers file
Signed-off-by: kim <grufwub@gmail.com>
* defer unlock on config.Set___(), to ensure unlocked on panic
Signed-off-by: kim <grufwub@gmail.com>
* make it more obvious which cmd flags are being attached
Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
ae5402ada6
commit
43ac0cdb9c
90 changed files with 2450 additions and 1125 deletions
139
internal/config/config.go
Normal file
139
internal/config/config.go
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// cfgtype is the reflected type information of Configuration{}.
|
||||
var cfgtype = reflect.TypeOf(Configuration{})
|
||||
|
||||
// fieldtag will fetch the string value for the given tag name
|
||||
// on the given field name in the Configuration{} struct.
|
||||
func fieldtag(field, tag string) string {
|
||||
sfield, ok := cfgtype.FieldByName(field)
|
||||
if !ok {
|
||||
panic("unknown struct field")
|
||||
}
|
||||
return sfield.Tag.Get(tag)
|
||||
}
|
||||
|
||||
// Configuration represents global GTS server runtime configuration.
|
||||
//
|
||||
// Please note that if you update this struct's fields or tags, you
|
||||
// will need to regenerate the global Getter/Setter helpers by running:
|
||||
// `go run ./internal/config/gen/ -out ./internal/config/helpers.gen.go`
|
||||
type Configuration struct {
|
||||
LogLevel string `name:"log-level" usage:"Log level to run at: [trace, debug, info, warn, fatal]"`
|
||||
LogDbQueries bool `name:"log-db-queries" usage:"Log database queries verbosely when log-level is trace or debug"`
|
||||
ApplicationName string `name:"application-name" usage:"Name of the application, used in various places internally"`
|
||||
ConfigPath string `name:"config-path" usage:"Path to a file containing gotosocial configuration. Values set in this file will be overwritten by values set as env vars or arguments"`
|
||||
Host string `name:"host" usage:"Hostname to use for the server (eg., example.org, gotosocial.whatever.com). DO NOT change this on a server that's already run!"`
|
||||
AccountDomain string `name:"account-domain" usage:"Domain to use in account names (eg., example.org, whatever.com). If not set, will default to the setting for host. DO NOT change this on a server that's already run!"`
|
||||
Protocol string `name:"protocol" usage:"Protocol to use for the REST api of the server (only use http if you are debugging or behind a reverse proxy!)"`
|
||||
BindAddress string `name:"bind-address" usage:"Bind address to use for the GoToSocial server (eg., 0.0.0.0, 172.138.0.9, [::], localhost). For ipv6, enclose the address in square brackets, eg [2001:db8::fed1]. Default binds to all interfaces."`
|
||||
Port int `name:"port" usage:"Port to use for GoToSocial. Change this to 443 if you're running the binary directly on the host machine."`
|
||||
TrustedProxies []string `name:"trusted-proxies" usage:"Proxies to trust when parsing x-forwarded headers into real IPs."`
|
||||
SoftwareVersion string `name:"software-version" usage:""`
|
||||
|
||||
DbType string `name:"db-type" usage:"Database type: eg., postgres"`
|
||||
DbAddress string `name:"db-address" usage:"Database ipv4 address, hostname, or filename"`
|
||||
DbPort int `name:"db-port" usage:"Database port"`
|
||||
DbUser string `name:"db-user" usage:"Database username"`
|
||||
DbPassword string `name:"db-password" usage:"Database password"`
|
||||
DbDatabase string `name:"db-database" usage:"Database name"`
|
||||
DbTLSMode string `name:"db-tls-mode" usage:"Database tls mode"`
|
||||
DbTLSCACert string `name:"db-tls-ca-cert" usage:"Path to CA cert for db tls connection"`
|
||||
|
||||
WebTemplateBaseDir string `name:"web-template-base-dir" usage:"Basedir for html templating files for rendering pages and composing emails."`
|
||||
WebAssetBaseDir string `name:"web-asset-base-dir" usage:"Directory to serve static assets from, accessible at example.org/assets/"`
|
||||
|
||||
AccountsRegistrationOpen bool `name:"accounts-registration-open" usage:"Allow anyone to submit an account signup request. If false, server will be invite-only."`
|
||||
AccountsApprovalRequired bool `name:"accounts-approval-required" usage:"Do account signups require approval by an admin or moderator before user can log in? If false, new registrations will be automatically approved."`
|
||||
AccountsReasonRequired bool `name:"accounts-reason-required" usage:"Do new account signups require a reason to be submitted on registration?"`
|
||||
|
||||
MediaImageMaxSize int `name:"media-image-max-size" usage:"Max size of accepted images in bytes"`
|
||||
MediaVideoMaxSize int `name:"media-video-max-size" usage:"Max size of accepted videos in bytes"`
|
||||
MediaDescriptionMinChars int `name:"media-description-min-chars" usage:"Min required chars for an image description"`
|
||||
MediaDescriptionMaxChars int `name:"media-description-max-chars" usage:"Max permitted chars for an image description"`
|
||||
MediaRemoteCacheDays int `name:"media-remote-cache-days" usage:"Number of days to locally cache media from remote instances. If set to 0, remote media will be kept indefinitely."`
|
||||
|
||||
StorageBackend string `name:"storage-backend" usage:"Storage backend to use for media attachments"`
|
||||
StorageLocalBasePath string `name:"storage-local-base-path" usage:"Full path to an already-created directory where gts should store/retrieve media files. Subfolders will be created within this dir."`
|
||||
|
||||
StatusesMaxChars int `name:"statuses-max-chars" usage:"Max permitted characters for posted statuses"`
|
||||
StatusesCWMaxChars int `name:"statuses-cw-max-chars" usage:"Max permitted characters for content/spoiler warnings on statuses"`
|
||||
StatusesPollMaxOptions int `name:"statuses-poll-max-options" usage:"Max amount of options permitted on a poll"`
|
||||
StatusesPollOptionMaxChars int `name:"statuses-poll-option-max-chars" usage:"Max amount of characters for a poll option"`
|
||||
StatusesMediaMaxFiles int `name:"statuses-media-max-files" usage:"Maximum number of media files/attachments per status"`
|
||||
|
||||
LetsEncryptEnabled bool `name:"letsencrypt-enabled" usage:"Enable letsencrypt TLS certs for this server. If set to true, then cert dir also needs to be set (or take the default)."`
|
||||
LetsEncryptPort int `name:"letsencrypt-port" usage:"Port to listen on for letsencrypt certificate challenges. Must not be the same as the GtS webserver/API port."`
|
||||
LetsEncryptCertDir string `name:"letsencrypt-cert-dir" usage:"Directory to store acquired letsencrypt certificates."`
|
||||
LetsEncryptEmailAddress string `name:"letsencrypt-email-address" usage:"Email address to use when requesting letsencrypt certs. Will receive updates on cert expiry etc."`
|
||||
|
||||
OIDCEnabled bool `name:"oidc-enabled" usage:"Enabled OIDC authorization for this instance. If set to true, then the other OIDC flags must also be set."`
|
||||
OIDCIdpName string `name:"oidc-idp-name" usage:"Name of the OIDC identity provider. Will be shown to the user when logging in."`
|
||||
OIDCSkipVerification bool `name:"oidc-skip-verification" usage:"Skip verification of tokens returned by the OIDC provider. Should only be set to 'true' for testing purposes, never in a production environment!"`
|
||||
OIDCIssuer string `name:"oidc-issuer" usage:"Address of the OIDC issuer. Should be the web address, including protocol, at which the issuer can be reached. Eg., 'https://example.org/auth'"`
|
||||
OIDCClientID string `name:"oidc-client-id" usage:"ClientID of GoToSocial, as registered with the OIDC provider."`
|
||||
OIDCClientSecret string `name:"oidc-client-secret" usage:"ClientSecret of GoToSocial, as registered with the OIDC provider."`
|
||||
OIDCScopes []string `name:"oidc-scopes" usage:"OIDC scopes."`
|
||||
|
||||
SMTPHost string `name:"smtp-host" usage:"Host of the smtp server. Eg., 'smtp.eu.mailgun.org'"`
|
||||
SMTPPort int `name:"smtp-port" usage:"Port of the smtp server. Eg., 587"`
|
||||
SMTPUsername string `name:"smtp-username" usage:"Username to authenticate with the smtp server as. Eg., 'postmaster@mail.example.org'"`
|
||||
SMTPPassword string `name:"smtp-password" usage:"Password to pass to the smtp server."`
|
||||
SMTPFrom string `name:"smtp-from" usage:"Address to use as the 'from' field of the email. Eg., 'gotosocial@example.org'"`
|
||||
|
||||
SyslogEnabled bool `name:"syslog-enabled" usage:"Enable the syslog logging hook. Logs will be mirrored to the configured destination."`
|
||||
SyslogProtocol string `name:"syslog-protocol" usage:"Protocol to use when directing logs to syslog. Leave empty to connect to local syslog."`
|
||||
SyslogAddress string `name:"syslog-address" usage:"Address:port to send syslog logs to. Leave empty to connect to local syslog."`
|
||||
|
||||
// TODO: move these elsewhere, these are more ephemeral vs long-running flags like above
|
||||
AdminAccountUsername string `name:"username" usage:"the username to create/delete/etc"`
|
||||
AdminAccountEmail string `name:"email" usage:"the email address of this account"`
|
||||
AdminAccountPassword string `name:"password" usage:"the password to set for this account"`
|
||||
AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"`
|
||||
}
|
||||
|
||||
// MarshalMap will marshal current Configuration into a map structure (useful for JSON).
|
||||
func (cfg *Configuration) MarshalMap() (map[string]interface{}, error) {
|
||||
var dst map[string]interface{}
|
||||
dec, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
TagName: "name",
|
||||
Result: &dst,
|
||||
})
|
||||
if err := dec.Decode(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// UnmarshalMap will unmarshal a map structure into the receiving Configuration.
|
||||
func (cfg *Configuration) UnmarshalMap(src map[string]interface{}) error {
|
||||
dec, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
TagName: "name",
|
||||
Result: cfg,
|
||||
})
|
||||
return dec.Decode(src)
|
||||
}
|
||||
|
|
@ -20,9 +20,9 @@ package config
|
|||
|
||||
import "github.com/coreos/go-oidc/v3/oidc"
|
||||
|
||||
// Defaults returns a populated Values struct with most of the values set to reasonable defaults.
|
||||
// Note that if you use this, you still need to set Host and, if desired, ConfigPath.
|
||||
var Defaults = Values{
|
||||
// Defaults contains a populated Configuration with reasonable defaults. Note that
|
||||
// if you use this, you will still need to set Host, and, if desired, ConfigPath.
|
||||
var Defaults = Configuration{
|
||||
LogLevel: "info",
|
||||
LogDbQueries: false,
|
||||
ApplicationName: "gotosocial",
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// ReadFromFile checks if there's already a path to the config file set in viper.
|
||||
// If there is, it will attempt to read the config file into viper.
|
||||
func ReadFromFile() error {
|
||||
// config file stuff
|
||||
// check if we have a config path set (either by cli arg or env var)
|
||||
if configPath := viper.GetString(Keys.ConfigPath); configPath != "" {
|
||||
viper.SetConfigFile(configPath)
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
157
internal/config/flags.go
Normal file
157
internal/config/flags.go
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// TODO: consolidate these methods into the Configuration{} or ConfigState{} structs.
|
||||
|
||||
// AddGlobalFlags will attach global configuration flags to given cobra command, loading defaults from global config.
|
||||
func AddGlobalFlags(cmd *cobra.Command) {
|
||||
Config(func(cfg *Configuration) {
|
||||
// General
|
||||
cmd.PersistentFlags().String(ApplicationNameFlag(), cfg.ApplicationName, fieldtag("ApplicationName", "usage"))
|
||||
cmd.PersistentFlags().String(HostFlag(), cfg.Host, fieldtag("Host", "usage"))
|
||||
cmd.PersistentFlags().String(AccountDomainFlag(), cfg.AccountDomain, fieldtag("AccountDomain", "usage"))
|
||||
cmd.PersistentFlags().String(ProtocolFlag(), cfg.Protocol, fieldtag("Protocol", "usage"))
|
||||
cmd.PersistentFlags().String(LogLevelFlag(), cfg.LogLevel, fieldtag("LogLevel", "usage"))
|
||||
cmd.PersistentFlags().Bool(LogDbQueriesFlag(), cfg.LogDbQueries, fieldtag("LogDbQueries", "usage"))
|
||||
cmd.PersistentFlags().String(ConfigPathFlag(), cfg.ConfigPath, fieldtag("ConfigPath", "usage"))
|
||||
|
||||
// Database
|
||||
cmd.PersistentFlags().String(DbTypeFlag(), cfg.DbType, fieldtag("DbType", "usage"))
|
||||
cmd.PersistentFlags().String(DbAddressFlag(), cfg.DbAddress, fieldtag("DbAddress", "usage"))
|
||||
cmd.PersistentFlags().Int(DbPortFlag(), cfg.DbPort, fieldtag("DbPort", "usage"))
|
||||
cmd.PersistentFlags().String(DbUserFlag(), cfg.DbUser, fieldtag("DbUser", "usage"))
|
||||
cmd.PersistentFlags().String(DbPasswordFlag(), cfg.DbPassword, fieldtag("DbPassword", "usage"))
|
||||
cmd.PersistentFlags().String(DbDatabaseFlag(), cfg.DbDatabase, fieldtag("DbDatabase", "usage"))
|
||||
cmd.PersistentFlags().String(DbTLSModeFlag(), cfg.DbTLSMode, fieldtag("DbTLSMode", "usage"))
|
||||
cmd.PersistentFlags().String(DbTLSCACertFlag(), cfg.DbTLSCACert, fieldtag("DbTLSCACert", "usage"))
|
||||
})
|
||||
}
|
||||
|
||||
// AddServerFlags will attach server configuration flags to given cobra command, loading defaults from global config.
|
||||
func AddServerFlags(cmd *cobra.Command) {
|
||||
Config(func(cfg *Configuration) {
|
||||
// Router
|
||||
cmd.PersistentFlags().String(BindAddressFlag(), cfg.BindAddress, fieldtag("BindAddress", "usage"))
|
||||
cmd.PersistentFlags().Int(PortFlag(), cfg.Port, fieldtag("Port", "usage"))
|
||||
cmd.PersistentFlags().StringSlice(TrustedProxiesFlag(), cfg.TrustedProxies, fieldtag("TrustedProxies", "usage"))
|
||||
|
||||
// Template
|
||||
cmd.Flags().String(WebTemplateBaseDirFlag(), cfg.WebTemplateBaseDir, fieldtag("WebTemplateBaseDir", "usage"))
|
||||
cmd.Flags().String(WebAssetBaseDirFlag(), cfg.WebAssetBaseDir, fieldtag("WebAssetBaseDir", "usage"))
|
||||
|
||||
// Accounts
|
||||
cmd.Flags().Bool(AccountsRegistrationOpenFlag(), cfg.AccountsRegistrationOpen, fieldtag("AccountsRegistrationOpen", "usage"))
|
||||
cmd.Flags().Bool(AccountsApprovalRequiredFlag(), cfg.AccountsApprovalRequired, fieldtag("AccountsApprovalRequired", "usage"))
|
||||
cmd.Flags().Bool(AccountsReasonRequiredFlag(), cfg.AccountsReasonRequired, fieldtag("AccountsReasonRequired", "usage"))
|
||||
|
||||
// Media
|
||||
cmd.Flags().Int(MediaImageMaxSizeFlag(), cfg.MediaImageMaxSize, fieldtag("MediaImageMaxSize", "usage"))
|
||||
cmd.Flags().Int(MediaVideoMaxSizeFlag(), cfg.MediaVideoMaxSize, fieldtag("MediaVideoMaxSize", "usage"))
|
||||
cmd.Flags().Int(MediaDescriptionMinCharsFlag(), cfg.MediaDescriptionMinChars, fieldtag("MediaDescriptionMinChars", "usage"))
|
||||
cmd.Flags().Int(MediaDescriptionMaxCharsFlag(), cfg.MediaDescriptionMaxChars, fieldtag("MediaDescriptionMaxChars", "usage"))
|
||||
cmd.Flags().Int(MediaRemoteCacheDaysFlag(), cfg.MediaRemoteCacheDays, fieldtag("MediaRemoteCacheDays", "usage"))
|
||||
|
||||
// Storage
|
||||
cmd.Flags().String(StorageBackendFlag(), cfg.StorageBackend, fieldtag("StorageBackend", "usage"))
|
||||
cmd.Flags().String(StorageLocalBasePathFlag(), cfg.StorageLocalBasePath, fieldtag("StorageLocalBasePath", "usage"))
|
||||
|
||||
// Statuses
|
||||
cmd.Flags().Int(StatusesMaxCharsFlag(), cfg.StatusesMaxChars, fieldtag("StatusesMaxChars", "usage"))
|
||||
cmd.Flags().Int(StatusesCWMaxCharsFlag(), cfg.StatusesCWMaxChars, fieldtag("StatusesCWMaxChars", "usage"))
|
||||
cmd.Flags().Int(StatusesPollMaxOptionsFlag(), cfg.StatusesPollMaxOptions, fieldtag("StatusesPollMaxOptions", "usage"))
|
||||
cmd.Flags().Int(StatusesPollOptionMaxCharsFlag(), cfg.StatusesPollOptionMaxChars, fieldtag("StatusesPollOptionMaxChars", "usage"))
|
||||
cmd.Flags().Int(StatusesMediaMaxFilesFlag(), cfg.StatusesMediaMaxFiles, fieldtag("StatusesMediaMaxFiles", "usage"))
|
||||
|
||||
// LetsEncrypt
|
||||
cmd.Flags().Bool(LetsEncryptEnabledFlag(), cfg.LetsEncryptEnabled, fieldtag("LetsEncryptEnabled", "usage"))
|
||||
cmd.Flags().Int(LetsEncryptPortFlag(), cfg.LetsEncryptPort, fieldtag("LetsEncryptPort", "usage"))
|
||||
cmd.Flags().String(LetsEncryptCertDirFlag(), cfg.LetsEncryptCertDir, fieldtag("LetsEncryptCertDir", "usage"))
|
||||
cmd.Flags().String(LetsEncryptEmailAddressFlag(), cfg.LetsEncryptEmailAddress, fieldtag("LetsEncryptEmailAddress", "usage"))
|
||||
|
||||
// OIDC
|
||||
cmd.Flags().Bool(OIDCEnabledFlag(), cfg.OIDCEnabled, fieldtag("OIDCEnabled", "usage"))
|
||||
cmd.Flags().String(OIDCIdpNameFlag(), cfg.OIDCIdpName, fieldtag("OIDCIdpName", "usage"))
|
||||
cmd.Flags().Bool(OIDCSkipVerificationFlag(), cfg.OIDCSkipVerification, fieldtag("OIDCSkipVerification", "usage"))
|
||||
cmd.Flags().String(OIDCIssuerFlag(), cfg.OIDCIssuer, fieldtag("OIDCIssuer", "usage"))
|
||||
cmd.Flags().String(OIDCClientIDFlag(), cfg.OIDCClientID, fieldtag("OIDCClientID", "usage"))
|
||||
cmd.Flags().String(OIDCClientSecretFlag(), cfg.OIDCClientSecret, fieldtag("OIDCClientSecret", "usage"))
|
||||
cmd.Flags().StringSlice(OIDCScopesFlag(), cfg.OIDCScopes, fieldtag("OIDCScopes", "usage"))
|
||||
|
||||
// SMTP
|
||||
cmd.Flags().String(SMTPHostFlag(), cfg.SMTPHost, fieldtag("SMTPHost", "usage"))
|
||||
cmd.Flags().Int(SMTPPortFlag(), cfg.SMTPPort, fieldtag("SMTPPort", "usage"))
|
||||
cmd.Flags().String(SMTPUsernameFlag(), cfg.SMTPUsername, fieldtag("SMTPUsername", "usage"))
|
||||
cmd.Flags().String(SMTPPasswordFlag(), cfg.SMTPPassword, fieldtag("SMTPPassword", "usage"))
|
||||
cmd.Flags().String(SMTPFromFlag(), cfg.SMTPFrom, fieldtag("SMTPFrom", "usage"))
|
||||
|
||||
// Syslog
|
||||
cmd.Flags().Bool(SyslogEnabledFlag(), cfg.SyslogEnabled, fieldtag("SyslogEnabled", "usage"))
|
||||
cmd.Flags().String(SyslogProtocolFlag(), cfg.SyslogProtocol, fieldtag("SyslogProtocol", "usage"))
|
||||
cmd.Flags().String(SyslogAddressFlag(), cfg.SyslogAddress, fieldtag("SyslogAddress", "usage"))
|
||||
})
|
||||
}
|
||||
|
||||
// AddAdminAccount attaches flags pertaining to admin account actions.
|
||||
func AddAdminAccount(cmd *cobra.Command) {
|
||||
name := AdminAccountUsernameFlag()
|
||||
usage := fieldtag("AdminAccountUsername", "usage")
|
||||
cmd.Flags().String(name, "", usage) // REQUIRED
|
||||
if err := cmd.MarkFlagRequired(name); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAdminAccountPassword attaches flags pertaining to admin account password reset.
|
||||
func AddAdminAccountPassword(cmd *cobra.Command) {
|
||||
name := AdminAccountPasswordFlag()
|
||||
usage := fieldtag("AdminAccountPassword", "usage")
|
||||
cmd.Flags().String(name, "", usage) // REQUIRED
|
||||
if err := cmd.MarkFlagRequired(name); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAdminAccountCreate attaches flags pertaining to admin account creation.
|
||||
func AddAdminAccountCreate(cmd *cobra.Command) {
|
||||
// Requires both account and password
|
||||
AddAdminAccount(cmd)
|
||||
AddAdminAccountPassword(cmd)
|
||||
|
||||
name := AdminAccountEmailFlag()
|
||||
usage := fieldtag("AdminAccountEmail", "usage")
|
||||
cmd.Flags().String(name, "", usage) // REQUIRED
|
||||
if err := cmd.MarkFlagRequired(name); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAdminTrans attaches flags pertaining to import/export commands.
|
||||
func AddAdminTrans(cmd *cobra.Command) {
|
||||
name := AdminTransPathFlag()
|
||||
usage := fieldtag("AdminTransPath", "usage")
|
||||
cmd.Flags().String(name, "", usage) // REQUIRED
|
||||
if err := cmd.MarkFlagRequired(name); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
112
internal/config/gen/gen.go
Normal file
112
internal/config/gen/gen.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
)
|
||||
|
||||
const license = `/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
`
|
||||
|
||||
func main() {
|
||||
var (
|
||||
out string
|
||||
gen string
|
||||
)
|
||||
|
||||
// Load runtime config flags
|
||||
flag.StringVar(&out, "out", "", "Generated file output path")
|
||||
flag.StringVar(&gen, "gen", "helpers", "Type of file to generate (helpers)")
|
||||
flag.Parse()
|
||||
|
||||
// Open output file path
|
||||
output, err := os.OpenFile(out, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch gen {
|
||||
// Generate config field helper methods
|
||||
case "helpers":
|
||||
fmt.Fprint(output, "// THIS IS A GENERATED FILE, DO NOT EDIT BY HAND\n")
|
||||
fmt.Fprint(output, license)
|
||||
fmt.Fprint(output, "package config\n\n")
|
||||
t := reflect.TypeOf(config.Configuration{})
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
|
||||
// ConfigState structure helper methods
|
||||
fmt.Fprintf(output, "// Get%s safely fetches the Configuration value for state's '%s' field\n", field.Name, field.Name)
|
||||
fmt.Fprintf(output, "func (st *ConfigState) Get%s() (v %s) {\n", field.Name, field.Type.String())
|
||||
fmt.Fprintf(output, "\tst.mutex.Lock()\n")
|
||||
fmt.Fprintf(output, "\tv = st.config.%s\n", field.Name)
|
||||
fmt.Fprintf(output, "\tst.mutex.Unlock()\n")
|
||||
fmt.Fprintf(output, "\treturn\n")
|
||||
fmt.Fprintf(output, "}\n\n")
|
||||
fmt.Fprintf(output, "// Set%s safely sets the Configuration value for state's '%s' field\n", field.Name, field.Name)
|
||||
fmt.Fprintf(output, "func (st *ConfigState) Set%s(v %s) {\n", field.Name, field.Type.String())
|
||||
fmt.Fprintf(output, "\tst.mutex.Lock()\n")
|
||||
fmt.Fprintf(output, "\tdefer st.mutex.Unlock()\n")
|
||||
fmt.Fprintf(output, "\tst.config.%s = v\n", field.Name)
|
||||
fmt.Fprintf(output, "\tst.reloadToViper()\n")
|
||||
fmt.Fprintf(output, "}\n\n")
|
||||
|
||||
// Global ConfigState helper methods
|
||||
// TODO: remove when we pass around a ConfigState{}
|
||||
fmt.Fprintf(output, "// %sFlag returns the flag name for the '%s' field\n", field.Name, field.Name)
|
||||
fmt.Fprintf(output, "func %sFlag() string { return \"%s\" }\n\n", field.Name, field.Tag.Get("name"))
|
||||
fmt.Fprintf(output, "// Get%s safely fetches the value for global configuration '%s' field\n", field.Name, field.Name)
|
||||
fmt.Fprintf(output, "func Get%[1]s() %[2]s { return global.Get%[1]s() }\n\n", field.Name, field.Type.String())
|
||||
fmt.Fprintf(output, "// Set%s safely sets the value for global configuration '%s' field\n", field.Name, field.Name)
|
||||
fmt.Fprintf(output, "func Set%[1]s(v %[2]s) { global.Set%[1]s(v) }\n\n", field.Name, field.Type.String())
|
||||
}
|
||||
_ = output.Close()
|
||||
_ = exec.Command("gofmt", "-w", out).Run()
|
||||
|
||||
// The plain here is that eventually we might be able
|
||||
// to generate an example configuration from struct tags
|
||||
|
||||
// Unknown type
|
||||
default:
|
||||
panic("unknown generation type: " + gen)
|
||||
}
|
||||
}
|
||||
53
internal/config/global.go
Normal file
53
internal/config/global.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var global *ConfigState
|
||||
|
||||
func init() {
|
||||
// init global state
|
||||
global = NewState()
|
||||
}
|
||||
|
||||
// TODO: in the future we should move away from using globals in this config
|
||||
// package, and instead pass the ConfigState round in a global gts state.
|
||||
|
||||
// Config provides you safe access to the global configuration.
|
||||
func Config(fn func(cfg *Configuration)) {
|
||||
global.Config(fn)
|
||||
}
|
||||
|
||||
// Reload will reload the current configuration values from file.
|
||||
func Reload() error {
|
||||
return global.Reload()
|
||||
}
|
||||
|
||||
// LoadEarlyFlags will bind specific flags from given Cobra command to global viper
|
||||
// instance, and load the current configuration values. This is useful for flags like
|
||||
// .ConfigPath which have to parsed first in order to perform early configuration load.
|
||||
func LoadEarlyFlags(cmd *cobra.Command) error {
|
||||
return global.LoadEarlyFlags(cmd)
|
||||
}
|
||||
|
||||
// BindFlags binds given command's pflags to the global viper instance.
|
||||
func BindFlags(cmd *cobra.Command) error {
|
||||
return global.BindFlags(cmd)
|
||||
}
|
||||
1494
internal/config/helpers.gen.go
Normal file
1494
internal/config/helpers.gen.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
// KeyNames is a struct that just contains the names of configuration keys.
|
||||
type KeyNames struct {
|
||||
// root
|
||||
LogLevel string
|
||||
LogDbQueries string
|
||||
ConfigPath string
|
||||
|
||||
// general
|
||||
ApplicationName string
|
||||
Host string
|
||||
AccountDomain string
|
||||
Protocol string
|
||||
BindAddress string
|
||||
Port string
|
||||
TrustedProxies string
|
||||
SoftwareVersion string
|
||||
|
||||
// database
|
||||
DbType string
|
||||
DbAddress string
|
||||
DbPort string
|
||||
DbUser string
|
||||
DbPassword string
|
||||
DbDatabase string
|
||||
DbTLSMode string
|
||||
DbTLSCACert string
|
||||
|
||||
// template
|
||||
WebTemplateBaseDir string
|
||||
WebAssetBaseDir string
|
||||
|
||||
// accounts
|
||||
AccountsRegistrationOpen string
|
||||
AccountsApprovalRequired string
|
||||
AccountsReasonRequired string
|
||||
|
||||
// media
|
||||
MediaImageMaxSize string
|
||||
MediaVideoMaxSize string
|
||||
MediaDescriptionMinChars string
|
||||
MediaDescriptionMaxChars string
|
||||
MediaRemoteCacheDays string
|
||||
|
||||
// storage
|
||||
StorageBackend string
|
||||
StorageLocalBasePath string
|
||||
|
||||
// statuses
|
||||
StatusesMaxChars string
|
||||
StatusesCWMaxChars string
|
||||
StatusesPollMaxOptions string
|
||||
StatusesPollOptionMaxChars string
|
||||
StatusesMediaMaxFiles string
|
||||
|
||||
// letsencrypt
|
||||
LetsEncryptEnabled string
|
||||
LetsEncryptCertDir string
|
||||
LetsEncryptEmailAddress string
|
||||
LetsEncryptPort string
|
||||
|
||||
// oidc
|
||||
OIDCEnabled string
|
||||
OIDCIdpName string
|
||||
OIDCSkipVerification string
|
||||
OIDCIssuer string
|
||||
OIDCClientID string
|
||||
OIDCClientSecret string
|
||||
OIDCScopes string
|
||||
|
||||
// smtp
|
||||
SMTPHost string
|
||||
SMTPPort string
|
||||
SMTPUsername string
|
||||
SMTPPassword string
|
||||
SMTPFrom string
|
||||
|
||||
// syslog
|
||||
SyslogEnabled string
|
||||
SyslogProtocol string
|
||||
SyslogAddress string
|
||||
|
||||
// admin
|
||||
AdminAccountUsername string
|
||||
AdminAccountEmail string
|
||||
AdminAccountPassword string
|
||||
AdminTransPath string
|
||||
}
|
||||
|
||||
// Keys contains the names of the various keys used for initializing and storing flag variables,
|
||||
// and retrieving values from the viper config store.
|
||||
var Keys = KeyNames{
|
||||
LogLevel: "log-level",
|
||||
LogDbQueries: "log-db-queries",
|
||||
ApplicationName: "application-name",
|
||||
ConfigPath: "config-path",
|
||||
Host: "host",
|
||||
AccountDomain: "account-domain",
|
||||
Protocol: "protocol",
|
||||
BindAddress: "bind-address",
|
||||
Port: "port",
|
||||
TrustedProxies: "trusted-proxies",
|
||||
SoftwareVersion: "software-version",
|
||||
|
||||
DbType: "db-type",
|
||||
DbAddress: "db-address",
|
||||
DbPort: "db-port",
|
||||
DbUser: "db-user",
|
||||
DbPassword: "db-password",
|
||||
DbDatabase: "db-database",
|
||||
DbTLSMode: "db-tls-mode",
|
||||
DbTLSCACert: "db-tls-ca-cert",
|
||||
|
||||
WebTemplateBaseDir: "web-template-base-dir",
|
||||
WebAssetBaseDir: "web-asset-base-dir",
|
||||
|
||||
AccountsRegistrationOpen: "accounts-registration-open",
|
||||
AccountsApprovalRequired: "accounts-approval-required",
|
||||
AccountsReasonRequired: "accounts-reason-required",
|
||||
|
||||
MediaImageMaxSize: "media-image-max-size",
|
||||
MediaVideoMaxSize: "media-video-max-size",
|
||||
MediaDescriptionMinChars: "media-description-min-chars",
|
||||
MediaDescriptionMaxChars: "media-description-max-chars",
|
||||
MediaRemoteCacheDays: "media-remote-cache-days",
|
||||
|
||||
StorageBackend: "storage-backend",
|
||||
StorageLocalBasePath: "storage-local-base-path",
|
||||
|
||||
StatusesMaxChars: "statuses-max-chars",
|
||||
StatusesCWMaxChars: "statuses-cw-max-chars",
|
||||
StatusesPollMaxOptions: "statuses-poll-max-options",
|
||||
StatusesPollOptionMaxChars: "statuses-poll-option-max-chars",
|
||||
StatusesMediaMaxFiles: "statuses-media-max-files",
|
||||
|
||||
LetsEncryptEnabled: "letsencrypt-enabled",
|
||||
LetsEncryptPort: "letsencrypt-port",
|
||||
LetsEncryptCertDir: "letsencrypt-cert-dir",
|
||||
LetsEncryptEmailAddress: "letsencrypt-email-address",
|
||||
|
||||
OIDCEnabled: "oidc-enabled",
|
||||
OIDCIdpName: "oidc-idp-name",
|
||||
OIDCSkipVerification: "oidc-skip-verification",
|
||||
OIDCIssuer: "oidc-issuer",
|
||||
OIDCClientID: "oidc-client-id",
|
||||
OIDCClientSecret: "oidc-client-secret",
|
||||
OIDCScopes: "oidc-scopes",
|
||||
|
||||
SMTPHost: "smtp-host",
|
||||
SMTPPort: "smtp-port",
|
||||
SMTPUsername: "smtp-username",
|
||||
SMTPPassword: "smtp-password",
|
||||
SMTPFrom: "smtp-from",
|
||||
|
||||
SyslogEnabled: "syslog-enabled",
|
||||
SyslogProtocol: "syslog-protocol",
|
||||
SyslogAddress: "syslog-address",
|
||||
|
||||
AdminAccountUsername: "username",
|
||||
AdminAccountEmail: "email",
|
||||
AdminAccountPassword: "password",
|
||||
AdminTransPath: "path",
|
||||
}
|
||||
136
internal/config/state.go
Normal file
136
internal/config/state.go
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// ConfigState manages safe concurrent access to Configuration{} values,
|
||||
// and provides ease of linking them (including reloading) via viper to
|
||||
// environment, CLI and configuration file variables.
|
||||
type ConfigState struct { //nolint
|
||||
viper *viper.Viper
|
||||
config Configuration
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewState returns a new initialized ConfigState instance.
|
||||
func NewState() *ConfigState {
|
||||
viper := viper.New()
|
||||
|
||||
// Flag 'some-flag-name' becomes env var 'GTS_SOME_FLAG_NAME'
|
||||
viper.SetEnvPrefix("gts")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
// Load appropriate named vals from env
|
||||
viper.AutomaticEnv()
|
||||
|
||||
// Create new ConfigState with defaults
|
||||
state := &ConfigState{
|
||||
viper: viper,
|
||||
config: Defaults,
|
||||
}
|
||||
|
||||
// Perform initial load into viper
|
||||
state.reloadToViper()
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
// Config provides safe access to the ConfigState's contained Configuration,
|
||||
// and will reload the current Configuration back into viper settings.
|
||||
func (st *ConfigState) Config(fn func(*Configuration)) {
|
||||
st.mutex.Lock()
|
||||
defer func() {
|
||||
st.reloadToViper()
|
||||
st.mutex.Unlock()
|
||||
}()
|
||||
fn(&st.config)
|
||||
}
|
||||
|
||||
// Viper provides safe access to the ConfigState's contained viper instance,
|
||||
// and will reload the current viper setting state back into Configuration.
|
||||
func (st *ConfigState) Viper(fn func(*viper.Viper)) {
|
||||
st.mutex.Lock()
|
||||
defer func() {
|
||||
st.reloadFromViper()
|
||||
st.mutex.Unlock()
|
||||
}()
|
||||
fn(st.viper)
|
||||
}
|
||||
|
||||
// LoadEarlyFlags will bind specific flags from given Cobra command to ConfigState's viper
|
||||
// instance, and load the current configuration values. This is useful for flags like
|
||||
// .ConfigPath which have to parsed first in order to perform early configuration load.
|
||||
func (st *ConfigState) LoadEarlyFlags(cmd *cobra.Command) (err error) {
|
||||
name := ConfigPathFlag()
|
||||
flag := cmd.Flags().Lookup(name)
|
||||
st.Viper(func(v *viper.Viper) {
|
||||
err = v.BindPFlag(name, flag)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// BindFlags will bind given Cobra command's pflags to this ConfigState's viper instance.
|
||||
func (st *ConfigState) BindFlags(cmd *cobra.Command) (err error) {
|
||||
st.Viper(func(v *viper.Viper) {
|
||||
err = v.BindPFlags(cmd.Flags())
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Reload will reload the Configuration values from ConfigState's viper instance, and from file if set.
|
||||
func (st *ConfigState) Reload() (err error) {
|
||||
st.Viper(func(v *viper.Viper) {
|
||||
if st.config.ConfigPath != "" {
|
||||
// Ensure configuration path is set
|
||||
v.SetConfigFile(st.config.ConfigPath)
|
||||
|
||||
// Read in configuration from file
|
||||
if err = v.ReadInConfig(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// reloadToViper will reload Configuration{} values into viper.
|
||||
func (st *ConfigState) reloadToViper() {
|
||||
raw, err := st.config.MarshalMap()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := st.viper.MergeConfigMap(raw); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// reloadFromViper will reload Configuration{} values from viper.
|
||||
func (st *ConfigState) reloadFromViper() {
|
||||
err := st.config.UnmarshalMap(st.viper.AllSettings())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Validate validates global config settings which don't have defaults, to make sure they are set sensibly.
|
||||
|
|
@ -32,22 +31,21 @@ func Validate() error {
|
|||
errs := []error{}
|
||||
|
||||
// host
|
||||
if viper.GetString(Keys.Host) == "" {
|
||||
errs = append(errs, fmt.Errorf("%s must be set", Keys.Host))
|
||||
if GetHost() == "" {
|
||||
errs = append(errs, fmt.Errorf("%s must be set", HostFlag()))
|
||||
}
|
||||
|
||||
// protocol
|
||||
protocol := viper.GetString(Keys.Protocol)
|
||||
switch protocol {
|
||||
switch proto := GetProtocol(); proto {
|
||||
case "https":
|
||||
// no problem
|
||||
break
|
||||
case "http":
|
||||
logrus.Warnf("%s was set to 'http'; this should *only* be used for debugging and tests!", Keys.Protocol)
|
||||
logrus.Warnf("%s was set to 'http'; this should *only* be used for debugging and tests!", ProtocolFlag())
|
||||
case "":
|
||||
errs = append(errs, fmt.Errorf("%s must be set", Keys.Protocol))
|
||||
errs = append(errs, fmt.Errorf("%s must be set", ProtocolFlag()))
|
||||
default:
|
||||
errs = append(errs, fmt.Errorf("%s must be set to either http or https, provided value was %s", Keys.Protocol, protocol))
|
||||
errs = append(errs, fmt.Errorf("%s must be set to either http or https, provided value was %s", ProtocolFlag(), proto))
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ package config_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
|
|
@ -41,7 +40,7 @@ func (suite *ConfigValidateTestSuite) TestValidateConfigOK() {
|
|||
func (suite *ConfigValidateTestSuite) TestValidateConfigNoHost() {
|
||||
testrig.InitTestConfig()
|
||||
|
||||
viper.Set(config.Keys.Host, "")
|
||||
config.SetHost("")
|
||||
|
||||
err := config.Validate()
|
||||
suite.EqualError(err, "host must be set")
|
||||
|
|
@ -50,7 +49,7 @@ func (suite *ConfigValidateTestSuite) TestValidateConfigNoHost() {
|
|||
func (suite *ConfigValidateTestSuite) TestValidateConfigNoProtocol() {
|
||||
testrig.InitTestConfig()
|
||||
|
||||
viper.Set(config.Keys.Protocol, "")
|
||||
config.SetProtocol("")
|
||||
|
||||
err := config.Validate()
|
||||
suite.EqualError(err, "protocol must be set")
|
||||
|
|
@ -59,8 +58,8 @@ func (suite *ConfigValidateTestSuite) TestValidateConfigNoProtocol() {
|
|||
func (suite *ConfigValidateTestSuite) TestValidateConfigNoProtocolOrHost() {
|
||||
testrig.InitTestConfig()
|
||||
|
||||
viper.Set(config.Keys.Host, "")
|
||||
viper.Set(config.Keys.Protocol, "")
|
||||
config.SetHost("")
|
||||
config.SetProtocol("")
|
||||
|
||||
err := config.Validate()
|
||||
suite.EqualError(err, "host must be set; protocol must be set")
|
||||
|
|
@ -69,7 +68,7 @@ func (suite *ConfigValidateTestSuite) TestValidateConfigNoProtocolOrHost() {
|
|||
func (suite *ConfigValidateTestSuite) TestValidateConfigBadProtocol() {
|
||||
testrig.InitTestConfig()
|
||||
|
||||
viper.Set(config.Keys.Protocol, "foo")
|
||||
config.SetProtocol("foo")
|
||||
|
||||
err := config.Validate()
|
||||
suite.EqualError(err, "protocol must be set to either http or https, provided value was foo")
|
||||
|
|
@ -78,8 +77,8 @@ func (suite *ConfigValidateTestSuite) TestValidateConfigBadProtocol() {
|
|||
func (suite *ConfigValidateTestSuite) TestValidateConfigBadProtocolNoHost() {
|
||||
testrig.InitTestConfig()
|
||||
|
||||
viper.Set(config.Keys.Host, "")
|
||||
viper.Set(config.Keys.Protocol, "foo")
|
||||
config.SetHost("")
|
||||
config.SetProtocol("foo")
|
||||
|
||||
err := config.Validate()
|
||||
suite.EqualError(err, "host must be set; protocol must be set to either http or https, provided value was foo")
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
// Values contains contains the type of each configuration value.
|
||||
type Values struct {
|
||||
LogLevel string
|
||||
LogDbQueries bool
|
||||
ApplicationName string
|
||||
ConfigPath string
|
||||
Host string
|
||||
AccountDomain string
|
||||
Protocol string
|
||||
BindAddress string
|
||||
Port int
|
||||
TrustedProxies []string
|
||||
SoftwareVersion string
|
||||
|
||||
DbType string
|
||||
DbAddress string
|
||||
DbPort int
|
||||
DbUser string
|
||||
DbPassword string
|
||||
DbDatabase string
|
||||
DbTLSMode string
|
||||
DbTLSCACert string
|
||||
|
||||
WebTemplateBaseDir string
|
||||
WebAssetBaseDir string
|
||||
|
||||
AccountsRegistrationOpen bool
|
||||
AccountsApprovalRequired bool
|
||||
AccountsReasonRequired bool
|
||||
|
||||
MediaImageMaxSize int
|
||||
MediaVideoMaxSize int
|
||||
MediaDescriptionMinChars int
|
||||
MediaDescriptionMaxChars int
|
||||
MediaRemoteCacheDays int
|
||||
|
||||
StorageBackend string
|
||||
StorageLocalBasePath string
|
||||
|
||||
StatusesMaxChars int
|
||||
StatusesCWMaxChars int
|
||||
StatusesPollMaxOptions int
|
||||
StatusesPollOptionMaxChars int
|
||||
StatusesMediaMaxFiles int
|
||||
|
||||
LetsEncryptEnabled bool
|
||||
LetsEncryptCertDir string
|
||||
LetsEncryptEmailAddress string
|
||||
LetsEncryptPort int
|
||||
|
||||
OIDCEnabled bool
|
||||
OIDCIdpName string
|
||||
OIDCSkipVerification bool
|
||||
OIDCIssuer string
|
||||
OIDCClientID string
|
||||
OIDCClientSecret string
|
||||
OIDCScopes []string
|
||||
|
||||
SMTPHost string
|
||||
SMTPPort int
|
||||
SMTPUsername string
|
||||
SMTPPassword string
|
||||
SMTPFrom string
|
||||
|
||||
SyslogEnabled bool
|
||||
SyslogProtocol string
|
||||
SyslogAddress string
|
||||
|
||||
AdminAccountUsername string
|
||||
AdminAccountEmail string
|
||||
AdminAccountPassword string
|
||||
AdminTransPath string
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func InitViper(f *pflag.FlagSet) error {
|
||||
// environment variable stuff
|
||||
// flag 'some-flag-name' becomes env var 'GTS_SOME_FLAG_NAME'
|
||||
viper.SetEnvPrefix("gts")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
// flag stuff
|
||||
// bind all of the flags in flagset to viper so that we can retrieve their values from the viper store
|
||||
if err := viper.BindPFlags(f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue