diff --git a/cmd/gotosocial/action/admin/account/account.go b/cmd/gotosocial/action/admin/account/account.go
index cdbe70c15..05f5a776b 100644
--- a/cmd/gotosocial/action/admin/account/account.go
+++ b/cmd/gotosocial/action/admin/account/account.go
@@ -24,7 +24,6 @@ import (
"fmt"
"time"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -41,7 +40,7 @@ var Create action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error creating dbservice: %s", err)
}
- username := viper.GetString(config.Keys.AdminAccountUsername)
+ username := config.GetAdminAccountUsername()
if username == "" {
return errors.New("no username set")
}
@@ -49,7 +48,7 @@ var Create action.GTSAction = func(ctx context.Context) error {
return err
}
- email := viper.GetString(config.Keys.AdminAccountEmail)
+ email := config.GetAdminAccountEmail()
if email == "" {
return errors.New("no email set")
}
@@ -57,7 +56,7 @@ var Create action.GTSAction = func(ctx context.Context) error {
return err
}
- password := viper.GetString(config.Keys.AdminAccountPassword)
+ password := config.GetAdminAccountPassword()
if password == "" {
return errors.New("no password set")
}
@@ -80,7 +79,7 @@ var Confirm action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error creating dbservice: %s", err)
}
- username := viper.GetString(config.Keys.AdminAccountUsername)
+ username := config.GetAdminAccountUsername()
if username == "" {
return errors.New("no username set")
}
@@ -115,7 +114,7 @@ var Promote action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error creating dbservice: %s", err)
}
- username := viper.GetString(config.Keys.AdminAccountUsername)
+ username := config.GetAdminAccountUsername()
if username == "" {
return errors.New("no username set")
}
@@ -147,7 +146,7 @@ var Demote action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error creating dbservice: %s", err)
}
- username := viper.GetString(config.Keys.AdminAccountUsername)
+ username := config.GetAdminAccountUsername()
if username == "" {
return errors.New("no username set")
}
@@ -179,7 +178,7 @@ var Disable action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error creating dbservice: %s", err)
}
- username := viper.GetString(config.Keys.AdminAccountUsername)
+ username := config.GetAdminAccountUsername()
if username == "" {
return errors.New("no username set")
}
@@ -217,7 +216,7 @@ var Password action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error creating dbservice: %s", err)
}
- username := viper.GetString(config.Keys.AdminAccountUsername)
+ username := config.GetAdminAccountUsername()
if username == "" {
return errors.New("no username set")
}
@@ -225,7 +224,7 @@ var Password action.GTSAction = func(ctx context.Context) error {
return err
}
- password := viper.GetString(config.Keys.AdminAccountPassword)
+ password := config.GetAdminAccountPassword()
if password == "" {
return errors.New("no password set")
}
diff --git a/cmd/gotosocial/action/admin/trans/export.go b/cmd/gotosocial/action/admin/trans/export.go
index a6eb3f73b..2b5f82ee8 100644
--- a/cmd/gotosocial/action/admin/trans/export.go
+++ b/cmd/gotosocial/action/admin/trans/export.go
@@ -23,7 +23,6 @@ import (
"errors"
"fmt"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
@@ -39,7 +38,7 @@ var Export action.GTSAction = func(ctx context.Context) error {
exporter := trans.NewExporter(dbConn)
- path := viper.GetString(config.Keys.AdminTransPath)
+ path := config.GetAdminTransPath()
if path == "" {
return errors.New("no path set")
}
diff --git a/cmd/gotosocial/action/admin/trans/import.go b/cmd/gotosocial/action/admin/trans/import.go
index df7d32b69..75f2d6a5e 100644
--- a/cmd/gotosocial/action/admin/trans/import.go
+++ b/cmd/gotosocial/action/admin/trans/import.go
@@ -23,7 +23,6 @@ import (
"errors"
"fmt"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
@@ -39,7 +38,7 @@ var Import action.GTSAction = func(ctx context.Context) error {
importer := trans.NewImporter(dbConn)
- path := viper.GetString(config.Keys.AdminTransPath)
+ path := config.GetAdminTransPath()
if path == "" {
return errors.New("no path set")
}
diff --git a/cmd/gotosocial/action/debug/config/config.go b/cmd/gotosocial/action/debug/config/config.go
index 92f18bdfd..010907eab 100644
--- a/cmd/gotosocial/action/debug/config/config.go
+++ b/cmd/gotosocial/action/debug/config/config.go
@@ -23,17 +23,29 @@ import (
"encoding/json"
"fmt"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
)
// Config just prints the collated config out to stdout as json.
-var Config action.GTSAction = func(ctx context.Context) error {
- allSettings := viper.AllSettings()
- b, err := json.Marshal(&allSettings)
+var Config action.GTSAction = func(ctx context.Context) (err error) {
+ var raw map[string]interface{}
+
+ // Marshal configuration to a raw JSON map
+ config.Config(func(cfg *config.Configuration) {
+ raw, err = cfg.MarshalMap()
+ })
if err != nil {
return err
}
- fmt.Println(string(b))
+
+ // Marshal map to JSON
+ b, err := json.Marshal(raw)
+ if err != nil {
+ return err
+ }
+
+ // Print to stdout
+ fmt.Printf("%s\n", b)
return nil
}
diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go
index 709b3d481..f266331f2 100644
--- a/cmd/gotosocial/action/server/server.go
+++ b/cmd/gotosocial/action/server/server.go
@@ -29,7 +29,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"codeberg.org/gruf/go-store/storage"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
@@ -107,7 +106,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
typeConverter := typeutils.NewConverter(dbService)
// Open the storage backend
- storageBasePath := viper.GetString(config.Keys.StorageLocalBasePath)
+ storageBasePath := config.GetStorageLocalBasePath()
storage, err := kv.OpenFile(storageBasePath, &storage.DiskConfig{
// Put the store lockfile in the storage dir itself.
// Normally this would not be safe, since we could end up
@@ -134,8 +133,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
// decide whether to create a noop email sender (won't send emails) or a real one
var emailSender email.Sender
- smtpHost := viper.GetString(config.Keys.SMTPHost)
- if smtpHost != "" {
+ if smtpHost := config.GetSMTPHost(); smtpHost != "" {
// host is defined so create a proper sender
emailSender, err = email.NewSender()
if err != nil {
@@ -239,7 +237,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
}
// perform initial media prune in case value of MediaRemoteCacheDays changed
- if err := processor.AdminMediaPrune(ctx, viper.GetInt(config.Keys.MediaRemoteCacheDays)); err != nil {
+ if err := processor.AdminMediaPrune(ctx, config.GetMediaRemoteCacheDays()); err != nil {
return fmt.Errorf("error during initial media prune: %s", err)
}
diff --git a/cmd/gotosocial/admin.go b/cmd/gotosocial/admin.go
index 2e4336d7a..cddc79f40 100644
--- a/cmd/gotosocial/admin.go
+++ b/cmd/gotosocial/admin.go
@@ -22,7 +22,6 @@ import (
"github.com/spf13/cobra"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action/admin/account"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action/admin/trans"
- "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/flag"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -40,7 +39,7 @@ func adminCommands() *cobra.Command {
Use: "account",
Short: "admin commands related to accounts",
}
- flag.AdminAccount(adminAccountCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountCmd)
adminAccountCreateCmd := &cobra.Command{
Use: "create",
@@ -52,7 +51,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Create)
},
}
- flag.AdminAccountCreate(adminAccountCreateCmd, config.Defaults)
+ config.AddAdminAccountCreate(adminAccountCreateCmd)
adminAccountCmd.AddCommand(adminAccountCreateCmd)
adminAccountConfirmCmd := &cobra.Command{
@@ -65,7 +64,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Confirm)
},
}
- flag.AdminAccount(adminAccountConfirmCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountConfirmCmd)
adminAccountCmd.AddCommand(adminAccountConfirmCmd)
adminAccountPromoteCmd := &cobra.Command{
@@ -78,7 +77,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Promote)
},
}
- flag.AdminAccount(adminAccountPromoteCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountPromoteCmd)
adminAccountCmd.AddCommand(adminAccountPromoteCmd)
adminAccountDemoteCmd := &cobra.Command{
@@ -91,7 +90,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Demote)
},
}
- flag.AdminAccount(adminAccountDemoteCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountDemoteCmd)
adminAccountCmd.AddCommand(adminAccountDemoteCmd)
adminAccountDisableCmd := &cobra.Command{
@@ -104,7 +103,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Disable)
},
}
- flag.AdminAccount(adminAccountDisableCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountDisableCmd)
adminAccountCmd.AddCommand(adminAccountDisableCmd)
adminAccountSuspendCmd := &cobra.Command{
@@ -117,7 +116,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Suspend)
},
}
- flag.AdminAccount(adminAccountSuspendCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountSuspendCmd)
adminAccountCmd.AddCommand(adminAccountSuspendCmd)
adminAccountPasswordCmd := &cobra.Command{
@@ -130,7 +129,8 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), account.Password)
},
}
- flag.AdminAccountPassword(adminAccountPasswordCmd, config.Defaults)
+ config.AddAdminAccount(adminAccountPasswordCmd)
+ config.AddAdminAccountPassword(adminAccountPasswordCmd)
adminAccountCmd.AddCommand(adminAccountPasswordCmd)
adminCmd.AddCommand(adminAccountCmd)
@@ -149,7 +149,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), trans.Export)
},
}
- flag.AdminTrans(adminExportCmd, config.Defaults)
+ config.AddAdminTrans(adminExportCmd)
adminCmd.AddCommand(adminExportCmd)
adminImportCmd := &cobra.Command{
@@ -162,7 +162,7 @@ func adminCommands() *cobra.Command {
return run(cmd.Context(), trans.Import)
},
}
- flag.AdminTrans(adminImportCmd, config.Defaults)
+ config.AddAdminTrans(adminImportCmd)
adminCmd.AddCommand(adminImportCmd)
return adminCmd
diff --git a/cmd/gotosocial/common.go b/cmd/gotosocial/common.go
index 48d56a7a2..43e2f16ad 100644
--- a/cmd/gotosocial/common.go
+++ b/cmd/gotosocial/common.go
@@ -43,12 +43,12 @@ type preRunArgs struct {
// of the config file from the viper store so that it can be picked up by either
// env vars or cli flag.
func preRun(a preRunArgs) error {
- if err := config.InitViper(a.cmd.Flags()); err != nil {
- return fmt.Errorf("error initializing viper: %s", err)
+ if err := config.BindFlags(a.cmd); err != nil {
+ return fmt.Errorf("error binding flags: %s", err)
}
- if err := config.ReadFromFile(); err != nil {
- return fmt.Errorf("error initializing config: %s", err)
+ if err := config.Reload(); err != nil {
+ return fmt.Errorf("error reloading config: %s", err)
}
if !a.skipValidation {
diff --git a/cmd/gotosocial/debug.go b/cmd/gotosocial/debug.go
index b1a1560ec..b32a73920 100644
--- a/cmd/gotosocial/debug.go
+++ b/cmd/gotosocial/debug.go
@@ -21,7 +21,6 @@ package main
import (
"github.com/spf13/cobra"
configaction "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action/debug/config"
- "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/flag"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -41,8 +40,7 @@ func debugCommands() *cobra.Command {
return run(cmd.Context(), configaction.Config)
},
}
- flag.Server(debugConfigCmd, config.Defaults)
-
+ config.AddServerFlags(debugConfigCmd)
debugCmd.AddCommand(debugConfigCmd)
return debugCmd
}
diff --git a/cmd/gotosocial/flag/admin.go b/cmd/gotosocial/flag/admin.go
deleted file mode 100644
index e3829954f..000000000
--- a/cmd/gotosocial/flag/admin.go
+++ /dev/null
@@ -1,62 +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 .
-*/
-
-package flag
-
-import (
- "github.com/spf13/cobra"
- "github.com/superseriousbusiness/gotosocial/internal/config"
-)
-
-// AdminAccount attaches flags pertaining to admin account actions.
-func AdminAccount(cmd *cobra.Command, values config.Values) {
- cmd.Flags().String(config.Keys.AdminAccountUsername, "", usage.AdminAccountUsername) // REQUIRED
- if err := cmd.MarkFlagRequired(config.Keys.AdminAccountUsername); err != nil {
- panic(err)
- }
-}
-
-// AdminAccountPassword attaches flags pertaining to admin account password reset.
-func AdminAccountPassword(cmd *cobra.Command, values config.Values) {
- AdminAccount(cmd, values)
- cmd.Flags().String(config.Keys.AdminAccountPassword, "", usage.AdminAccountPassword) // REQUIRED
- if err := cmd.MarkFlagRequired(config.Keys.AdminAccountPassword); err != nil {
- panic(err)
- }
-}
-
-// AdminAccountCreate attaches flags pertaining to admin account creation.
-func AdminAccountCreate(cmd *cobra.Command, values config.Values) {
- AdminAccount(cmd, values)
- cmd.Flags().String(config.Keys.AdminAccountPassword, "", usage.AdminAccountPassword) // REQUIRED
- if err := cmd.MarkFlagRequired(config.Keys.AdminAccountPassword); err != nil {
- panic(err)
- }
- cmd.Flags().String(config.Keys.AdminAccountEmail, "", usage.AdminAccountEmail) // REQUIRED
- if err := cmd.MarkFlagRequired(config.Keys.AdminAccountEmail); err != nil {
- panic(err)
- }
-}
-
-// AdminTrans attaches flags pertaining to import/export commands.
-func AdminTrans(cmd *cobra.Command, values config.Values) {
- cmd.Flags().String(config.Keys.AdminTransPath, "", usage.AdminTransPath) // REQUIRED
- if err := cmd.MarkFlagRequired(config.Keys.AdminTransPath); err != nil {
- panic(err)
- }
-}
diff --git a/cmd/gotosocial/flag/global.go b/cmd/gotosocial/flag/global.go
deleted file mode 100644
index 173180024..000000000
--- a/cmd/gotosocial/flag/global.go
+++ /dev/null
@@ -1,46 +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 .
-*/
-
-package flag
-
-import (
- "github.com/spf13/cobra"
- "github.com/superseriousbusiness/gotosocial/internal/config"
-)
-
-// Global attaches flags that are common to all commands, aka persistent commands.
-func Global(cmd *cobra.Command, values config.Values) {
- // general stuff
- cmd.PersistentFlags().String(config.Keys.ApplicationName, values.ApplicationName, usage.ApplicationName)
- cmd.PersistentFlags().String(config.Keys.Host, values.Host, usage.Host)
- cmd.PersistentFlags().String(config.Keys.AccountDomain, values.AccountDomain, usage.AccountDomain)
- cmd.PersistentFlags().String(config.Keys.Protocol, values.Protocol, usage.Protocol)
- cmd.PersistentFlags().String(config.Keys.LogLevel, values.LogLevel, usage.LogLevel)
- cmd.PersistentFlags().Bool(config.Keys.LogDbQueries, values.LogDbQueries, usage.LogDbQueries)
- cmd.PersistentFlags().String(config.Keys.ConfigPath, values.ConfigPath, usage.ConfigPath)
-
- // database stuff
- cmd.PersistentFlags().String(config.Keys.DbType, values.DbType, usage.DbType)
- cmd.PersistentFlags().String(config.Keys.DbAddress, values.DbAddress, usage.DbAddress)
- cmd.PersistentFlags().Int(config.Keys.DbPort, values.DbPort, usage.DbPort)
- cmd.PersistentFlags().String(config.Keys.DbUser, values.DbUser, usage.DbUser)
- cmd.PersistentFlags().String(config.Keys.DbPassword, values.DbPassword, usage.DbPassword)
- cmd.PersistentFlags().String(config.Keys.DbDatabase, values.DbDatabase, usage.DbDatabase)
- cmd.PersistentFlags().String(config.Keys.DbTLSMode, values.DbTLSMode, usage.DbTLSMode)
- cmd.PersistentFlags().String(config.Keys.DbTLSCACert, values.DbTLSCACert, usage.DbTLSCACert)
-}
diff --git a/cmd/gotosocial/flag/server.go b/cmd/gotosocial/flag/server.go
deleted file mode 100644
index 418e48af6..000000000
--- a/cmd/gotosocial/flag/server.go
+++ /dev/null
@@ -1,117 +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 .
-*/
-
-package flag
-
-import (
- "github.com/spf13/cobra"
- "github.com/superseriousbusiness/gotosocial/internal/config"
-)
-
-// Server attaches all flags pertaining to running the GtS server or testrig.
-func Server(cmd *cobra.Command, values config.Values) {
- Template(cmd, values)
- Accounts(cmd, values)
- Media(cmd, values)
- Storage(cmd, values)
- Statuses(cmd, values)
- LetsEncrypt(cmd, values)
- OIDC(cmd, values)
- SMTP(cmd, values)
- Router(cmd, values)
- Syslog(cmd, values)
-}
-
-// Router attaches flags pertaining to the gin router.
-func Router(cmd *cobra.Command, values config.Values) {
- cmd.PersistentFlags().String(config.Keys.BindAddress, values.BindAddress, usage.BindAddress)
- cmd.PersistentFlags().Int(config.Keys.Port, values.Port, usage.Port)
- cmd.PersistentFlags().StringSlice(config.Keys.TrustedProxies, values.TrustedProxies, usage.TrustedProxies)
-}
-
-// Template attaches flags pertaining to templating config.
-func Template(cmd *cobra.Command, values config.Values) {
- cmd.Flags().String(config.Keys.WebTemplateBaseDir, values.WebTemplateBaseDir, usage.WebTemplateBaseDir)
- cmd.Flags().String(config.Keys.WebAssetBaseDir, values.WebAssetBaseDir, usage.WebAssetBaseDir)
-}
-
-// Accounts attaches flags pertaining to account config.
-func Accounts(cmd *cobra.Command, values config.Values) {
- cmd.Flags().Bool(config.Keys.AccountsRegistrationOpen, values.AccountsRegistrationOpen, usage.AccountsRegistrationOpen)
- cmd.Flags().Bool(config.Keys.AccountsApprovalRequired, values.AccountsApprovalRequired, usage.AccountsApprovalRequired)
- cmd.Flags().Bool(config.Keys.AccountsReasonRequired, values.AccountsReasonRequired, usage.AccountsReasonRequired)
-}
-
-// Media attaches flags pertaining to media config.
-func Media(cmd *cobra.Command, values config.Values) {
- cmd.Flags().Int(config.Keys.MediaImageMaxSize, values.MediaImageMaxSize, usage.MediaImageMaxSize)
- cmd.Flags().Int(config.Keys.MediaVideoMaxSize, values.MediaVideoMaxSize, usage.MediaVideoMaxSize)
- cmd.Flags().Int(config.Keys.MediaDescriptionMinChars, values.MediaDescriptionMinChars, usage.MediaDescriptionMinChars)
- cmd.Flags().Int(config.Keys.MediaDescriptionMaxChars, values.MediaDescriptionMaxChars, usage.MediaDescriptionMaxChars)
- cmd.Flags().Int(config.Keys.MediaRemoteCacheDays, values.MediaRemoteCacheDays, usage.MediaRemoteCacheDays)
-}
-
-// Storage attaches flags pertaining to storage config.
-func Storage(cmd *cobra.Command, values config.Values) {
- cmd.Flags().String(config.Keys.StorageBackend, values.StorageBackend, usage.StorageBackend)
- cmd.Flags().String(config.Keys.StorageLocalBasePath, values.StorageLocalBasePath, usage.StorageLocalBasePath)
-}
-
-// Statuses attaches flags pertaining to statuses config.
-func Statuses(cmd *cobra.Command, values config.Values) {
- cmd.Flags().Int(config.Keys.StatusesMaxChars, values.StatusesMaxChars, usage.StatusesMaxChars)
- cmd.Flags().Int(config.Keys.StatusesCWMaxChars, values.StatusesCWMaxChars, usage.StatusesCWMaxChars)
- cmd.Flags().Int(config.Keys.StatusesPollMaxOptions, values.StatusesPollMaxOptions, usage.StatusesPollMaxOptions)
- cmd.Flags().Int(config.Keys.StatusesPollOptionMaxChars, values.StatusesPollOptionMaxChars, usage.StatusesPollOptionMaxChars)
- cmd.Flags().Int(config.Keys.StatusesMediaMaxFiles, values.StatusesMediaMaxFiles, usage.StatusesMediaMaxFiles)
-}
-
-// LetsEncrypt attaches flags pertaining to letsencrypt config.
-func LetsEncrypt(cmd *cobra.Command, values config.Values) {
- cmd.Flags().Bool(config.Keys.LetsEncryptEnabled, values.LetsEncryptEnabled, usage.LetsEncryptEnabled)
- cmd.Flags().Int(config.Keys.LetsEncryptPort, values.LetsEncryptPort, usage.LetsEncryptPort)
- cmd.Flags().String(config.Keys.LetsEncryptCertDir, values.LetsEncryptCertDir, usage.LetsEncryptCertDir)
- cmd.Flags().String(config.Keys.LetsEncryptEmailAddress, values.LetsEncryptEmailAddress, usage.LetsEncryptEmailAddress)
-}
-
-// OIDC attaches flags pertaining to oidc config.
-func OIDC(cmd *cobra.Command, values config.Values) {
- cmd.Flags().Bool(config.Keys.OIDCEnabled, values.OIDCEnabled, usage.OIDCEnabled)
- cmd.Flags().String(config.Keys.OIDCIdpName, values.OIDCIdpName, usage.OIDCIdpName)
- cmd.Flags().Bool(config.Keys.OIDCSkipVerification, values.OIDCSkipVerification, usage.OIDCSkipVerification)
- cmd.Flags().String(config.Keys.OIDCIssuer, values.OIDCIssuer, usage.OIDCIssuer)
- cmd.Flags().String(config.Keys.OIDCClientID, values.OIDCClientID, usage.OIDCClientID)
- cmd.Flags().String(config.Keys.OIDCClientSecret, values.OIDCClientSecret, usage.OIDCClientSecret)
- cmd.Flags().StringSlice(config.Keys.OIDCScopes, values.OIDCScopes, usage.OIDCScopes)
-}
-
-// SMTP attaches flags pertaining to smtp/email config.
-func SMTP(cmd *cobra.Command, values config.Values) {
- cmd.Flags().String(config.Keys.SMTPHost, values.SMTPHost, usage.SMTPHost)
- cmd.Flags().Int(config.Keys.SMTPPort, values.SMTPPort, usage.SMTPPort)
- cmd.Flags().String(config.Keys.SMTPUsername, values.SMTPUsername, usage.SMTPUsername)
- cmd.Flags().String(config.Keys.SMTPPassword, values.SMTPPassword, usage.SMTPPassword)
- cmd.Flags().String(config.Keys.SMTPFrom, values.SMTPFrom, usage.SMTPFrom)
-}
-
-// Syslog attaches flags pertaining to syslog config.
-func Syslog(cmd *cobra.Command, values config.Values) {
- cmd.Flags().Bool(config.Keys.SyslogEnabled, values.SyslogEnabled, usage.SyslogEnabled)
- cmd.Flags().String(config.Keys.SyslogProtocol, values.SyslogProtocol, usage.SyslogProtocol)
- cmd.Flags().String(config.Keys.SyslogAddress, values.SyslogAddress, usage.SyslogAddress)
-}
diff --git a/cmd/gotosocial/flag/usage.go b/cmd/gotosocial/flag/usage.go
deleted file mode 100644
index 3393f4675..000000000
--- a/cmd/gotosocial/flag/usage.go
+++ /dev/null
@@ -1,82 +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 .
-*/
-
-package flag
-
-import "github.com/superseriousbusiness/gotosocial/internal/config"
-
-var usage = config.KeyNames{
- LogLevel: "Log level to run at: [trace, debug, info, warn, fatal]",
- LogDbQueries: "Log database queries verbosely when log-level is trace or debug",
- ApplicationName: "Name of the application, used in various places internally",
- ConfigPath: "Path to a file containing gotosocial configuration. Values set in this file will be overwritten by values set as env vars or arguments",
- Host: "Hostname to use for the server (eg., example.org, gotosocial.whatever.com). This value must be set. DO NOT change this on a server that's already run!",
- AccountDomain: "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: "Protocol to use for the REST api of the server. This value must be set to one of http or https; only use http for debugging and tests!",
- BindAddress: "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: "Port to use for GoToSocial. Change this to 443 if you're running the binary directly on the host machine.",
- TrustedProxies: "Proxies to trust when parsing x-forwarded headers into real IPs.",
- DbType: "Database type: eg., postgres",
- DbAddress: "Database ipv4 address, hostname, or filename",
- DbPort: "Database port",
- DbUser: "Database username",
- DbPassword: "Database password",
- DbDatabase: "Database name",
- DbTLSMode: "Database tls mode",
- DbTLSCACert: "Path to CA cert for db tls connection",
- WebTemplateBaseDir: "Basedir for html templating files for rendering pages and composing emails.",
- WebAssetBaseDir: "Directory to serve static assets from, accessible at example.org/assets/",
- AccountsRegistrationOpen: "Allow anyone to submit an account signup request. If false, server will be invite-only.",
- AccountsApprovalRequired: "Do account signups require approval by an admin or moderator before user can log in? If false, new registrations will be automatically approved.",
- AccountsReasonRequired: "Do new account signups require a reason to be submitted on registration?",
- MediaImageMaxSize: "Max size of accepted images in bytes",
- MediaVideoMaxSize: "Max size of accepted videos in bytes",
- MediaDescriptionMinChars: "Min required chars for an image description",
- MediaDescriptionMaxChars: "Max permitted chars for an image description",
- MediaRemoteCacheDays: "Number of days to locally cache media from remote instances. If set to 0, remote media will be kept indefinitely.",
- StorageBackend: "Storage backend to use for media attachments",
- StorageLocalBasePath: "Full path to an already-created directory where gts should store/retrieve media files. Subfolders will be created within this dir.",
- StatusesMaxChars: "Max permitted characters for posted statuses",
- StatusesCWMaxChars: "Max permitted characters for content/spoiler warnings on statuses",
- StatusesPollMaxOptions: "Max amount of options permitted on a poll",
- StatusesPollOptionMaxChars: "Max amount of characters for a poll option",
- StatusesMediaMaxFiles: "Maximum number of media files/attachments per status",
- LetsEncryptEnabled: "Enable letsencrypt TLS certs for this server. If set to true, then cert dir also needs to be set (or take the default).",
- LetsEncryptPort: "Port to listen on for letsencrypt certificate challenges. Must not be the same as the GtS webserver/API port.",
- LetsEncryptCertDir: "Directory to store acquired letsencrypt certificates.",
- LetsEncryptEmailAddress: "Email address to use when requesting letsencrypt certs. Will receive updates on cert expiry etc.",
- OIDCEnabled: "Enabled OIDC authorization for this instance. If set to true, then the other OIDC flags must also be set.",
- OIDCIdpName: "Name of the OIDC identity provider. Will be shown to the user when logging in.",
- OIDCSkipVerification: "Skip verification of tokens returned by the OIDC provider. Should only be set to 'true' for testing purposes, never in a production environment!",
- OIDCIssuer: "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: "ClientID of GoToSocial, as registered with the OIDC provider.",
- OIDCClientSecret: "ClientSecret of GoToSocial, as registered with the OIDC provider.",
- OIDCScopes: "OIDC scopes.",
- SMTPHost: "Host of the smtp server. Eg., 'smtp.eu.mailgun.org'",
- SMTPPort: "Port of the smtp server. Eg., 587",
- SMTPUsername: "Username to authenticate with the smtp server as. Eg., 'postmaster@mail.example.org'",
- SMTPPassword: "Password to pass to the smtp server.",
- SMTPFrom: "Address to use as the 'from' field of the email. Eg., 'gotosocial@example.org'",
- SyslogEnabled: "Enable the syslog logging hook. Logs will be mirrored to the configured destination.",
- SyslogProtocol: "Protocol to use when directing logs to syslog. Leave empty to connect to local syslog.",
- SyslogAddress: "Address:port to send syslog logs to. Leave empty to connect to local syslog.",
- AdminAccountUsername: "the username to create/delete/etc",
- AdminAccountEmail: "the email address of this account",
- AdminAccountPassword: "the password to set for this account",
- AdminTransPath: "the path of the file to import from/export to",
-}
diff --git a/cmd/gotosocial/main.go b/cmd/gotosocial/main.go
index 49560503f..1b815f6b7 100644
--- a/cmd/gotosocial/main.go
+++ b/cmd/gotosocial/main.go
@@ -19,14 +19,12 @@
package main
import (
- "fmt"
"runtime/debug"
+ "strings"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "github.com/spf13/viper"
- "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/flag"
_ "github.com/superseriousbusiness/gotosocial/docs"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -37,48 +35,28 @@ var Version string
//go:generate swagger generate spec
func main() {
- buildInfo, ok := debug.ReadBuildInfo()
- if !ok {
- panic("could not read buildinfo")
- }
+ // Load version string
+ version := version()
- goVersion := buildInfo.GoVersion
- var commit string
- var time string
- for _, s := range buildInfo.Settings {
- if s.Key == "vcs.revision" {
- commit = s.Value[:7]
- }
- if s.Key == "vcs.time" {
- time = s.Value
- }
- }
-
- var versionString string
- if Version != "" {
- versionString = fmt.Sprintf("%s %s %s [%s]", Version, commit, time, goVersion)
- }
-
- // override software version in viper store
- viper.Set(config.Keys.SoftwareVersion, versionString)
+ // override version in config store
+ config.SetSoftwareVersion(version)
// instantiate the root command
rootCmd := &cobra.Command{
- Use: "gotosocial",
- Short: "GoToSocial - a fediverse social media server",
- Long: "GoToSocial - a fediverse social media server\n\nFor help, see: https://docs.gotosocial.org.\n\nCode: https://github.com/superseriousbusiness/gotosocial",
- Version: versionString,
+ Use: "gotosocial",
+ Short: "GoToSocial - a fediverse social media server",
+ Long: "GoToSocial - a fediverse social media server\n\nFor help, see: https://docs.gotosocial.org.\n\nCode: https://github.com/superseriousbusiness/gotosocial",
+ Version: version,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ // before running any other cmd funcs, we must load config-path
+ return config.LoadEarlyFlags(cmd)
+ },
SilenceErrors: true,
SilenceUsage: true,
}
// attach global flags to the root command so that they can be accessed from any subcommand
- flag.Global(rootCmd, config.Defaults)
-
- // bind the config-path flag to viper early so that we can call it in the pre-run of following commands
- if err := viper.BindPFlag(config.Keys.ConfigPath, rootCmd.PersistentFlags().Lookup(config.Keys.ConfigPath)); err != nil {
- logrus.Fatalf("error attaching config flag: %s", err)
- }
+ config.AddGlobalFlags(rootCmd)
// add subcommands
rootCmd.AddCommand(serverCommands())
@@ -91,3 +69,45 @@ func main() {
logrus.Fatalf("error executing command: %s", err)
}
}
+
+// version will build a version string from binary's stored build information.
+func version() string {
+ // Read build information from binary
+ build, ok := debug.ReadBuildInfo()
+ if !ok {
+ return ""
+ }
+
+ // Define easy getter to fetch build settings
+ getSetting := func(key string) string {
+ for i := 0; i < len(build.Settings); i++ {
+ if build.Settings[i].Key == key {
+ return build.Settings[i].Value
+ }
+ }
+ return ""
+ }
+
+ var info []string
+
+ if Version != "" {
+ // Append version if set
+ info = append(info, Version)
+ }
+
+ if vcs := getSetting("vcs"); vcs != "" {
+ // A VCS type was set (99.9% probably git)
+
+ if commit := getSetting("vcs.revision"); commit != "" {
+ if len(commit) > 7 {
+ // Truncate commit
+ commit = commit[:7]
+ }
+
+ // Append VCS + commit if set
+ info = append(info, vcs+"-"+commit)
+ }
+ }
+
+ return strings.Join(info, " ")
+}
diff --git a/cmd/gotosocial/server.go b/cmd/gotosocial/server.go
index fda5bad90..42d5543ea 100644
--- a/cmd/gotosocial/server.go
+++ b/cmd/gotosocial/server.go
@@ -21,7 +21,6 @@ package main
import (
"github.com/spf13/cobra"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action/server"
- "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/flag"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -31,7 +30,6 @@ func serverCommands() *cobra.Command {
Use: "server",
Short: "gotosocial server-related tasks",
}
-
serverStartCmd := &cobra.Command{
Use: "start",
Short: "start the gotosocial server",
@@ -42,8 +40,7 @@ func serverCommands() *cobra.Command {
return run(cmd.Context(), server.Start)
},
}
- flag.Server(serverStartCmd, config.Defaults)
-
+ config.AddServerFlags(serverStartCmd)
serverCmd.AddCommand(serverStartCmd)
return serverCmd
}
diff --git a/go.mod b/go.mod
index 13c743ae2..451610f43 100644
--- a/go.mod
+++ b/go.mod
@@ -32,7 +32,6 @@ require (
github.com/russross/blackfriday/v2 v2.1.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.4.0
- github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.11.0
github.com/stretchr/testify v1.7.1
github.com/superseriousbusiness/activity v1.1.0-gts
@@ -105,6 +104,7 @@ require (
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/superseriousbusiness/go-jpeg-image-structure/v2 v2.0.0-20220321154430-d89a106fdabe // indirect
github.com/tdewolff/parse/v2 v2.5.29 // indirect
diff --git a/internal/api/client/account/account_test.go b/internal/api/client/account/account_test.go
index d6bb5a5c0..f2114a0f8 100644
--- a/internal/api/client/account/account_test.go
+++ b/internal/api/client/account/account_test.go
@@ -8,7 +8,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
@@ -90,8 +89,8 @@ func (suite *AccountStandardTestSuite) newContext(recorder *httptest.ResponseRec
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
baseURI := fmt.Sprintf("%s://%s", protocol, host)
requestURI := fmt.Sprintf("%s/%s", baseURI, requestPath)
diff --git a/internal/api/client/account/accountcreate.go b/internal/api/client/account/accountcreate.go
index ee9f508d7..35eb36216 100644
--- a/internal/api/client/account/accountcreate.go
+++ b/internal/api/client/account/accountcreate.go
@@ -24,7 +24,6 @@ import (
"net/http"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
@@ -123,9 +122,7 @@ func (m *Module) AccountCreatePOSTHandler(c *gin.Context) {
// validateCreateAccount checks through all the necessary prerequisites for creating a new account,
// according to the provided account create request. If the account isn't eligible, an error will be returned.
func validateCreateAccount(form *model.AccountCreateRequest) error {
- keys := config.Keys
-
- if !viper.GetBool(keys.AccountsRegistrationOpen) {
+ if !config.GetAccountsRegistrationOpen() {
return errors.New("registration is not open for this server")
}
@@ -149,7 +146,7 @@ func validateCreateAccount(form *model.AccountCreateRequest) error {
return err
}
- if err := validate.SignUpReason(form.Reason, viper.GetBool(keys.AccountsReasonRequired)); err != nil {
+ if err := validate.SignUpReason(form.Reason, config.GetAccountsReasonRequired()); err != nil {
return err
}
diff --git a/internal/api/client/admin/admin_test.go b/internal/api/client/admin/admin_test.go
index 11e2f8354..251a8be9b 100644
--- a/internal/api/client/admin/admin_test.go
+++ b/internal/api/client/admin/admin_test.go
@@ -26,7 +26,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
@@ -108,8 +107,8 @@ func (suite *AdminStandardTestSuite) newContext(recorder *httptest.ResponseRecor
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["admin_account"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["admin_account"])
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
baseURI := fmt.Sprintf("%s://%s", protocol, host)
requestURI := fmt.Sprintf("%s/%s", baseURI, requestPath)
diff --git a/internal/api/client/admin/mediacleanup.go b/internal/api/client/admin/mediacleanup.go
index 508840b23..02eec82f3 100644
--- a/internal/api/client/admin/mediacleanup.go
+++ b/internal/api/client/admin/mediacleanup.go
@@ -24,7 +24,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -93,7 +92,7 @@ func (m *Module) MediaCleanupPOSTHandler(c *gin.Context) {
var remoteCacheDays int
if form.RemoteCacheDays == nil {
- remoteCacheDays = viper.GetInt(config.Keys.MediaRemoteCacheDays)
+ remoteCacheDays = config.GetMediaRemoteCacheDays()
} else {
remoteCacheDays = *form.RemoteCacheDays
}
diff --git a/internal/api/client/auth/auth_test.go b/internal/api/client/auth/auth_test.go
index fdf1b6baf..bd1a1948e 100644
--- a/internal/api/client/auth/auth_test.go
+++ b/internal/api/client/auth/auth_test.go
@@ -26,7 +26,6 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/memstore"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/auth"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -96,8 +95,8 @@ func (suite *AuthStandardTestSuite) newContext(requestMethod string, requestPath
testrig.ConfigureTemplatesWithGin(engine)
// create the request
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
baseURI := fmt.Sprintf("%s://%s", protocol, host)
requestURI := fmt.Sprintf("%s/%s", baseURI, requestPath)
ctx.Request = httptest.NewRequest(requestMethod, requestURI, nil) // the endpoint we're hitting
diff --git a/internal/api/client/followrequest/followrequest_test.go b/internal/api/client/followrequest/followrequest_test.go
index 14b5656b6..b86e22ce4 100644
--- a/internal/api/client/followrequest/followrequest_test.go
+++ b/internal/api/client/followrequest/followrequest_test.go
@@ -25,7 +25,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequest"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
@@ -104,8 +103,8 @@ func (suite *FollowRequestStandardTestSuite) newContext(recorder *httptest.Respo
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
baseURI := fmt.Sprintf("%s://%s", protocol, host)
requestURI := fmt.Sprintf("%s/%s", baseURI, requestPath)
diff --git a/internal/api/client/instance/instance_test.go b/internal/api/client/instance/instance_test.go
index a1fe1f17c..7ea7d475c 100644
--- a/internal/api/client/instance/instance_test.go
+++ b/internal/api/client/instance/instance_test.go
@@ -26,7 +26,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/instance"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
@@ -108,8 +107,8 @@ func (suite *InstanceStandardTestSuite) newContext(recorder *httptest.ResponseRe
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["admin_account"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["admin_account"])
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
baseURI := fmt.Sprintf("%s://%s", protocol, host)
requestURI := fmt.Sprintf("%s/%s", baseURI, requestPath)
diff --git a/internal/api/client/instance/instanceget.go b/internal/api/client/instance/instanceget.go
index 4f9afdb38..cd6dd32cc 100644
--- a/internal/api/client/instance/instanceget.go
+++ b/internal/api/client/instance/instanceget.go
@@ -4,7 +4,6 @@ import (
"net/http"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -41,7 +40,7 @@ func (m *Module) InstanceInformationGETHandler(c *gin.Context) {
return
}
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
instance, err := m.processor.InstanceGet(c.Request.Context(), host)
if err != nil {
diff --git a/internal/api/client/media/mediacreate.go b/internal/api/client/media/mediacreate.go
index 5946ed398..ed6a12d37 100644
--- a/internal/api/client/media/mediacreate.go
+++ b/internal/api/client/media/mediacreate.go
@@ -24,7 +24,6 @@ import (
"net/http"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
@@ -133,11 +132,10 @@ func validateCreateMedia(form *model.AttachmentRequest) error {
return errors.New("no attachment given")
}
- keys := config.Keys
- maxVideoSize := viper.GetInt(keys.MediaVideoMaxSize)
- maxImageSize := viper.GetInt(keys.MediaImageMaxSize)
- minDescriptionChars := viper.GetInt(keys.MediaDescriptionMinChars)
- maxDescriptionChars := viper.GetInt(keys.MediaDescriptionMaxChars)
+ maxVideoSize := config.GetMediaVideoMaxSize()
+ maxImageSize := config.GetMediaImageMaxSize()
+ minDescriptionChars := config.GetMediaDescriptionMinChars()
+ maxDescriptionChars := config.GetMediaDescriptionMaxChars()
// a very superficial check to see if no size limits are exceeded
// we still don't actually know which media types we're dealing with but the other handlers will go into more detail there
diff --git a/internal/api/client/media/mediacreate_test.go b/internal/api/client/media/mediacreate_test.go
index e16b9f5eb..f39e756f7 100644
--- a/internal/api/client/media/mediacreate_test.go
+++ b/internal/api/client/media/mediacreate_test.go
@@ -33,7 +33,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
mediamodule "github.com/superseriousbusiness/gotosocial/internal/api/client/media"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
@@ -261,7 +260,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateLongDescription() {
func (suite *MediaCreateTestSuite) TestMediaCreateTooShortDescription() {
// set the min description length
- viper.Set(config.Keys.MediaDescriptionMinChars, 500)
+ config.SetMediaDescriptionMinChars(500)
// set up the context for the request
t := suite.testTokens["local_account_1"]
diff --git a/internal/api/client/media/mediaupdate.go b/internal/api/client/media/mediaupdate.go
index ffe3b5e55..21b8c9c8e 100644
--- a/internal/api/client/media/mediaupdate.go
+++ b/internal/api/client/media/mediaupdate.go
@@ -24,7 +24,6 @@ import (
"net/http"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
@@ -141,9 +140,8 @@ func (m *Module) MediaPUTHandler(c *gin.Context) {
}
func validateUpdateMedia(form *model.AttachmentUpdateRequest) error {
- keys := config.Keys
- minDescriptionChars := viper.GetInt(keys.MediaDescriptionMinChars)
- maxDescriptionChars := viper.GetInt(keys.MediaDescriptionMaxChars)
+ minDescriptionChars := config.GetMediaDescriptionMinChars()
+ maxDescriptionChars := config.GetMediaDescriptionMaxChars()
if form.Description != nil {
if len(*form.Description) < minDescriptionChars || len(*form.Description) > maxDescriptionChars {
diff --git a/internal/api/client/media/mediaupdate_test.go b/internal/api/client/media/mediaupdate_test.go
index a87718438..fbf794e1d 100644
--- a/internal/api/client/media/mediaupdate_test.go
+++ b/internal/api/client/media/mediaupdate_test.go
@@ -31,7 +31,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
mediamodule "github.com/superseriousbusiness/gotosocial/internal/api/client/media"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
@@ -188,7 +187,7 @@ func (suite *MediaUpdateTestSuite) TestUpdateImage() {
func (suite *MediaUpdateTestSuite) TestUpdateImageShortDescription() {
// set the min description length
- viper.Set(config.Keys.MediaDescriptionMinChars, 50)
+ config.SetMediaDescriptionMinChars(50)
toUpdate := suite.testAttachments["local_account_1_unattached_1"]
diff --git a/internal/api/client/status/statuscreate.go b/internal/api/client/status/statuscreate.go
index 406472772..2813efb90 100644
--- a/internal/api/client/status/statuscreate.go
+++ b/internal/api/client/status/statuscreate.go
@@ -24,7 +24,6 @@ import (
"net/http"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
@@ -130,12 +129,11 @@ func validateCreateStatus(form *model.AdvancedStatusCreateForm) error {
return errors.New("can't post media + poll in same status")
}
- keys := config.Keys
- maxChars := viper.GetInt(keys.StatusesMaxChars)
- maxMediaFiles := viper.GetInt(keys.StatusesMediaMaxFiles)
- maxPollOptions := viper.GetInt(keys.StatusesPollMaxOptions)
- maxPollChars := viper.GetInt(keys.StatusesPollOptionMaxChars)
- maxCwChars := viper.GetInt(keys.StatusesCWMaxChars)
+ maxChars := config.GetStatusesMaxChars()
+ maxMediaFiles := config.GetStatusesMediaMaxFiles()
+ maxPollOptions := config.GetStatusesPollMaxOptions()
+ maxPollChars := config.GetStatusesPollOptionMaxChars()
+ maxCwChars := config.GetStatusesCWMaxChars()
// validate status
if form.Status != "" {
diff --git a/internal/api/s2s/webfinger/webfingerget.go b/internal/api/s2s/webfinger/webfingerget.go
index 5d237408f..a271c031b 100644
--- a/internal/api/s2s/webfinger/webfingerget.go
+++ b/internal/api/s2s/webfinger/webfingerget.go
@@ -26,7 +26,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -90,8 +89,8 @@ func (m *Module) WebfingerGETRequest(c *gin.Context) {
return
}
- accountDomain := viper.GetString(config.Keys.AccountDomain)
- host := viper.GetString(config.Keys.Host)
+ accountDomain := config.GetAccountDomain()
+ host := config.GetHost()
if requestedAccountDomain != accountDomain && requestedAccountDomain != host {
l.Debugf("aborting request because accountDomain %s does not belong to this instance", requestedAccountDomain)
diff --git a/internal/api/s2s/webfinger/webfingerget_test.go b/internal/api/s2s/webfinger/webfingerget_test.go
index 7871b6a3f..781fad027 100644
--- a/internal/api/s2s/webfinger/webfingerget_test.go
+++ b/internal/api/s2s/webfinger/webfingerget_test.go
@@ -27,7 +27,6 @@ import (
"testing"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/webfinger"
@@ -46,7 +45,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUser() {
targetAccount := suite.testAccounts["local_account_1"]
// setup request
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, host)
recorder := httptest.NewRecorder()
@@ -69,8 +68,9 @@ func (suite *WebfingerGetTestSuite) TestFingerUser() {
}
func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByHost() {
- viper.Set(config.Keys.Host, "gts.example.org")
- viper.Set(config.Keys.AccountDomain, "example.org")
+ config.SetHost("gts.example.org")
+ config.SetAccountDomain("example.org")
+
clientWorker := concurrency.NewWorkerPool[messages.FromClientAPI](-1, -1)
fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1)
suite.processor = processing.NewProcessor(suite.tc, suite.federator, testrig.NewTestOauthServer(suite.db), testrig.NewTestMediaManager(suite.db, suite.storage), suite.storage, suite.db, suite.emailSender, clientWorker, fedWorker)
@@ -82,7 +82,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByHo
}
// setup request
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, host)
recorder := httptest.NewRecorder()
@@ -105,8 +105,9 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByHo
}
func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByAccountDomain() {
- viper.Set(config.Keys.Host, "gts.example.org")
- viper.Set(config.Keys.AccountDomain, "example.org")
+ config.SetHost("gts.example.org")
+ config.SetAccountDomain("example.org")
+
clientWorker := concurrency.NewWorkerPool[messages.FromClientAPI](-1, -1)
fedWorker := concurrency.NewWorkerPool[messages.FromFederator](-1, -1)
suite.processor = processing.NewProcessor(suite.tc, suite.federator, testrig.NewTestOauthServer(suite.db), testrig.NewTestMediaManager(suite.db, suite.storage), suite.storage, suite.db, suite.emailSender, clientWorker, fedWorker)
@@ -118,7 +119,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByAc
}
// setup request
- accountDomain := viper.GetString(config.Keys.AccountDomain)
+ accountDomain := config.GetAccountDomain()
requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, accountDomain)
recorder := httptest.NewRecorder()
@@ -144,7 +145,7 @@ func (suite *WebfingerGetTestSuite) TestFingerUserWithoutAcct() {
targetAccount := suite.testAccounts["local_account_1"]
// setup request -- leave out the 'acct:' prefix, which is prettymuch what pixelfed currently does
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
requestPath := fmt.Sprintf("/%s?resource=%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, host)
recorder := httptest.NewRecorder()
diff --git a/internal/config/config.go b/internal/config/config.go
new file mode 100644
index 000000000..431fbbe4d
--- /dev/null
+++ b/internal/config/config.go
@@ -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 .
+*/
+
+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)
+}
diff --git a/internal/config/defaults.go b/internal/config/defaults.go
index 847f10c81..75af21222 100644
--- a/internal/config/defaults.go
+++ b/internal/config/defaults.go
@@ -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",
diff --git a/internal/config/file.go b/internal/config/file.go
deleted file mode 100644
index 75d273fed..000000000
--- a/internal/config/file.go
+++ /dev/null
@@ -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 .
-*/
-
-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
-}
diff --git a/internal/config/flags.go b/internal/config/flags.go
new file mode 100644
index 000000000..0be372551
--- /dev/null
+++ b/internal/config/flags.go
@@ -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 .
+*/
+
+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)
+ }
+}
diff --git a/internal/config/gen/gen.go b/internal/config/gen/gen.go
new file mode 100644
index 000000000..d36fee0e9
--- /dev/null
+++ b/internal/config/gen/gen.go
@@ -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 .
+*/
+
+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 .
+*/
+`
+
+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)
+ }
+}
diff --git a/internal/config/global.go b/internal/config/global.go
new file mode 100644
index 000000000..8752fc925
--- /dev/null
+++ b/internal/config/global.go
@@ -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 .
+*/
+
+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)
+}
diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go
new file mode 100644
index 000000000..a90199495
--- /dev/null
+++ b/internal/config/helpers.gen.go
@@ -0,0 +1,1494 @@
+// THIS IS A GENERATED FILE, DO NOT EDIT BY HAND
+/*
+ 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 .
+*/
+package config
+
+// GetLogLevel safely fetches the Configuration value for state's 'LogLevel' field
+func (st *ConfigState) GetLogLevel() (v string) {
+ st.mutex.Lock()
+ v = st.config.LogLevel
+ st.mutex.Unlock()
+ return
+}
+
+// SetLogLevel safely sets the Configuration value for state's 'LogLevel' field
+func (st *ConfigState) SetLogLevel(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LogLevel = v
+ st.reloadToViper()
+}
+
+// LogLevelFlag returns the flag name for the 'LogLevel' field
+func LogLevelFlag() string { return "log-level" }
+
+// GetLogLevel safely fetches the value for global configuration 'LogLevel' field
+func GetLogLevel() string { return global.GetLogLevel() }
+
+// SetLogLevel safely sets the value for global configuration 'LogLevel' field
+func SetLogLevel(v string) { global.SetLogLevel(v) }
+
+// GetLogDbQueries safely fetches the Configuration value for state's 'LogDbQueries' field
+func (st *ConfigState) GetLogDbQueries() (v bool) {
+ st.mutex.Lock()
+ v = st.config.LogDbQueries
+ st.mutex.Unlock()
+ return
+}
+
+// SetLogDbQueries safely sets the Configuration value for state's 'LogDbQueries' field
+func (st *ConfigState) SetLogDbQueries(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LogDbQueries = v
+ st.reloadToViper()
+}
+
+// LogDbQueriesFlag returns the flag name for the 'LogDbQueries' field
+func LogDbQueriesFlag() string { return "log-db-queries" }
+
+// GetLogDbQueries safely fetches the value for global configuration 'LogDbQueries' field
+func GetLogDbQueries() bool { return global.GetLogDbQueries() }
+
+// SetLogDbQueries safely sets the value for global configuration 'LogDbQueries' field
+func SetLogDbQueries(v bool) { global.SetLogDbQueries(v) }
+
+// GetApplicationName safely fetches the Configuration value for state's 'ApplicationName' field
+func (st *ConfigState) GetApplicationName() (v string) {
+ st.mutex.Lock()
+ v = st.config.ApplicationName
+ st.mutex.Unlock()
+ return
+}
+
+// SetApplicationName safely sets the Configuration value for state's 'ApplicationName' field
+func (st *ConfigState) SetApplicationName(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.ApplicationName = v
+ st.reloadToViper()
+}
+
+// ApplicationNameFlag returns the flag name for the 'ApplicationName' field
+func ApplicationNameFlag() string { return "application-name" }
+
+// GetApplicationName safely fetches the value for global configuration 'ApplicationName' field
+func GetApplicationName() string { return global.GetApplicationName() }
+
+// SetApplicationName safely sets the value for global configuration 'ApplicationName' field
+func SetApplicationName(v string) { global.SetApplicationName(v) }
+
+// GetConfigPath safely fetches the Configuration value for state's 'ConfigPath' field
+func (st *ConfigState) GetConfigPath() (v string) {
+ st.mutex.Lock()
+ v = st.config.ConfigPath
+ st.mutex.Unlock()
+ return
+}
+
+// SetConfigPath safely sets the Configuration value for state's 'ConfigPath' field
+func (st *ConfigState) SetConfigPath(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.ConfigPath = v
+ st.reloadToViper()
+}
+
+// ConfigPathFlag returns the flag name for the 'ConfigPath' field
+func ConfigPathFlag() string { return "config-path" }
+
+// GetConfigPath safely fetches the value for global configuration 'ConfigPath' field
+func GetConfigPath() string { return global.GetConfigPath() }
+
+// SetConfigPath safely sets the value for global configuration 'ConfigPath' field
+func SetConfigPath(v string) { global.SetConfigPath(v) }
+
+// GetHost safely fetches the Configuration value for state's 'Host' field
+func (st *ConfigState) GetHost() (v string) {
+ st.mutex.Lock()
+ v = st.config.Host
+ st.mutex.Unlock()
+ return
+}
+
+// SetHost safely sets the Configuration value for state's 'Host' field
+func (st *ConfigState) SetHost(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.Host = v
+ st.reloadToViper()
+}
+
+// HostFlag returns the flag name for the 'Host' field
+func HostFlag() string { return "host" }
+
+// GetHost safely fetches the value for global configuration 'Host' field
+func GetHost() string { return global.GetHost() }
+
+// SetHost safely sets the value for global configuration 'Host' field
+func SetHost(v string) { global.SetHost(v) }
+
+// GetAccountDomain safely fetches the Configuration value for state's 'AccountDomain' field
+func (st *ConfigState) GetAccountDomain() (v string) {
+ st.mutex.Lock()
+ v = st.config.AccountDomain
+ st.mutex.Unlock()
+ return
+}
+
+// SetAccountDomain safely sets the Configuration value for state's 'AccountDomain' field
+func (st *ConfigState) SetAccountDomain(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AccountDomain = v
+ st.reloadToViper()
+}
+
+// AccountDomainFlag returns the flag name for the 'AccountDomain' field
+func AccountDomainFlag() string { return "account-domain" }
+
+// GetAccountDomain safely fetches the value for global configuration 'AccountDomain' field
+func GetAccountDomain() string { return global.GetAccountDomain() }
+
+// SetAccountDomain safely sets the value for global configuration 'AccountDomain' field
+func SetAccountDomain(v string) { global.SetAccountDomain(v) }
+
+// GetProtocol safely fetches the Configuration value for state's 'Protocol' field
+func (st *ConfigState) GetProtocol() (v string) {
+ st.mutex.Lock()
+ v = st.config.Protocol
+ st.mutex.Unlock()
+ return
+}
+
+// SetProtocol safely sets the Configuration value for state's 'Protocol' field
+func (st *ConfigState) SetProtocol(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.Protocol = v
+ st.reloadToViper()
+}
+
+// ProtocolFlag returns the flag name for the 'Protocol' field
+func ProtocolFlag() string { return "protocol" }
+
+// GetProtocol safely fetches the value for global configuration 'Protocol' field
+func GetProtocol() string { return global.GetProtocol() }
+
+// SetProtocol safely sets the value for global configuration 'Protocol' field
+func SetProtocol(v string) { global.SetProtocol(v) }
+
+// GetBindAddress safely fetches the Configuration value for state's 'BindAddress' field
+func (st *ConfigState) GetBindAddress() (v string) {
+ st.mutex.Lock()
+ v = st.config.BindAddress
+ st.mutex.Unlock()
+ return
+}
+
+// SetBindAddress safely sets the Configuration value for state's 'BindAddress' field
+func (st *ConfigState) SetBindAddress(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.BindAddress = v
+ st.reloadToViper()
+}
+
+// BindAddressFlag returns the flag name for the 'BindAddress' field
+func BindAddressFlag() string { return "bind-address" }
+
+// GetBindAddress safely fetches the value for global configuration 'BindAddress' field
+func GetBindAddress() string { return global.GetBindAddress() }
+
+// SetBindAddress safely sets the value for global configuration 'BindAddress' field
+func SetBindAddress(v string) { global.SetBindAddress(v) }
+
+// GetPort safely fetches the Configuration value for state's 'Port' field
+func (st *ConfigState) GetPort() (v int) {
+ st.mutex.Lock()
+ v = st.config.Port
+ st.mutex.Unlock()
+ return
+}
+
+// SetPort safely sets the Configuration value for state's 'Port' field
+func (st *ConfigState) SetPort(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.Port = v
+ st.reloadToViper()
+}
+
+// PortFlag returns the flag name for the 'Port' field
+func PortFlag() string { return "port" }
+
+// GetPort safely fetches the value for global configuration 'Port' field
+func GetPort() int { return global.GetPort() }
+
+// SetPort safely sets the value for global configuration 'Port' field
+func SetPort(v int) { global.SetPort(v) }
+
+// GetTrustedProxies safely fetches the Configuration value for state's 'TrustedProxies' field
+func (st *ConfigState) GetTrustedProxies() (v []string) {
+ st.mutex.Lock()
+ v = st.config.TrustedProxies
+ st.mutex.Unlock()
+ return
+}
+
+// SetTrustedProxies safely sets the Configuration value for state's 'TrustedProxies' field
+func (st *ConfigState) SetTrustedProxies(v []string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.TrustedProxies = v
+ st.reloadToViper()
+}
+
+// TrustedProxiesFlag returns the flag name for the 'TrustedProxies' field
+func TrustedProxiesFlag() string { return "trusted-proxies" }
+
+// GetTrustedProxies safely fetches the value for global configuration 'TrustedProxies' field
+func GetTrustedProxies() []string { return global.GetTrustedProxies() }
+
+// SetTrustedProxies safely sets the value for global configuration 'TrustedProxies' field
+func SetTrustedProxies(v []string) { global.SetTrustedProxies(v) }
+
+// GetSoftwareVersion safely fetches the Configuration value for state's 'SoftwareVersion' field
+func (st *ConfigState) GetSoftwareVersion() (v string) {
+ st.mutex.Lock()
+ v = st.config.SoftwareVersion
+ st.mutex.Unlock()
+ return
+}
+
+// SetSoftwareVersion safely sets the Configuration value for state's 'SoftwareVersion' field
+func (st *ConfigState) SetSoftwareVersion(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SoftwareVersion = v
+ st.reloadToViper()
+}
+
+// SoftwareVersionFlag returns the flag name for the 'SoftwareVersion' field
+func SoftwareVersionFlag() string { return "software-version" }
+
+// GetSoftwareVersion safely fetches the value for global configuration 'SoftwareVersion' field
+func GetSoftwareVersion() string { return global.GetSoftwareVersion() }
+
+// SetSoftwareVersion safely sets the value for global configuration 'SoftwareVersion' field
+func SetSoftwareVersion(v string) { global.SetSoftwareVersion(v) }
+
+// GetDbType safely fetches the Configuration value for state's 'DbType' field
+func (st *ConfigState) GetDbType() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbType
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbType safely sets the Configuration value for state's 'DbType' field
+func (st *ConfigState) SetDbType(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbType = v
+ st.reloadToViper()
+}
+
+// DbTypeFlag returns the flag name for the 'DbType' field
+func DbTypeFlag() string { return "db-type" }
+
+// GetDbType safely fetches the value for global configuration 'DbType' field
+func GetDbType() string { return global.GetDbType() }
+
+// SetDbType safely sets the value for global configuration 'DbType' field
+func SetDbType(v string) { global.SetDbType(v) }
+
+// GetDbAddress safely fetches the Configuration value for state's 'DbAddress' field
+func (st *ConfigState) GetDbAddress() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbAddress
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbAddress safely sets the Configuration value for state's 'DbAddress' field
+func (st *ConfigState) SetDbAddress(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbAddress = v
+ st.reloadToViper()
+}
+
+// DbAddressFlag returns the flag name for the 'DbAddress' field
+func DbAddressFlag() string { return "db-address" }
+
+// GetDbAddress safely fetches the value for global configuration 'DbAddress' field
+func GetDbAddress() string { return global.GetDbAddress() }
+
+// SetDbAddress safely sets the value for global configuration 'DbAddress' field
+func SetDbAddress(v string) { global.SetDbAddress(v) }
+
+// GetDbPort safely fetches the Configuration value for state's 'DbPort' field
+func (st *ConfigState) GetDbPort() (v int) {
+ st.mutex.Lock()
+ v = st.config.DbPort
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbPort safely sets the Configuration value for state's 'DbPort' field
+func (st *ConfigState) SetDbPort(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbPort = v
+ st.reloadToViper()
+}
+
+// DbPortFlag returns the flag name for the 'DbPort' field
+func DbPortFlag() string { return "db-port" }
+
+// GetDbPort safely fetches the value for global configuration 'DbPort' field
+func GetDbPort() int { return global.GetDbPort() }
+
+// SetDbPort safely sets the value for global configuration 'DbPort' field
+func SetDbPort(v int) { global.SetDbPort(v) }
+
+// GetDbUser safely fetches the Configuration value for state's 'DbUser' field
+func (st *ConfigState) GetDbUser() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbUser
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbUser safely sets the Configuration value for state's 'DbUser' field
+func (st *ConfigState) SetDbUser(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbUser = v
+ st.reloadToViper()
+}
+
+// DbUserFlag returns the flag name for the 'DbUser' field
+func DbUserFlag() string { return "db-user" }
+
+// GetDbUser safely fetches the value for global configuration 'DbUser' field
+func GetDbUser() string { return global.GetDbUser() }
+
+// SetDbUser safely sets the value for global configuration 'DbUser' field
+func SetDbUser(v string) { global.SetDbUser(v) }
+
+// GetDbPassword safely fetches the Configuration value for state's 'DbPassword' field
+func (st *ConfigState) GetDbPassword() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbPassword
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbPassword safely sets the Configuration value for state's 'DbPassword' field
+func (st *ConfigState) SetDbPassword(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbPassword = v
+ st.reloadToViper()
+}
+
+// DbPasswordFlag returns the flag name for the 'DbPassword' field
+func DbPasswordFlag() string { return "db-password" }
+
+// GetDbPassword safely fetches the value for global configuration 'DbPassword' field
+func GetDbPassword() string { return global.GetDbPassword() }
+
+// SetDbPassword safely sets the value for global configuration 'DbPassword' field
+func SetDbPassword(v string) { global.SetDbPassword(v) }
+
+// GetDbDatabase safely fetches the Configuration value for state's 'DbDatabase' field
+func (st *ConfigState) GetDbDatabase() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbDatabase
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbDatabase safely sets the Configuration value for state's 'DbDatabase' field
+func (st *ConfigState) SetDbDatabase(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbDatabase = v
+ st.reloadToViper()
+}
+
+// DbDatabaseFlag returns the flag name for the 'DbDatabase' field
+func DbDatabaseFlag() string { return "db-database" }
+
+// GetDbDatabase safely fetches the value for global configuration 'DbDatabase' field
+func GetDbDatabase() string { return global.GetDbDatabase() }
+
+// SetDbDatabase safely sets the value for global configuration 'DbDatabase' field
+func SetDbDatabase(v string) { global.SetDbDatabase(v) }
+
+// GetDbTLSMode safely fetches the Configuration value for state's 'DbTLSMode' field
+func (st *ConfigState) GetDbTLSMode() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbTLSMode
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbTLSMode safely sets the Configuration value for state's 'DbTLSMode' field
+func (st *ConfigState) SetDbTLSMode(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbTLSMode = v
+ st.reloadToViper()
+}
+
+// DbTLSModeFlag returns the flag name for the 'DbTLSMode' field
+func DbTLSModeFlag() string { return "db-tls-mode" }
+
+// GetDbTLSMode safely fetches the value for global configuration 'DbTLSMode' field
+func GetDbTLSMode() string { return global.GetDbTLSMode() }
+
+// SetDbTLSMode safely sets the value for global configuration 'DbTLSMode' field
+func SetDbTLSMode(v string) { global.SetDbTLSMode(v) }
+
+// GetDbTLSCACert safely fetches the Configuration value for state's 'DbTLSCACert' field
+func (st *ConfigState) GetDbTLSCACert() (v string) {
+ st.mutex.Lock()
+ v = st.config.DbTLSCACert
+ st.mutex.Unlock()
+ return
+}
+
+// SetDbTLSCACert safely sets the Configuration value for state's 'DbTLSCACert' field
+func (st *ConfigState) SetDbTLSCACert(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.DbTLSCACert = v
+ st.reloadToViper()
+}
+
+// DbTLSCACertFlag returns the flag name for the 'DbTLSCACert' field
+func DbTLSCACertFlag() string { return "db-tls-ca-cert" }
+
+// GetDbTLSCACert safely fetches the value for global configuration 'DbTLSCACert' field
+func GetDbTLSCACert() string { return global.GetDbTLSCACert() }
+
+// SetDbTLSCACert safely sets the value for global configuration 'DbTLSCACert' field
+func SetDbTLSCACert(v string) { global.SetDbTLSCACert(v) }
+
+// GetWebTemplateBaseDir safely fetches the Configuration value for state's 'WebTemplateBaseDir' field
+func (st *ConfigState) GetWebTemplateBaseDir() (v string) {
+ st.mutex.Lock()
+ v = st.config.WebTemplateBaseDir
+ st.mutex.Unlock()
+ return
+}
+
+// SetWebTemplateBaseDir safely sets the Configuration value for state's 'WebTemplateBaseDir' field
+func (st *ConfigState) SetWebTemplateBaseDir(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.WebTemplateBaseDir = v
+ st.reloadToViper()
+}
+
+// WebTemplateBaseDirFlag returns the flag name for the 'WebTemplateBaseDir' field
+func WebTemplateBaseDirFlag() string { return "web-template-base-dir" }
+
+// GetWebTemplateBaseDir safely fetches the value for global configuration 'WebTemplateBaseDir' field
+func GetWebTemplateBaseDir() string { return global.GetWebTemplateBaseDir() }
+
+// SetWebTemplateBaseDir safely sets the value for global configuration 'WebTemplateBaseDir' field
+func SetWebTemplateBaseDir(v string) { global.SetWebTemplateBaseDir(v) }
+
+// GetWebAssetBaseDir safely fetches the Configuration value for state's 'WebAssetBaseDir' field
+func (st *ConfigState) GetWebAssetBaseDir() (v string) {
+ st.mutex.Lock()
+ v = st.config.WebAssetBaseDir
+ st.mutex.Unlock()
+ return
+}
+
+// SetWebAssetBaseDir safely sets the Configuration value for state's 'WebAssetBaseDir' field
+func (st *ConfigState) SetWebAssetBaseDir(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.WebAssetBaseDir = v
+ st.reloadToViper()
+}
+
+// WebAssetBaseDirFlag returns the flag name for the 'WebAssetBaseDir' field
+func WebAssetBaseDirFlag() string { return "web-asset-base-dir" }
+
+// GetWebAssetBaseDir safely fetches the value for global configuration 'WebAssetBaseDir' field
+func GetWebAssetBaseDir() string { return global.GetWebAssetBaseDir() }
+
+// SetWebAssetBaseDir safely sets the value for global configuration 'WebAssetBaseDir' field
+func SetWebAssetBaseDir(v string) { global.SetWebAssetBaseDir(v) }
+
+// GetAccountsRegistrationOpen safely fetches the Configuration value for state's 'AccountsRegistrationOpen' field
+func (st *ConfigState) GetAccountsRegistrationOpen() (v bool) {
+ st.mutex.Lock()
+ v = st.config.AccountsRegistrationOpen
+ st.mutex.Unlock()
+ return
+}
+
+// SetAccountsRegistrationOpen safely sets the Configuration value for state's 'AccountsRegistrationOpen' field
+func (st *ConfigState) SetAccountsRegistrationOpen(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AccountsRegistrationOpen = v
+ st.reloadToViper()
+}
+
+// AccountsRegistrationOpenFlag returns the flag name for the 'AccountsRegistrationOpen' field
+func AccountsRegistrationOpenFlag() string { return "accounts-registration-open" }
+
+// GetAccountsRegistrationOpen safely fetches the value for global configuration 'AccountsRegistrationOpen' field
+func GetAccountsRegistrationOpen() bool { return global.GetAccountsRegistrationOpen() }
+
+// SetAccountsRegistrationOpen safely sets the value for global configuration 'AccountsRegistrationOpen' field
+func SetAccountsRegistrationOpen(v bool) { global.SetAccountsRegistrationOpen(v) }
+
+// GetAccountsApprovalRequired safely fetches the Configuration value for state's 'AccountsApprovalRequired' field
+func (st *ConfigState) GetAccountsApprovalRequired() (v bool) {
+ st.mutex.Lock()
+ v = st.config.AccountsApprovalRequired
+ st.mutex.Unlock()
+ return
+}
+
+// SetAccountsApprovalRequired safely sets the Configuration value for state's 'AccountsApprovalRequired' field
+func (st *ConfigState) SetAccountsApprovalRequired(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AccountsApprovalRequired = v
+ st.reloadToViper()
+}
+
+// AccountsApprovalRequiredFlag returns the flag name for the 'AccountsApprovalRequired' field
+func AccountsApprovalRequiredFlag() string { return "accounts-approval-required" }
+
+// GetAccountsApprovalRequired safely fetches the value for global configuration 'AccountsApprovalRequired' field
+func GetAccountsApprovalRequired() bool { return global.GetAccountsApprovalRequired() }
+
+// SetAccountsApprovalRequired safely sets the value for global configuration 'AccountsApprovalRequired' field
+func SetAccountsApprovalRequired(v bool) { global.SetAccountsApprovalRequired(v) }
+
+// GetAccountsReasonRequired safely fetches the Configuration value for state's 'AccountsReasonRequired' field
+func (st *ConfigState) GetAccountsReasonRequired() (v bool) {
+ st.mutex.Lock()
+ v = st.config.AccountsReasonRequired
+ st.mutex.Unlock()
+ return
+}
+
+// SetAccountsReasonRequired safely sets the Configuration value for state's 'AccountsReasonRequired' field
+func (st *ConfigState) SetAccountsReasonRequired(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AccountsReasonRequired = v
+ st.reloadToViper()
+}
+
+// AccountsReasonRequiredFlag returns the flag name for the 'AccountsReasonRequired' field
+func AccountsReasonRequiredFlag() string { return "accounts-reason-required" }
+
+// GetAccountsReasonRequired safely fetches the value for global configuration 'AccountsReasonRequired' field
+func GetAccountsReasonRequired() bool { return global.GetAccountsReasonRequired() }
+
+// SetAccountsReasonRequired safely sets the value for global configuration 'AccountsReasonRequired' field
+func SetAccountsReasonRequired(v bool) { global.SetAccountsReasonRequired(v) }
+
+// GetMediaImageMaxSize safely fetches the Configuration value for state's 'MediaImageMaxSize' field
+func (st *ConfigState) GetMediaImageMaxSize() (v int) {
+ st.mutex.Lock()
+ v = st.config.MediaImageMaxSize
+ st.mutex.Unlock()
+ return
+}
+
+// SetMediaImageMaxSize safely sets the Configuration value for state's 'MediaImageMaxSize' field
+func (st *ConfigState) SetMediaImageMaxSize(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaImageMaxSize = v
+ st.reloadToViper()
+}
+
+// MediaImageMaxSizeFlag returns the flag name for the 'MediaImageMaxSize' field
+func MediaImageMaxSizeFlag() string { return "media-image-max-size" }
+
+// GetMediaImageMaxSize safely fetches the value for global configuration 'MediaImageMaxSize' field
+func GetMediaImageMaxSize() int { return global.GetMediaImageMaxSize() }
+
+// SetMediaImageMaxSize safely sets the value for global configuration 'MediaImageMaxSize' field
+func SetMediaImageMaxSize(v int) { global.SetMediaImageMaxSize(v) }
+
+// GetMediaVideoMaxSize safely fetches the Configuration value for state's 'MediaVideoMaxSize' field
+func (st *ConfigState) GetMediaVideoMaxSize() (v int) {
+ st.mutex.Lock()
+ v = st.config.MediaVideoMaxSize
+ st.mutex.Unlock()
+ return
+}
+
+// SetMediaVideoMaxSize safely sets the Configuration value for state's 'MediaVideoMaxSize' field
+func (st *ConfigState) SetMediaVideoMaxSize(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaVideoMaxSize = v
+ st.reloadToViper()
+}
+
+// MediaVideoMaxSizeFlag returns the flag name for the 'MediaVideoMaxSize' field
+func MediaVideoMaxSizeFlag() string { return "media-video-max-size" }
+
+// GetMediaVideoMaxSize safely fetches the value for global configuration 'MediaVideoMaxSize' field
+func GetMediaVideoMaxSize() int { return global.GetMediaVideoMaxSize() }
+
+// SetMediaVideoMaxSize safely sets the value for global configuration 'MediaVideoMaxSize' field
+func SetMediaVideoMaxSize(v int) { global.SetMediaVideoMaxSize(v) }
+
+// GetMediaDescriptionMinChars safely fetches the Configuration value for state's 'MediaDescriptionMinChars' field
+func (st *ConfigState) GetMediaDescriptionMinChars() (v int) {
+ st.mutex.Lock()
+ v = st.config.MediaDescriptionMinChars
+ st.mutex.Unlock()
+ return
+}
+
+// SetMediaDescriptionMinChars safely sets the Configuration value for state's 'MediaDescriptionMinChars' field
+func (st *ConfigState) SetMediaDescriptionMinChars(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaDescriptionMinChars = v
+ st.reloadToViper()
+}
+
+// MediaDescriptionMinCharsFlag returns the flag name for the 'MediaDescriptionMinChars' field
+func MediaDescriptionMinCharsFlag() string { return "media-description-min-chars" }
+
+// GetMediaDescriptionMinChars safely fetches the value for global configuration 'MediaDescriptionMinChars' field
+func GetMediaDescriptionMinChars() int { return global.GetMediaDescriptionMinChars() }
+
+// SetMediaDescriptionMinChars safely sets the value for global configuration 'MediaDescriptionMinChars' field
+func SetMediaDescriptionMinChars(v int) { global.SetMediaDescriptionMinChars(v) }
+
+// GetMediaDescriptionMaxChars safely fetches the Configuration value for state's 'MediaDescriptionMaxChars' field
+func (st *ConfigState) GetMediaDescriptionMaxChars() (v int) {
+ st.mutex.Lock()
+ v = st.config.MediaDescriptionMaxChars
+ st.mutex.Unlock()
+ return
+}
+
+// SetMediaDescriptionMaxChars safely sets the Configuration value for state's 'MediaDescriptionMaxChars' field
+func (st *ConfigState) SetMediaDescriptionMaxChars(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaDescriptionMaxChars = v
+ st.reloadToViper()
+}
+
+// MediaDescriptionMaxCharsFlag returns the flag name for the 'MediaDescriptionMaxChars' field
+func MediaDescriptionMaxCharsFlag() string { return "media-description-max-chars" }
+
+// GetMediaDescriptionMaxChars safely fetches the value for global configuration 'MediaDescriptionMaxChars' field
+func GetMediaDescriptionMaxChars() int { return global.GetMediaDescriptionMaxChars() }
+
+// SetMediaDescriptionMaxChars safely sets the value for global configuration 'MediaDescriptionMaxChars' field
+func SetMediaDescriptionMaxChars(v int) { global.SetMediaDescriptionMaxChars(v) }
+
+// GetMediaRemoteCacheDays safely fetches the Configuration value for state's 'MediaRemoteCacheDays' field
+func (st *ConfigState) GetMediaRemoteCacheDays() (v int) {
+ st.mutex.Lock()
+ v = st.config.MediaRemoteCacheDays
+ st.mutex.Unlock()
+ return
+}
+
+// SetMediaRemoteCacheDays safely sets the Configuration value for state's 'MediaRemoteCacheDays' field
+func (st *ConfigState) SetMediaRemoteCacheDays(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaRemoteCacheDays = v
+ st.reloadToViper()
+}
+
+// MediaRemoteCacheDaysFlag returns the flag name for the 'MediaRemoteCacheDays' field
+func MediaRemoteCacheDaysFlag() string { return "media-remote-cache-days" }
+
+// GetMediaRemoteCacheDays safely fetches the value for global configuration 'MediaRemoteCacheDays' field
+func GetMediaRemoteCacheDays() int { return global.GetMediaRemoteCacheDays() }
+
+// SetMediaRemoteCacheDays safely sets the value for global configuration 'MediaRemoteCacheDays' field
+func SetMediaRemoteCacheDays(v int) { global.SetMediaRemoteCacheDays(v) }
+
+// GetStorageBackend safely fetches the Configuration value for state's 'StorageBackend' field
+func (st *ConfigState) GetStorageBackend() (v string) {
+ st.mutex.Lock()
+ v = st.config.StorageBackend
+ st.mutex.Unlock()
+ return
+}
+
+// SetStorageBackend safely sets the Configuration value for state's 'StorageBackend' field
+func (st *ConfigState) SetStorageBackend(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StorageBackend = v
+ st.reloadToViper()
+}
+
+// StorageBackendFlag returns the flag name for the 'StorageBackend' field
+func StorageBackendFlag() string { return "storage-backend" }
+
+// GetStorageBackend safely fetches the value for global configuration 'StorageBackend' field
+func GetStorageBackend() string { return global.GetStorageBackend() }
+
+// SetStorageBackend safely sets the value for global configuration 'StorageBackend' field
+func SetStorageBackend(v string) { global.SetStorageBackend(v) }
+
+// GetStorageLocalBasePath safely fetches the Configuration value for state's 'StorageLocalBasePath' field
+func (st *ConfigState) GetStorageLocalBasePath() (v string) {
+ st.mutex.Lock()
+ v = st.config.StorageLocalBasePath
+ st.mutex.Unlock()
+ return
+}
+
+// SetStorageLocalBasePath safely sets the Configuration value for state's 'StorageLocalBasePath' field
+func (st *ConfigState) SetStorageLocalBasePath(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StorageLocalBasePath = v
+ st.reloadToViper()
+}
+
+// StorageLocalBasePathFlag returns the flag name for the 'StorageLocalBasePath' field
+func StorageLocalBasePathFlag() string { return "storage-local-base-path" }
+
+// GetStorageLocalBasePath safely fetches the value for global configuration 'StorageLocalBasePath' field
+func GetStorageLocalBasePath() string { return global.GetStorageLocalBasePath() }
+
+// SetStorageLocalBasePath safely sets the value for global configuration 'StorageLocalBasePath' field
+func SetStorageLocalBasePath(v string) { global.SetStorageLocalBasePath(v) }
+
+// GetStatusesMaxChars safely fetches the Configuration value for state's 'StatusesMaxChars' field
+func (st *ConfigState) GetStatusesMaxChars() (v int) {
+ st.mutex.Lock()
+ v = st.config.StatusesMaxChars
+ st.mutex.Unlock()
+ return
+}
+
+// SetStatusesMaxChars safely sets the Configuration value for state's 'StatusesMaxChars' field
+func (st *ConfigState) SetStatusesMaxChars(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StatusesMaxChars = v
+ st.reloadToViper()
+}
+
+// StatusesMaxCharsFlag returns the flag name for the 'StatusesMaxChars' field
+func StatusesMaxCharsFlag() string { return "statuses-max-chars" }
+
+// GetStatusesMaxChars safely fetches the value for global configuration 'StatusesMaxChars' field
+func GetStatusesMaxChars() int { return global.GetStatusesMaxChars() }
+
+// SetStatusesMaxChars safely sets the value for global configuration 'StatusesMaxChars' field
+func SetStatusesMaxChars(v int) { global.SetStatusesMaxChars(v) }
+
+// GetStatusesCWMaxChars safely fetches the Configuration value for state's 'StatusesCWMaxChars' field
+func (st *ConfigState) GetStatusesCWMaxChars() (v int) {
+ st.mutex.Lock()
+ v = st.config.StatusesCWMaxChars
+ st.mutex.Unlock()
+ return
+}
+
+// SetStatusesCWMaxChars safely sets the Configuration value for state's 'StatusesCWMaxChars' field
+func (st *ConfigState) SetStatusesCWMaxChars(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StatusesCWMaxChars = v
+ st.reloadToViper()
+}
+
+// StatusesCWMaxCharsFlag returns the flag name for the 'StatusesCWMaxChars' field
+func StatusesCWMaxCharsFlag() string { return "statuses-cw-max-chars" }
+
+// GetStatusesCWMaxChars safely fetches the value for global configuration 'StatusesCWMaxChars' field
+func GetStatusesCWMaxChars() int { return global.GetStatusesCWMaxChars() }
+
+// SetStatusesCWMaxChars safely sets the value for global configuration 'StatusesCWMaxChars' field
+func SetStatusesCWMaxChars(v int) { global.SetStatusesCWMaxChars(v) }
+
+// GetStatusesPollMaxOptions safely fetches the Configuration value for state's 'StatusesPollMaxOptions' field
+func (st *ConfigState) GetStatusesPollMaxOptions() (v int) {
+ st.mutex.Lock()
+ v = st.config.StatusesPollMaxOptions
+ st.mutex.Unlock()
+ return
+}
+
+// SetStatusesPollMaxOptions safely sets the Configuration value for state's 'StatusesPollMaxOptions' field
+func (st *ConfigState) SetStatusesPollMaxOptions(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StatusesPollMaxOptions = v
+ st.reloadToViper()
+}
+
+// StatusesPollMaxOptionsFlag returns the flag name for the 'StatusesPollMaxOptions' field
+func StatusesPollMaxOptionsFlag() string { return "statuses-poll-max-options" }
+
+// GetStatusesPollMaxOptions safely fetches the value for global configuration 'StatusesPollMaxOptions' field
+func GetStatusesPollMaxOptions() int { return global.GetStatusesPollMaxOptions() }
+
+// SetStatusesPollMaxOptions safely sets the value for global configuration 'StatusesPollMaxOptions' field
+func SetStatusesPollMaxOptions(v int) { global.SetStatusesPollMaxOptions(v) }
+
+// GetStatusesPollOptionMaxChars safely fetches the Configuration value for state's 'StatusesPollOptionMaxChars' field
+func (st *ConfigState) GetStatusesPollOptionMaxChars() (v int) {
+ st.mutex.Lock()
+ v = st.config.StatusesPollOptionMaxChars
+ st.mutex.Unlock()
+ return
+}
+
+// SetStatusesPollOptionMaxChars safely sets the Configuration value for state's 'StatusesPollOptionMaxChars' field
+func (st *ConfigState) SetStatusesPollOptionMaxChars(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StatusesPollOptionMaxChars = v
+ st.reloadToViper()
+}
+
+// StatusesPollOptionMaxCharsFlag returns the flag name for the 'StatusesPollOptionMaxChars' field
+func StatusesPollOptionMaxCharsFlag() string { return "statuses-poll-option-max-chars" }
+
+// GetStatusesPollOptionMaxChars safely fetches the value for global configuration 'StatusesPollOptionMaxChars' field
+func GetStatusesPollOptionMaxChars() int { return global.GetStatusesPollOptionMaxChars() }
+
+// SetStatusesPollOptionMaxChars safely sets the value for global configuration 'StatusesPollOptionMaxChars' field
+func SetStatusesPollOptionMaxChars(v int) { global.SetStatusesPollOptionMaxChars(v) }
+
+// GetStatusesMediaMaxFiles safely fetches the Configuration value for state's 'StatusesMediaMaxFiles' field
+func (st *ConfigState) GetStatusesMediaMaxFiles() (v int) {
+ st.mutex.Lock()
+ v = st.config.StatusesMediaMaxFiles
+ st.mutex.Unlock()
+ return
+}
+
+// SetStatusesMediaMaxFiles safely sets the Configuration value for state's 'StatusesMediaMaxFiles' field
+func (st *ConfigState) SetStatusesMediaMaxFiles(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.StatusesMediaMaxFiles = v
+ st.reloadToViper()
+}
+
+// StatusesMediaMaxFilesFlag returns the flag name for the 'StatusesMediaMaxFiles' field
+func StatusesMediaMaxFilesFlag() string { return "statuses-media-max-files" }
+
+// GetStatusesMediaMaxFiles safely fetches the value for global configuration 'StatusesMediaMaxFiles' field
+func GetStatusesMediaMaxFiles() int { return global.GetStatusesMediaMaxFiles() }
+
+// SetStatusesMediaMaxFiles safely sets the value for global configuration 'StatusesMediaMaxFiles' field
+func SetStatusesMediaMaxFiles(v int) { global.SetStatusesMediaMaxFiles(v) }
+
+// GetLetsEncryptEnabled safely fetches the Configuration value for state's 'LetsEncryptEnabled' field
+func (st *ConfigState) GetLetsEncryptEnabled() (v bool) {
+ st.mutex.Lock()
+ v = st.config.LetsEncryptEnabled
+ st.mutex.Unlock()
+ return
+}
+
+// SetLetsEncryptEnabled safely sets the Configuration value for state's 'LetsEncryptEnabled' field
+func (st *ConfigState) SetLetsEncryptEnabled(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LetsEncryptEnabled = v
+ st.reloadToViper()
+}
+
+// LetsEncryptEnabledFlag returns the flag name for the 'LetsEncryptEnabled' field
+func LetsEncryptEnabledFlag() string { return "letsencrypt-enabled" }
+
+// GetLetsEncryptEnabled safely fetches the value for global configuration 'LetsEncryptEnabled' field
+func GetLetsEncryptEnabled() bool { return global.GetLetsEncryptEnabled() }
+
+// SetLetsEncryptEnabled safely sets the value for global configuration 'LetsEncryptEnabled' field
+func SetLetsEncryptEnabled(v bool) { global.SetLetsEncryptEnabled(v) }
+
+// GetLetsEncryptPort safely fetches the Configuration value for state's 'LetsEncryptPort' field
+func (st *ConfigState) GetLetsEncryptPort() (v int) {
+ st.mutex.Lock()
+ v = st.config.LetsEncryptPort
+ st.mutex.Unlock()
+ return
+}
+
+// SetLetsEncryptPort safely sets the Configuration value for state's 'LetsEncryptPort' field
+func (st *ConfigState) SetLetsEncryptPort(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LetsEncryptPort = v
+ st.reloadToViper()
+}
+
+// LetsEncryptPortFlag returns the flag name for the 'LetsEncryptPort' field
+func LetsEncryptPortFlag() string { return "letsencrypt-port" }
+
+// GetLetsEncryptPort safely fetches the value for global configuration 'LetsEncryptPort' field
+func GetLetsEncryptPort() int { return global.GetLetsEncryptPort() }
+
+// SetLetsEncryptPort safely sets the value for global configuration 'LetsEncryptPort' field
+func SetLetsEncryptPort(v int) { global.SetLetsEncryptPort(v) }
+
+// GetLetsEncryptCertDir safely fetches the Configuration value for state's 'LetsEncryptCertDir' field
+func (st *ConfigState) GetLetsEncryptCertDir() (v string) {
+ st.mutex.Lock()
+ v = st.config.LetsEncryptCertDir
+ st.mutex.Unlock()
+ return
+}
+
+// SetLetsEncryptCertDir safely sets the Configuration value for state's 'LetsEncryptCertDir' field
+func (st *ConfigState) SetLetsEncryptCertDir(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LetsEncryptCertDir = v
+ st.reloadToViper()
+}
+
+// LetsEncryptCertDirFlag returns the flag name for the 'LetsEncryptCertDir' field
+func LetsEncryptCertDirFlag() string { return "letsencrypt-cert-dir" }
+
+// GetLetsEncryptCertDir safely fetches the value for global configuration 'LetsEncryptCertDir' field
+func GetLetsEncryptCertDir() string { return global.GetLetsEncryptCertDir() }
+
+// SetLetsEncryptCertDir safely sets the value for global configuration 'LetsEncryptCertDir' field
+func SetLetsEncryptCertDir(v string) { global.SetLetsEncryptCertDir(v) }
+
+// GetLetsEncryptEmailAddress safely fetches the Configuration value for state's 'LetsEncryptEmailAddress' field
+func (st *ConfigState) GetLetsEncryptEmailAddress() (v string) {
+ st.mutex.Lock()
+ v = st.config.LetsEncryptEmailAddress
+ st.mutex.Unlock()
+ return
+}
+
+// SetLetsEncryptEmailAddress safely sets the Configuration value for state's 'LetsEncryptEmailAddress' field
+func (st *ConfigState) SetLetsEncryptEmailAddress(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LetsEncryptEmailAddress = v
+ st.reloadToViper()
+}
+
+// LetsEncryptEmailAddressFlag returns the flag name for the 'LetsEncryptEmailAddress' field
+func LetsEncryptEmailAddressFlag() string { return "letsencrypt-email-address" }
+
+// GetLetsEncryptEmailAddress safely fetches the value for global configuration 'LetsEncryptEmailAddress' field
+func GetLetsEncryptEmailAddress() string { return global.GetLetsEncryptEmailAddress() }
+
+// SetLetsEncryptEmailAddress safely sets the value for global configuration 'LetsEncryptEmailAddress' field
+func SetLetsEncryptEmailAddress(v string) { global.SetLetsEncryptEmailAddress(v) }
+
+// GetOIDCEnabled safely fetches the Configuration value for state's 'OIDCEnabled' field
+func (st *ConfigState) GetOIDCEnabled() (v bool) {
+ st.mutex.Lock()
+ v = st.config.OIDCEnabled
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCEnabled safely sets the Configuration value for state's 'OIDCEnabled' field
+func (st *ConfigState) SetOIDCEnabled(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCEnabled = v
+ st.reloadToViper()
+}
+
+// OIDCEnabledFlag returns the flag name for the 'OIDCEnabled' field
+func OIDCEnabledFlag() string { return "oidc-enabled" }
+
+// GetOIDCEnabled safely fetches the value for global configuration 'OIDCEnabled' field
+func GetOIDCEnabled() bool { return global.GetOIDCEnabled() }
+
+// SetOIDCEnabled safely sets the value for global configuration 'OIDCEnabled' field
+func SetOIDCEnabled(v bool) { global.SetOIDCEnabled(v) }
+
+// GetOIDCIdpName safely fetches the Configuration value for state's 'OIDCIdpName' field
+func (st *ConfigState) GetOIDCIdpName() (v string) {
+ st.mutex.Lock()
+ v = st.config.OIDCIdpName
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCIdpName safely sets the Configuration value for state's 'OIDCIdpName' field
+func (st *ConfigState) SetOIDCIdpName(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCIdpName = v
+ st.reloadToViper()
+}
+
+// OIDCIdpNameFlag returns the flag name for the 'OIDCIdpName' field
+func OIDCIdpNameFlag() string { return "oidc-idp-name" }
+
+// GetOIDCIdpName safely fetches the value for global configuration 'OIDCIdpName' field
+func GetOIDCIdpName() string { return global.GetOIDCIdpName() }
+
+// SetOIDCIdpName safely sets the value for global configuration 'OIDCIdpName' field
+func SetOIDCIdpName(v string) { global.SetOIDCIdpName(v) }
+
+// GetOIDCSkipVerification safely fetches the Configuration value for state's 'OIDCSkipVerification' field
+func (st *ConfigState) GetOIDCSkipVerification() (v bool) {
+ st.mutex.Lock()
+ v = st.config.OIDCSkipVerification
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCSkipVerification safely sets the Configuration value for state's 'OIDCSkipVerification' field
+func (st *ConfigState) SetOIDCSkipVerification(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCSkipVerification = v
+ st.reloadToViper()
+}
+
+// OIDCSkipVerificationFlag returns the flag name for the 'OIDCSkipVerification' field
+func OIDCSkipVerificationFlag() string { return "oidc-skip-verification" }
+
+// GetOIDCSkipVerification safely fetches the value for global configuration 'OIDCSkipVerification' field
+func GetOIDCSkipVerification() bool { return global.GetOIDCSkipVerification() }
+
+// SetOIDCSkipVerification safely sets the value for global configuration 'OIDCSkipVerification' field
+func SetOIDCSkipVerification(v bool) { global.SetOIDCSkipVerification(v) }
+
+// GetOIDCIssuer safely fetches the Configuration value for state's 'OIDCIssuer' field
+func (st *ConfigState) GetOIDCIssuer() (v string) {
+ st.mutex.Lock()
+ v = st.config.OIDCIssuer
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCIssuer safely sets the Configuration value for state's 'OIDCIssuer' field
+func (st *ConfigState) SetOIDCIssuer(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCIssuer = v
+ st.reloadToViper()
+}
+
+// OIDCIssuerFlag returns the flag name for the 'OIDCIssuer' field
+func OIDCIssuerFlag() string { return "oidc-issuer" }
+
+// GetOIDCIssuer safely fetches the value for global configuration 'OIDCIssuer' field
+func GetOIDCIssuer() string { return global.GetOIDCIssuer() }
+
+// SetOIDCIssuer safely sets the value for global configuration 'OIDCIssuer' field
+func SetOIDCIssuer(v string) { global.SetOIDCIssuer(v) }
+
+// GetOIDCClientID safely fetches the Configuration value for state's 'OIDCClientID' field
+func (st *ConfigState) GetOIDCClientID() (v string) {
+ st.mutex.Lock()
+ v = st.config.OIDCClientID
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCClientID safely sets the Configuration value for state's 'OIDCClientID' field
+func (st *ConfigState) SetOIDCClientID(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCClientID = v
+ st.reloadToViper()
+}
+
+// OIDCClientIDFlag returns the flag name for the 'OIDCClientID' field
+func OIDCClientIDFlag() string { return "oidc-client-id" }
+
+// GetOIDCClientID safely fetches the value for global configuration 'OIDCClientID' field
+func GetOIDCClientID() string { return global.GetOIDCClientID() }
+
+// SetOIDCClientID safely sets the value for global configuration 'OIDCClientID' field
+func SetOIDCClientID(v string) { global.SetOIDCClientID(v) }
+
+// GetOIDCClientSecret safely fetches the Configuration value for state's 'OIDCClientSecret' field
+func (st *ConfigState) GetOIDCClientSecret() (v string) {
+ st.mutex.Lock()
+ v = st.config.OIDCClientSecret
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCClientSecret safely sets the Configuration value for state's 'OIDCClientSecret' field
+func (st *ConfigState) SetOIDCClientSecret(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCClientSecret = v
+ st.reloadToViper()
+}
+
+// OIDCClientSecretFlag returns the flag name for the 'OIDCClientSecret' field
+func OIDCClientSecretFlag() string { return "oidc-client-secret" }
+
+// GetOIDCClientSecret safely fetches the value for global configuration 'OIDCClientSecret' field
+func GetOIDCClientSecret() string { return global.GetOIDCClientSecret() }
+
+// SetOIDCClientSecret safely sets the value for global configuration 'OIDCClientSecret' field
+func SetOIDCClientSecret(v string) { global.SetOIDCClientSecret(v) }
+
+// GetOIDCScopes safely fetches the Configuration value for state's 'OIDCScopes' field
+func (st *ConfigState) GetOIDCScopes() (v []string) {
+ st.mutex.Lock()
+ v = st.config.OIDCScopes
+ st.mutex.Unlock()
+ return
+}
+
+// SetOIDCScopes safely sets the Configuration value for state's 'OIDCScopes' field
+func (st *ConfigState) SetOIDCScopes(v []string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.OIDCScopes = v
+ st.reloadToViper()
+}
+
+// OIDCScopesFlag returns the flag name for the 'OIDCScopes' field
+func OIDCScopesFlag() string { return "oidc-scopes" }
+
+// GetOIDCScopes safely fetches the value for global configuration 'OIDCScopes' field
+func GetOIDCScopes() []string { return global.GetOIDCScopes() }
+
+// SetOIDCScopes safely sets the value for global configuration 'OIDCScopes' field
+func SetOIDCScopes(v []string) { global.SetOIDCScopes(v) }
+
+// GetSMTPHost safely fetches the Configuration value for state's 'SMTPHost' field
+func (st *ConfigState) GetSMTPHost() (v string) {
+ st.mutex.Lock()
+ v = st.config.SMTPHost
+ st.mutex.Unlock()
+ return
+}
+
+// SetSMTPHost safely sets the Configuration value for state's 'SMTPHost' field
+func (st *ConfigState) SetSMTPHost(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SMTPHost = v
+ st.reloadToViper()
+}
+
+// SMTPHostFlag returns the flag name for the 'SMTPHost' field
+func SMTPHostFlag() string { return "smtp-host" }
+
+// GetSMTPHost safely fetches the value for global configuration 'SMTPHost' field
+func GetSMTPHost() string { return global.GetSMTPHost() }
+
+// SetSMTPHost safely sets the value for global configuration 'SMTPHost' field
+func SetSMTPHost(v string) { global.SetSMTPHost(v) }
+
+// GetSMTPPort safely fetches the Configuration value for state's 'SMTPPort' field
+func (st *ConfigState) GetSMTPPort() (v int) {
+ st.mutex.Lock()
+ v = st.config.SMTPPort
+ st.mutex.Unlock()
+ return
+}
+
+// SetSMTPPort safely sets the Configuration value for state's 'SMTPPort' field
+func (st *ConfigState) SetSMTPPort(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SMTPPort = v
+ st.reloadToViper()
+}
+
+// SMTPPortFlag returns the flag name for the 'SMTPPort' field
+func SMTPPortFlag() string { return "smtp-port" }
+
+// GetSMTPPort safely fetches the value for global configuration 'SMTPPort' field
+func GetSMTPPort() int { return global.GetSMTPPort() }
+
+// SetSMTPPort safely sets the value for global configuration 'SMTPPort' field
+func SetSMTPPort(v int) { global.SetSMTPPort(v) }
+
+// GetSMTPUsername safely fetches the Configuration value for state's 'SMTPUsername' field
+func (st *ConfigState) GetSMTPUsername() (v string) {
+ st.mutex.Lock()
+ v = st.config.SMTPUsername
+ st.mutex.Unlock()
+ return
+}
+
+// SetSMTPUsername safely sets the Configuration value for state's 'SMTPUsername' field
+func (st *ConfigState) SetSMTPUsername(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SMTPUsername = v
+ st.reloadToViper()
+}
+
+// SMTPUsernameFlag returns the flag name for the 'SMTPUsername' field
+func SMTPUsernameFlag() string { return "smtp-username" }
+
+// GetSMTPUsername safely fetches the value for global configuration 'SMTPUsername' field
+func GetSMTPUsername() string { return global.GetSMTPUsername() }
+
+// SetSMTPUsername safely sets the value for global configuration 'SMTPUsername' field
+func SetSMTPUsername(v string) { global.SetSMTPUsername(v) }
+
+// GetSMTPPassword safely fetches the Configuration value for state's 'SMTPPassword' field
+func (st *ConfigState) GetSMTPPassword() (v string) {
+ st.mutex.Lock()
+ v = st.config.SMTPPassword
+ st.mutex.Unlock()
+ return
+}
+
+// SetSMTPPassword safely sets the Configuration value for state's 'SMTPPassword' field
+func (st *ConfigState) SetSMTPPassword(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SMTPPassword = v
+ st.reloadToViper()
+}
+
+// SMTPPasswordFlag returns the flag name for the 'SMTPPassword' field
+func SMTPPasswordFlag() string { return "smtp-password" }
+
+// GetSMTPPassword safely fetches the value for global configuration 'SMTPPassword' field
+func GetSMTPPassword() string { return global.GetSMTPPassword() }
+
+// SetSMTPPassword safely sets the value for global configuration 'SMTPPassword' field
+func SetSMTPPassword(v string) { global.SetSMTPPassword(v) }
+
+// GetSMTPFrom safely fetches the Configuration value for state's 'SMTPFrom' field
+func (st *ConfigState) GetSMTPFrom() (v string) {
+ st.mutex.Lock()
+ v = st.config.SMTPFrom
+ st.mutex.Unlock()
+ return
+}
+
+// SetSMTPFrom safely sets the Configuration value for state's 'SMTPFrom' field
+func (st *ConfigState) SetSMTPFrom(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SMTPFrom = v
+ st.reloadToViper()
+}
+
+// SMTPFromFlag returns the flag name for the 'SMTPFrom' field
+func SMTPFromFlag() string { return "smtp-from" }
+
+// GetSMTPFrom safely fetches the value for global configuration 'SMTPFrom' field
+func GetSMTPFrom() string { return global.GetSMTPFrom() }
+
+// SetSMTPFrom safely sets the value for global configuration 'SMTPFrom' field
+func SetSMTPFrom(v string) { global.SetSMTPFrom(v) }
+
+// GetSyslogEnabled safely fetches the Configuration value for state's 'SyslogEnabled' field
+func (st *ConfigState) GetSyslogEnabled() (v bool) {
+ st.mutex.Lock()
+ v = st.config.SyslogEnabled
+ st.mutex.Unlock()
+ return
+}
+
+// SetSyslogEnabled safely sets the Configuration value for state's 'SyslogEnabled' field
+func (st *ConfigState) SetSyslogEnabled(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SyslogEnabled = v
+ st.reloadToViper()
+}
+
+// SyslogEnabledFlag returns the flag name for the 'SyslogEnabled' field
+func SyslogEnabledFlag() string { return "syslog-enabled" }
+
+// GetSyslogEnabled safely fetches the value for global configuration 'SyslogEnabled' field
+func GetSyslogEnabled() bool { return global.GetSyslogEnabled() }
+
+// SetSyslogEnabled safely sets the value for global configuration 'SyslogEnabled' field
+func SetSyslogEnabled(v bool) { global.SetSyslogEnabled(v) }
+
+// GetSyslogProtocol safely fetches the Configuration value for state's 'SyslogProtocol' field
+func (st *ConfigState) GetSyslogProtocol() (v string) {
+ st.mutex.Lock()
+ v = st.config.SyslogProtocol
+ st.mutex.Unlock()
+ return
+}
+
+// SetSyslogProtocol safely sets the Configuration value for state's 'SyslogProtocol' field
+func (st *ConfigState) SetSyslogProtocol(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SyslogProtocol = v
+ st.reloadToViper()
+}
+
+// SyslogProtocolFlag returns the flag name for the 'SyslogProtocol' field
+func SyslogProtocolFlag() string { return "syslog-protocol" }
+
+// GetSyslogProtocol safely fetches the value for global configuration 'SyslogProtocol' field
+func GetSyslogProtocol() string { return global.GetSyslogProtocol() }
+
+// SetSyslogProtocol safely sets the value for global configuration 'SyslogProtocol' field
+func SetSyslogProtocol(v string) { global.SetSyslogProtocol(v) }
+
+// GetSyslogAddress safely fetches the Configuration value for state's 'SyslogAddress' field
+func (st *ConfigState) GetSyslogAddress() (v string) {
+ st.mutex.Lock()
+ v = st.config.SyslogAddress
+ st.mutex.Unlock()
+ return
+}
+
+// SetSyslogAddress safely sets the Configuration value for state's 'SyslogAddress' field
+func (st *ConfigState) SetSyslogAddress(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.SyslogAddress = v
+ st.reloadToViper()
+}
+
+// SyslogAddressFlag returns the flag name for the 'SyslogAddress' field
+func SyslogAddressFlag() string { return "syslog-address" }
+
+// GetSyslogAddress safely fetches the value for global configuration 'SyslogAddress' field
+func GetSyslogAddress() string { return global.GetSyslogAddress() }
+
+// SetSyslogAddress safely sets the value for global configuration 'SyslogAddress' field
+func SetSyslogAddress(v string) { global.SetSyslogAddress(v) }
+
+// GetAdminAccountUsername safely fetches the Configuration value for state's 'AdminAccountUsername' field
+func (st *ConfigState) GetAdminAccountUsername() (v string) {
+ st.mutex.Lock()
+ v = st.config.AdminAccountUsername
+ st.mutex.Unlock()
+ return
+}
+
+// SetAdminAccountUsername safely sets the Configuration value for state's 'AdminAccountUsername' field
+func (st *ConfigState) SetAdminAccountUsername(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AdminAccountUsername = v
+ st.reloadToViper()
+}
+
+// AdminAccountUsernameFlag returns the flag name for the 'AdminAccountUsername' field
+func AdminAccountUsernameFlag() string { return "username" }
+
+// GetAdminAccountUsername safely fetches the value for global configuration 'AdminAccountUsername' field
+func GetAdminAccountUsername() string { return global.GetAdminAccountUsername() }
+
+// SetAdminAccountUsername safely sets the value for global configuration 'AdminAccountUsername' field
+func SetAdminAccountUsername(v string) { global.SetAdminAccountUsername(v) }
+
+// GetAdminAccountEmail safely fetches the Configuration value for state's 'AdminAccountEmail' field
+func (st *ConfigState) GetAdminAccountEmail() (v string) {
+ st.mutex.Lock()
+ v = st.config.AdminAccountEmail
+ st.mutex.Unlock()
+ return
+}
+
+// SetAdminAccountEmail safely sets the Configuration value for state's 'AdminAccountEmail' field
+func (st *ConfigState) SetAdminAccountEmail(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AdminAccountEmail = v
+ st.reloadToViper()
+}
+
+// AdminAccountEmailFlag returns the flag name for the 'AdminAccountEmail' field
+func AdminAccountEmailFlag() string { return "email" }
+
+// GetAdminAccountEmail safely fetches the value for global configuration 'AdminAccountEmail' field
+func GetAdminAccountEmail() string { return global.GetAdminAccountEmail() }
+
+// SetAdminAccountEmail safely sets the value for global configuration 'AdminAccountEmail' field
+func SetAdminAccountEmail(v string) { global.SetAdminAccountEmail(v) }
+
+// GetAdminAccountPassword safely fetches the Configuration value for state's 'AdminAccountPassword' field
+func (st *ConfigState) GetAdminAccountPassword() (v string) {
+ st.mutex.Lock()
+ v = st.config.AdminAccountPassword
+ st.mutex.Unlock()
+ return
+}
+
+// SetAdminAccountPassword safely sets the Configuration value for state's 'AdminAccountPassword' field
+func (st *ConfigState) SetAdminAccountPassword(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AdminAccountPassword = v
+ st.reloadToViper()
+}
+
+// AdminAccountPasswordFlag returns the flag name for the 'AdminAccountPassword' field
+func AdminAccountPasswordFlag() string { return "password" }
+
+// GetAdminAccountPassword safely fetches the value for global configuration 'AdminAccountPassword' field
+func GetAdminAccountPassword() string { return global.GetAdminAccountPassword() }
+
+// SetAdminAccountPassword safely sets the value for global configuration 'AdminAccountPassword' field
+func SetAdminAccountPassword(v string) { global.SetAdminAccountPassword(v) }
+
+// GetAdminTransPath safely fetches the Configuration value for state's 'AdminTransPath' field
+func (st *ConfigState) GetAdminTransPath() (v string) {
+ st.mutex.Lock()
+ v = st.config.AdminTransPath
+ st.mutex.Unlock()
+ return
+}
+
+// SetAdminTransPath safely sets the Configuration value for state's 'AdminTransPath' field
+func (st *ConfigState) SetAdminTransPath(v string) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AdminTransPath = v
+ st.reloadToViper()
+}
+
+// AdminTransPathFlag returns the flag name for the 'AdminTransPath' field
+func AdminTransPathFlag() string { return "path" }
+
+// GetAdminTransPath safely fetches the value for global configuration 'AdminTransPath' field
+func GetAdminTransPath() string { return global.GetAdminTransPath() }
+
+// SetAdminTransPath safely sets the value for global configuration 'AdminTransPath' field
+func SetAdminTransPath(v string) { global.SetAdminTransPath(v) }
diff --git a/internal/config/keys.go b/internal/config/keys.go
deleted file mode 100644
index 50a9c2fa7..000000000
--- a/internal/config/keys.go
+++ /dev/null
@@ -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 .
-*/
-
-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",
-}
diff --git a/internal/config/state.go b/internal/config/state.go
new file mode 100644
index 000000000..70972a835
--- /dev/null
+++ b/internal/config/state.go
@@ -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 .
+*/
+
+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)
+ }
+}
diff --git a/internal/config/validate.go b/internal/config/validate.go
index d229e5418..b9dab0f56 100644
--- a/internal/config/validate.go
+++ b/internal/config/validate.go
@@ -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 {
diff --git a/internal/config/validate_test.go b/internal/config/validate_test.go
index 6d8294205..066f1807b 100644
--- a/internal/config/validate_test.go
+++ b/internal/config/validate_test.go
@@ -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")
diff --git a/internal/config/values.go b/internal/config/values.go
deleted file mode 100644
index 1c71e4e30..000000000
--- a/internal/config/values.go
+++ /dev/null
@@ -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 .
-*/
-
-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
-}
diff --git a/internal/config/viper.go b/internal/config/viper.go
deleted file mode 100644
index 8ed241e1b..000000000
--- a/internal/config/viper.go
+++ /dev/null
@@ -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 .
-*/
-
-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
-}
diff --git a/internal/db/bundb/account.go b/internal/db/bundb/account.go
index 59292055e..6061676c5 100644
--- a/internal/db/bundb/account.go
+++ b/internal/db/bundb/account.go
@@ -25,7 +25,6 @@ import (
"strings"
"time"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/cache"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -133,9 +132,8 @@ func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gts
Where("account.username = ?", domain).
Where("account.domain = ?", domain)
} else {
- host := viper.GetString(config.Keys.Host)
q = q.
- Where("account.username = ?", host).
+ Where("account.username = ?", config.GetHost()).
WhereGroup(" AND ", whereEmptyOrNull("domain"))
}
diff --git a/internal/db/bundb/admin.go b/internal/db/bundb/admin.go
index a92834f9c..8b9c7c9a3 100644
--- a/internal/db/bundb/admin.go
+++ b/internal/db/bundb/admin.go
@@ -30,7 +30,6 @@ import (
"time"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -178,7 +177,7 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,
}
func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {
- username := viper.GetString(config.Keys.Host)
+ username := config.GetHost()
q := a.conn.
NewSelect().
@@ -237,8 +236,8 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {
}
func (a *adminDB) CreateInstanceInstance(ctx context.Context) db.Error {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
// check if instance entry already exists
q := a.conn.
diff --git a/internal/db/bundb/bundb.go b/internal/db/bundb/bundb.go
index f458132a1..fef62a55f 100644
--- a/internal/db/bundb/bundb.go
+++ b/internal/db/bundb/bundb.go
@@ -35,7 +35,6 @@ import (
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/stdlib"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/cache"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -120,7 +119,7 @@ func doMigration(ctx context.Context, db *bun.DB) error {
func NewBunDBService(ctx context.Context) (db.DB, error) {
var conn *DBConn
var err error
- dbType := strings.ToLower(viper.GetString(config.Keys.DbType))
+ dbType := strings.ToLower(config.GetDbType())
switch dbType {
case dbTypePostgres:
@@ -139,7 +138,7 @@ func NewBunDBService(ctx context.Context) (db.DB, error) {
// add a hook to log queries and the time they take
// only do this for logging where performance isn't 1st concern
- if logrus.GetLevel() >= logrus.DebugLevel && viper.GetBool(config.Keys.LogDbQueries) {
+ if logrus.GetLevel() >= logrus.DebugLevel && config.GetLogDbQueries() {
conn.DB.AddQueryHook(newDebugQueryHook())
}
@@ -209,9 +208,9 @@ func NewBunDBService(ctx context.Context) (db.DB, error) {
func sqliteConn(ctx context.Context) (*DBConn, error) {
// validate db address has actually been set
- dbAddress := viper.GetString(config.Keys.DbAddress)
+ dbAddress := config.GetDbAddress()
if dbAddress == "" {
- return nil, fmt.Errorf("'%s' was not set when attempting to start sqlite", config.Keys.DbAddress)
+ return nil, fmt.Errorf("'%s' was not set when attempting to start sqlite", config.DbAddressFlag())
}
// Drop anything fancy from DB address
@@ -282,27 +281,21 @@ func pgConn(ctx context.Context) (*DBConn, error) {
// deriveBunDBPGOptions takes an application config and returns either a ready-to-use set of options
// with sensible defaults, or an error if it's not satisfied by the provided config.
func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
- keys := config.Keys
-
- if strings.ToUpper(viper.GetString(keys.DbType)) != db.DBTypePostgres {
- return nil, fmt.Errorf("expected db type of %s but got %s", db.DBTypePostgres, viper.GetString(keys.DbType))
+ if strings.ToUpper(config.GetDbType()) != db.DBTypePostgres {
+ return nil, fmt.Errorf("expected db type of %s but got %s", db.DBTypePostgres, config.DbTypeFlag())
}
// these are all optional, the db adapter figures out defaults
- port := viper.GetInt(keys.DbPort)
- address := viper.GetString(keys.DbAddress)
- username := viper.GetString(keys.DbUser)
- password := viper.GetString(keys.DbPassword)
+ address := config.GetDbAddress()
// validate database
- database := viper.GetString(keys.DbDatabase)
+ database := config.GetDbDatabase()
if database == "" {
return nil, errors.New("no database set")
}
var tlsConfig *tls.Config
- tlsMode := viper.GetString(keys.DbTLSMode)
- switch tlsMode {
+ switch config.GetDbTLSMode() {
case dbTLSModeDisable, dbTLSModeUnset:
break // nothing to do
case dbTLSModeEnable:
@@ -313,13 +306,12 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
case dbTLSModeRequire:
tlsConfig = &tls.Config{
InsecureSkipVerify: false,
- ServerName: viper.GetString(keys.DbAddress),
+ ServerName: address,
MinVersion: tls.VersionTLS12,
}
}
- caCertPath := viper.GetString(keys.DbTLSCACert)
- if tlsConfig != nil && caCertPath != "" {
+ if certPath := config.GetDbTLSCACert(); tlsConfig != nil && certPath != "" {
// load the system cert pool first -- we'll append the given CA cert to this
certPool, err := x509.SystemCertPool()
if err != nil {
@@ -327,24 +319,24 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
}
// open the file itself and make sure there's something in it
- caCertBytes, err := os.ReadFile(caCertPath)
+ caCertBytes, err := os.ReadFile(certPath)
if err != nil {
- return nil, fmt.Errorf("error opening CA certificate at %s: %s", caCertPath, err)
+ return nil, fmt.Errorf("error opening CA certificate at %s: %s", certPath, err)
}
if len(caCertBytes) == 0 {
- return nil, fmt.Errorf("ca cert at %s was empty", caCertPath)
+ return nil, fmt.Errorf("ca cert at %s was empty", certPath)
}
// make sure we have a PEM block
caPem, _ := pem.Decode(caCertBytes)
if caPem == nil {
- return nil, fmt.Errorf("could not parse cert at %s into PEM", caCertPath)
+ return nil, fmt.Errorf("could not parse cert at %s into PEM", certPath)
}
// parse the PEM block into the certificate
caCert, err := x509.ParseCertificate(caPem.Bytes)
if err != nil {
- return nil, fmt.Errorf("could not parse cert at %s into x509 certificate: %s", caCertPath, err)
+ return nil, fmt.Errorf("could not parse cert at %s into x509 certificate: %s", certPath, err)
}
// we're happy, add it to the existing pool and then use this pool in our tls config
@@ -356,21 +348,21 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
if address != "" {
cfg.Host = address
}
- if port > 0 {
+ if port := config.GetPort(); port > 0 {
cfg.Port = uint16(port)
}
- if username != "" {
- cfg.User = username
+ if u := config.GetDbUser(); u != "" {
+ cfg.User = u
}
- if password != "" {
- cfg.Password = password
+ if p := config.GetDbPassword(); p != "" {
+ cfg.Password = p
}
if tlsConfig != nil {
cfg.TLSConfig = tlsConfig
}
cfg.Database = database
cfg.PreferSimpleProtocol = true
- cfg.RuntimeParams["application_name"] = viper.GetString(keys.ApplicationName)
+ cfg.RuntimeParams["application_name"] = config.GetApplicationName()
return cfg, nil
}
@@ -387,8 +379,8 @@ func tweakConnectionValues(sqldb *sql.DB) {
*/
func (ps *bunDBService) TagStringsToTags(ctx context.Context, tags []string, originAccountID string) ([]*gtsmodel.Tag, error) {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
newTags := []*gtsmodel.Tag{}
for _, t := range tags {
diff --git a/internal/db/bundb/bundbnew_test.go b/internal/db/bundb/bundbnew_test.go
index 40a05cb50..d5e413a4f 100644
--- a/internal/db/bundb/bundbnew_test.go
+++ b/internal/db/bundb/bundbnew_test.go
@@ -22,7 +22,6 @@ import (
"context"
"testing"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
@@ -41,7 +40,7 @@ func (suite *BundbNewTestSuite) TestCreateNewDB() {
func (suite *BundbNewTestSuite) TestCreateNewSqliteDBNoAddress() {
// create a new db with no address specified
- viper.Set(config.Keys.DbAddress, "")
+ config.SetDbAddress("")
db, err := bundb.NewBunDBService(context.Background())
suite.EqualError(err, "'db-address' was not set when attempting to start sqlite")
suite.Nil(db)
diff --git a/internal/db/bundb/domain.go b/internal/db/bundb/domain.go
index 9ddd33b05..ee7fed6a9 100644
--- a/internal/db/bundb/domain.go
+++ b/internal/db/bundb/domain.go
@@ -23,7 +23,6 @@ import (
"net/url"
"strings"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@@ -35,7 +34,7 @@ type domainDB struct {
}
func (d *domainDB) IsDomainBlocked(ctx context.Context, domain string) (bool, db.Error) {
- if domain == "" || domain == viper.GetString(config.Keys.Host) {
+ if domain == "" || domain == config.GetHost() {
return false, nil
}
diff --git a/internal/db/bundb/instance.go b/internal/db/bundb/instance.go
index 24cc6f1be..d16fac90b 100644
--- a/internal/db/bundb/instance.go
+++ b/internal/db/bundb/instance.go
@@ -22,7 +22,6 @@ import (
"context"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -41,8 +40,7 @@ func (i *instanceDB) CountInstanceUsers(ctx context.Context, domain string) (int
Where("username != ?", domain).
Where("? IS NULL", bun.Ident("suspended_at"))
- host := viper.GetString(config.Keys.Host)
- if domain == host {
+ if domain == config.GetHost() {
// if the domain is *this* domain, just count where the domain field is null
q = q.WhereGroup(" AND ", whereEmptyOrNull("domain"))
} else {
@@ -61,8 +59,7 @@ func (i *instanceDB) CountInstanceStatuses(ctx context.Context, domain string) (
NewSelect().
Model(&[]*gtsmodel.Status{})
- host := viper.GetString(config.Keys.Host)
- if domain == host {
+ if domain == config.GetHost() {
// if the domain is *this* domain, just count where local is true
q = q.Where("local = ?", true)
} else {
@@ -83,8 +80,7 @@ func (i *instanceDB) CountInstanceDomains(ctx context.Context, domain string) (i
NewSelect().
Model(&[]*gtsmodel.Instance{})
- host := viper.GetString(config.Keys.Host)
- if domain == host {
+ if domain == config.GetHost() {
// if the domain is *this* domain, just count other instances it knows about
// exclude domains that are blocked
q = q.
diff --git a/internal/email/confirm.go b/internal/email/confirm.go
index 34e2fb660..b49004056 100644
--- a/internal/email/confirm.go
+++ b/internal/email/confirm.go
@@ -23,7 +23,6 @@ import (
"net/smtp"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -43,7 +42,7 @@ func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error {
if err != nil {
return err
}
- logrus.WithField("func", "SendConfirmEmail").Trace(s.hostAddress + "\n" + viper.GetString(config.Keys.SMTPUsername) + ":password" + "\n" + s.from + "\n" + toAddress + "\n\n" + string(msg) + "\n")
+ logrus.WithField("func", "SendConfirmEmail").Trace(s.hostAddress + "\n" + config.GetSMTPUsername() + ":password" + "\n" + s.from + "\n" + toAddress + "\n\n" + string(msg) + "\n")
return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)
}
diff --git a/internal/email/noopsender.go b/internal/email/noopsender.go
index 9f587f319..9aab1ca41 100644
--- a/internal/email/noopsender.go
+++ b/internal/email/noopsender.go
@@ -23,7 +23,6 @@ import (
"text/template"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -32,7 +31,7 @@ import (
//
// Passing a nil function is also acceptable, in which case the send functions will just return nil.
func NewNoopSender(sendCallback func(toAddress string, message string)) (Sender, error) {
- templateBaseDir := viper.GetString(config.Keys.WebTemplateBaseDir)
+ templateBaseDir := config.GetWebTemplateBaseDir()
t, err := loadTemplates(templateBaseDir)
if err != nil {
diff --git a/internal/email/sender.go b/internal/email/sender.go
index f44627496..18372ab47 100644
--- a/internal/email/sender.go
+++ b/internal/email/sender.go
@@ -23,7 +23,6 @@ import (
"net/smtp"
"text/template"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -38,19 +37,17 @@ type Sender interface {
// NewSender returns a new email Sender interface with the given configuration, or an error if something goes wrong.
func NewSender() (Sender, error) {
- keys := config.Keys
-
- templateBaseDir := viper.GetString(keys.WebTemplateBaseDir)
+ templateBaseDir := config.GetWebTemplateBaseDir()
t, err := loadTemplates(templateBaseDir)
if err != nil {
return nil, err
}
- username := viper.GetString(keys.SMTPUsername)
- password := viper.GetString(keys.SMTPPassword)
- host := viper.GetString(keys.SMTPHost)
- port := viper.GetInt(keys.SMTPPort)
- from := viper.GetString(keys.SMTPFrom)
+ username := config.GetSMTPUsername()
+ password := config.GetSMTPPassword()
+ host := config.GetSMTPHost()
+ port := config.GetSMTPPort()
+ from := config.GetSMTPFrom()
return &sender{
hostAddress: fmt.Sprintf("%s:%d", host, port),
diff --git a/internal/federation/authenticate.go b/internal/federation/authenticate.go
index 380fa1448..1d0a4a7ef 100644
--- a/internal/federation/authenticate.go
+++ b/internal/federation/authenticate.go
@@ -29,7 +29,6 @@ import (
"strings"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/go-fed/httpsig"
"github.com/superseriousbusiness/activity/pub"
@@ -168,8 +167,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
requestingRemoteAccount := >smodel.Account{}
requestingLocalAccount := >smodel.Account{}
requestingHost := requestingPublicKeyID.Host
- host := viper.GetString(config.Keys.Host)
- if strings.EqualFold(requestingHost, host) {
+ if host := config.GetHost(); strings.EqualFold(requestingHost, host) {
// LOCAL ACCOUNT REQUEST
// the request is coming from INSIDE THE HOUSE so skip the remote dereferencing
l.Tracef("proceeding without dereference for local public key %s", requestingPublicKeyID)
diff --git a/internal/federation/dereferencing/thread.go b/internal/federation/dereferencing/thread.go
index 4e161952d..096d0e8ae 100644
--- a/internal/federation/dereferencing/thread.go
+++ b/internal/federation/dereferencing/thread.go
@@ -24,7 +24,6 @@ import (
"net/url"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/uris"
@@ -45,8 +44,7 @@ func (d *deref) DereferenceThread(ctx context.Context, username string, statusIR
l.Debug("entering DereferenceThread")
// if it's our status we already have everything stashed so we can bail early
- host := viper.GetString(config.Keys.Host)
- if statusIRI.Host == host {
+ if statusIRI.Host == config.GetHost() {
l.Debug("iri belongs to us, bailing")
return nil
}
@@ -80,8 +78,7 @@ func (d *deref) iterateAncestors(ctx context.Context, username string, statusIRI
l.Debug("entering iterateAncestors")
// if it's our status we don't need to dereference anything so we can immediately move up the chain
- host := viper.GetString(config.Keys.Host)
- if statusIRI.Host == host {
+ if statusIRI.Host == config.GetHost() {
l.Debug("iri belongs to us, moving up to next ancestor")
// since this is our status, we know we can extract the id from the status path
@@ -132,8 +129,7 @@ func (d *deref) iterateDescendants(ctx context.Context, username string, statusI
l.Debug("entering iterateDescendants")
// if it's our status we already have descendants stashed so we can bail early
- host := viper.GetString(config.Keys.Host)
- if statusIRI.Host == host {
+ if statusIRI.Host == config.GetHost() {
l.Debug("iri belongs to us, bailing")
return nil
}
@@ -209,8 +205,7 @@ pageLoop:
continue
}
- host := viper.GetString(config.Keys.Host)
- if itemURI.Host == host {
+ if itemURI.Host == config.GetHost() {
// skip if the reply is from us -- we already have it then
continue
}
diff --git a/internal/federation/federatingdb/inbox.go b/internal/federation/federatingdb/inbox.go
index 20a9bb06c..8d8ffffed 100644
--- a/internal/federation/federatingdb/inbox.go
+++ b/internal/federation/federatingdb/inbox.go
@@ -23,7 +23,6 @@ import (
"fmt"
"net/url"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -80,7 +79,7 @@ func (f *federatingDB) SetInbox(c context.Context, inbox vocab.ActivityStreamsOr
// The library makes this call only after acquiring a lock first.
func (f *federatingDB) InboxesForIRI(c context.Context, iri *url.URL) (inboxIRIs []*url.URL, err error) {
// check if this is a followers collection iri for a local account...
- if iri.Host == viper.GetString(config.Keys.Host) && uris.IsFollowersPath(iri) {
+ if iri.Host == config.GetHost() && uris.IsFollowersPath(iri) {
localAccountUsername, err := uris.ParseFollowersPath(iri)
if err != nil {
return nil, fmt.Errorf("couldn't extract local account username from uri %s: %s", iri, err)
diff --git a/internal/federation/federatingdb/owns.go b/internal/federation/federatingdb/owns.go
index bfb656a16..aaa58348f 100644
--- a/internal/federation/federatingdb/owns.go
+++ b/internal/federation/federatingdb/owns.go
@@ -24,7 +24,6 @@ import (
"net/url"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@@ -44,8 +43,7 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
l.Debug("entering Owns")
// if the id host isn't this instance host, we don't own this IRI
- host := viper.GetString(config.Keys.Host)
- if id.Host != host {
+ if host := config.GetHost(); id.Host != host {
l.Tracef("we DO NOT own activity because the host is %s not %s", id.Host, host)
return false, nil
}
diff --git a/internal/federation/federatingdb/update.go b/internal/federation/federatingdb/update.go
index 7930cde12..525932ea8 100644
--- a/internal/federation/federatingdb/update.go
+++ b/internal/federation/federatingdb/update.go
@@ -24,7 +24,6 @@ import (
"fmt"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -125,8 +124,7 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
return fmt.Errorf("UPDATE: error converting to account: %s", err)
}
- host := viper.GetString(config.Keys.Host)
- if updatedAcct.Domain == host {
+ if updatedAcct.Domain == config.GetHost() {
// no need to update local accounts
// in fact, if we do this will break the shit out of things so do NOT
return nil
diff --git a/internal/federation/federatingdb/util.go b/internal/federation/federatingdb/util.go
index 5a3a65a0c..7f27cc759 100644
--- a/internal/federation/federatingdb/util.go
+++ b/internal/federation/federatingdb/util.go
@@ -26,7 +26,6 @@ import (
"net/url"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap"
@@ -209,9 +208,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,
return nil, err
}
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
- return url.Parse(fmt.Sprintf("%s://%s/%s", protocol, host, newID))
+ return url.Parse(fmt.Sprintf("%s://%s/%s", config.GetProtocol(), config.GetHost(), newID))
}
// ActorForOutbox fetches the actor's IRI for the given outbox IRI.
diff --git a/internal/log/log.go b/internal/log/log.go
index f5ce7ec24..7ffa31c99 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -26,7 +26,6 @@ import (
"github.com/sirupsen/logrus"
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -48,12 +47,9 @@ func Initialize() error {
FullTimestamp: true,
})
- keys := config.Keys
-
// check if a desired log level has been set
- logLevel := viper.GetString(keys.LogLevel)
- if logLevel != "" {
- level, err := logrus.ParseLevel(logLevel)
+ if lvl := config.GetLogLevel(); lvl != "" {
+ level, err := logrus.ParseLevel(lvl)
if err != nil {
return err
}
@@ -65,9 +61,9 @@ func Initialize() error {
}
// check if syslog has been enabled, and configure it if so
- if syslogEnabled := viper.GetBool(keys.SyslogEnabled); syslogEnabled {
- protocol := viper.GetString(keys.SyslogProtocol)
- address := viper.GetString(keys.SyslogAddress)
+ if config.GetSyslogEnabled() {
+ protocol := config.GetSyslogProtocol()
+ address := config.GetSyslogAddress()
hook, err := lSyslog.NewSyslogHook(protocol, address, syslog.LOG_INFO, "")
if err != nil {
diff --git a/internal/log/syslog_test.go b/internal/log/syslog_test.go
index 6507afa52..d58dfdcba 100644
--- a/internal/log/syslog_test.go
+++ b/internal/log/syslog_test.go
@@ -26,7 +26,6 @@ import (
"github.com/google/uuid"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/testrig"
@@ -45,9 +44,10 @@ type SyslogTestSuite struct {
func (suite *SyslogTestSuite) SetupTest() {
testrig.InitTestConfig()
- viper.Set(config.Keys.SyslogEnabled, true)
- viper.Set(config.Keys.SyslogProtocol, "udp")
- viper.Set(config.Keys.SyslogAddress, "127.0.0.1:42069")
+ config.SetSyslogEnabled(true)
+ config.SetSyslogProtocol("udp")
+ config.SetSyslogAddress("127.0.0.1:42069")
+
server, channel, err := testrig.InitTestSyslog()
if err != nil {
panic(err)
@@ -93,9 +93,10 @@ func (suite *SyslogTestSuite) TestSyslogLongMessageUnixgram() {
syslogServer := server
syslogChannel := channel
- viper.Set(config.Keys.SyslogEnabled, true)
- viper.Set(config.Keys.SyslogProtocol, "unixgram")
- viper.Set(config.Keys.SyslogAddress, socketPath)
+ config.SetSyslogEnabled(true)
+ config.SetSyslogProtocol("unixgram")
+ config.SetSyslogAddress(socketPath)
+
testrig.InitTestLog()
logrus.Warn(longMessage)
diff --git a/internal/media/manager.go b/internal/media/manager.go
index 60290e4ff..663f74123 100644
--- a/internal/media/manager.go
+++ b/internal/media/manager.go
@@ -26,7 +26,6 @@ import (
"codeberg.org/gruf/go-store/kv"
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -212,7 +211,7 @@ func scheduleCleanupJobs(m *manager) error {
}
// start remote cache cleanup cronjob if configured
- if mediaRemoteCacheDays := viper.GetInt(config.Keys.MediaRemoteCacheDays); mediaRemoteCacheDays > 0 {
+ if mediaRemoteCacheDays := config.GetMediaRemoteCacheDays(); mediaRemoteCacheDays > 0 {
if _, err := c.AddFunc("@midnight", func() {
begin := time.Now()
pruned, err := m.PruneAllRemote(pruneCtx, mediaRemoteCacheDays)
diff --git a/internal/oidc/idp.go b/internal/oidc/idp.go
index b3b204c86..7ce535644 100644
--- a/internal/oidc/idp.go
+++ b/internal/oidc/idp.go
@@ -23,7 +23,6 @@ import (
"fmt"
"github.com/coreos/go-oidc/v3/oidc"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"golang.org/x/oauth2"
)
@@ -56,36 +55,33 @@ type idp struct {
// is set to false, then nil, nil will be returned. If OIDCConfig.Enabled is true,
// then the other OIDC config fields must also be set.
func NewIDP(ctx context.Context) (IDP, error) {
- keys := config.Keys
-
- oidcEnabled := viper.GetBool(keys.OIDCEnabled)
- if !oidcEnabled {
+ if !config.GetOIDCEnabled() {
// oidc isn't enabled so we don't need to do anything
return nil, nil
}
// validate config fields
- idpName := viper.GetString(keys.OIDCIdpName)
+ idpName := config.GetOIDCIdpName()
if idpName == "" {
return nil, fmt.Errorf("not set: IDPName")
}
- issuer := viper.GetString(keys.OIDCIssuer)
+ issuer := config.GetOIDCIssuer()
if issuer == "" {
return nil, fmt.Errorf("not set: Issuer")
}
- clientID := viper.GetString(keys.OIDCClientID)
+ clientID := config.GetOIDCClientID()
if clientID == "" {
return nil, fmt.Errorf("not set: ClientID")
}
- clientSecret := viper.GetString(keys.OIDCClientSecret)
+ clientSecret := config.GetOIDCClientSecret()
if clientSecret == "" {
return nil, fmt.Errorf("not set: ClientSecret")
}
- scopes := viper.GetStringSlice(keys.OIDCScopes)
+ scopes := config.GetOIDCScopes()
if len(scopes) == 0 {
return nil, fmt.Errorf("not set: Scopes")
}
@@ -95,8 +91,8 @@ func NewIDP(ctx context.Context) (IDP, error) {
return nil, err
}
- protocol := viper.GetString(keys.Protocol)
- host := viper.GetString(keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
oauth2Config := oauth2.Config{
// client_id and client_secret of the client.
@@ -120,8 +116,7 @@ func NewIDP(ctx context.Context) (IDP, error) {
ClientID: clientID,
}
- skipVerification := viper.GetBool(keys.OIDCSkipVerification)
- if skipVerification {
+ if config.GetOIDCSkipVerification() {
oidcConf.SkipClientIDCheck = true
oidcConf.SkipExpiryCheck = true
oidcConf.SkipIssuerCheck = true
diff --git a/internal/processing/account/create.go b/internal/processing/account/create.go
index 61c4f95ef..72626220b 100644
--- a/internal/processing/account/create.go
+++ b/internal/processing/account/create.go
@@ -23,7 +23,6 @@ import (
"fmt"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/ap"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
@@ -53,9 +52,8 @@ func (p *processor) Create(ctx context.Context, applicationToken oauth2.TokenInf
return nil, fmt.Errorf("username %s in use", form.Username)
}
- keys := config.Keys
- reasonRequired := viper.GetBool(keys.AccountsReasonRequired)
- approvalRequired := viper.GetBool(keys.AccountsApprovalRequired)
+ reasonRequired := config.GetAccountsReasonRequired()
+ approvalRequired := config.GetAccountsApprovalRequired()
// don't store a reason if we don't require one
reason := form.Reason
diff --git a/internal/processing/account/update.go b/internal/processing/account/update.go
index 5fae6e73b..42da40ffe 100644
--- a/internal/processing/account/update.go
+++ b/internal/processing/account/update.go
@@ -25,7 +25,6 @@ import (
"mime/multipart"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/ap"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
@@ -142,7 +141,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
// parsing and checking the image, and doing the necessary updates in the database for this to become
// the account's new avatar image.
func (p *processor) UpdateAvatar(ctx context.Context, avatar *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) {
- maxImageSize := viper.GetInt(config.Keys.MediaImageMaxSize)
+ maxImageSize := config.GetMediaImageMaxSize()
if int(avatar.Size) > maxImageSize {
return nil, fmt.Errorf("UpdateAvatar: avatar with size %d exceeded max image size of %d bytes", avatar.Size, maxImageSize)
}
@@ -169,7 +168,7 @@ func (p *processor) UpdateAvatar(ctx context.Context, avatar *multipart.FileHead
// parsing and checking the image, and doing the necessary updates in the database for this to become
// the account's new header image.
func (p *processor) UpdateHeader(ctx context.Context, header *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) {
- maxImageSize := viper.GetInt(config.Keys.MediaImageMaxSize)
+ maxImageSize := config.GetMediaImageMaxSize()
if int(header.Size) > maxImageSize {
return nil, fmt.Errorf("UpdateHeader: header with size %d exceeded max image size of %d bytes", header.Size, maxImageSize)
}
diff --git a/internal/processing/blocks.go b/internal/processing/blocks.go
index 2700d4d3b..6a4c949a4 100644
--- a/internal/processing/blocks.go
+++ b/internal/processing/blocks.go
@@ -23,7 +23,6 @@ import (
"fmt"
"net/url"
- "github.com/spf13/viper"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -64,8 +63,8 @@ func (p *processor) packageBlocksResponse(accounts []*apimodel.Account, path str
// prepare the next and previous links
if len(accounts) != 0 {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
nextLink := &url.URL{
Scheme: protocol,
diff --git a/internal/processing/federation/getnodeinfo.go b/internal/processing/federation/getnodeinfo.go
index 46792d22a..c4aebe57d 100644
--- a/internal/processing/federation/getnodeinfo.go
+++ b/internal/processing/federation/getnodeinfo.go
@@ -23,7 +23,6 @@ import (
"fmt"
"net/http"
- "github.com/spf13/viper"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -40,8 +39,8 @@ var (
)
func (p *processor) GetNodeInfoRel(ctx context.Context, request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode) {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return &apimodel.WellKnownResponse{
Links: []apimodel.Link{
@@ -54,8 +53,8 @@ func (p *processor) GetNodeInfoRel(ctx context.Context, request *http.Request) (
}
func (p *processor) GetNodeInfo(ctx context.Context, request *http.Request) (*apimodel.Nodeinfo, gtserror.WithCode) {
- openRegistration := viper.GetBool(config.Keys.AccountsRegistrationOpen)
- softwareVersion := viper.GetString(config.Keys.SoftwareVersion)
+ openRegistration := config.GetAccountsRegistrationOpen()
+ softwareVersion := config.GetSoftwareVersion()
return &apimodel.Nodeinfo{
Version: nodeInfoVersion,
diff --git a/internal/processing/federation/getwebfinger.go b/internal/processing/federation/getwebfinger.go
index cbc4a7ebc..7158680d7 100644
--- a/internal/processing/federation/getwebfinger.go
+++ b/internal/processing/federation/getwebfinger.go
@@ -22,7 +22,6 @@ import (
"context"
"fmt"
- "github.com/spf13/viper"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -43,9 +42,9 @@ func (p *processor) GetWebfingerAccount(ctx context.Context, requestedUsername s
return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err))
}
- accountDomain := viper.GetString(config.Keys.AccountDomain)
+ accountDomain := config.GetAccountDomain()
if accountDomain == "" {
- accountDomain = viper.GetString(config.Keys.Host)
+ accountDomain = config.GetHost()
}
// return the webfinger representation
diff --git a/internal/processing/instance.go b/internal/processing/instance.go
index f4fe2ca79..ab601d3b3 100644
--- a/internal/processing/instance.go
+++ b/internal/processing/instance.go
@@ -22,7 +22,6 @@ import (
"context"
"fmt"
- "github.com/spf13/viper"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -49,7 +48,7 @@ func (p *processor) InstanceGet(ctx context.Context, domain string) (*apimodel.I
func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSettingsUpdateRequest) (*apimodel.Instance, gtserror.WithCode) {
// fetch the instance entry from the db for processing
i := >smodel.Instance{}
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: host}}, i); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error fetching instance %s: %s", host, err))
}
diff --git a/internal/processing/search.go b/internal/processing/search.go
index 690a6eeaf..1b0813fd9 100644
--- a/internal/processing/search.go
+++ b/internal/processing/search.go
@@ -25,7 +25,6 @@ import (
"strings"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -166,8 +165,7 @@ func (p *processor) searchAccountByMention(ctx context.Context, authed *oauth.Au
// if it's a local account we can skip a whole bunch of stuff
maybeAcct := >smodel.Account{}
- host := viper.GetString(config.Keys.Host)
- if domain == host {
+ if domain == config.GetHost() {
maybeAcct, err = p.db.GetLocalAccountByUsername(ctx, username)
if err != nil {
return nil, fmt.Errorf("searchAccountByMention: error getting local account by username: %s", err)
diff --git a/internal/processing/statustimeline.go b/internal/processing/statustimeline.go
index 355825900..d4388f381 100644
--- a/internal/processing/statustimeline.go
+++ b/internal/processing/statustimeline.go
@@ -25,7 +25,6 @@ import (
"net/url"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -111,8 +110,8 @@ func StatusSkipInsertFunction() timeline.SkipInsertFunction {
nextItemAccountID string,
nextItemBoostOfID string,
nextItemBoostOfAccountID string,
- depth int) (bool, error) {
-
+ depth int,
+ ) (bool, error) {
// make sure we don't insert a duplicate
if newItemID == nextItemID {
return true, nil
@@ -148,8 +147,8 @@ func (p *processor) packageStatusResponse(statuses []*apimodel.Status, path stri
// prepare the next and previous links
if len(statuses) != 0 {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
nextLink := &url.URL{
Scheme: protocol,
diff --git a/internal/processing/user/emailconfirm.go b/internal/processing/user/emailconfirm.go
index e44a4605f..eccaae5ec 100644
--- a/internal/processing/user/emailconfirm.go
+++ b/internal/processing/user/emailconfirm.go
@@ -25,7 +25,6 @@ import (
"time"
"github.com/google/uuid"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/email"
@@ -34,9 +33,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/uris"
)
-var (
- oneWeek = 168 * time.Hour
-)
+var oneWeek = 168 * time.Hour
func (p *processor) SendConfirmEmail(ctx context.Context, user *gtsmodel.User, username string) error {
if user.UnconfirmedEmail == "" || user.UnconfirmedEmail == user.Email {
@@ -57,7 +54,7 @@ func (p *processor) SendConfirmEmail(ctx context.Context, user *gtsmodel.User, u
// pull our instance entry from the database so we can greet the user nicely in the email
instance := >smodel.Instance{}
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: host}}, instance); err != nil {
return fmt.Errorf("SendConfirmEmail: error getting instance: %s", err)
}
diff --git a/internal/router/router.go b/internal/router/router.go
index 939624cb7..ee7024cd1 100644
--- a/internal/router/router.go
+++ b/internal/router/router.go
@@ -27,7 +27,6 @@ import (
"codeberg.org/gruf/go-debug"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"golang.org/x/crypto/acme/autocert"
@@ -70,16 +69,12 @@ func (r *router) AttachStaticFS(relativePath string, fs http.FileSystem) {
// Start starts the router nicely. It will serve two handlers if letsencrypt is enabled, and only the web/API handler if letsencrypt is not enabled.
func (r *router) Start() {
- var (
- keys = config.Keys
+ // listen is the server start function, by
+ // default pointing to regular HTTP listener,
+ // but updated to TLS if LetsEncrypt is enabled.
+ listen := r.srv.ListenAndServe
- // listen is the server start function, by
- // default pointing to regular HTTP listener,
- // but updated to TLS if LetsEncrypt is enabled.
- listen = r.srv.ListenAndServe
- )
-
- if viper.GetBool(keys.LetsEncryptEnabled) {
+ if config.GetLetsEncryptEnabled() {
// LetsEncrypt support is enabled
// Prepare an HTTPS-redirect handler for LetsEncrypt fallback
@@ -97,8 +92,8 @@ func (r *router) Start() {
srv := (*r.srv) //nolint
srv.Handler = r.certManager.HTTPHandler(redirect)
srv.Addr = fmt.Sprintf("%s:%d",
- viper.GetString(keys.BindAddress),
- viper.GetInt(keys.LetsEncryptPort),
+ config.GetBindAddress(),
+ config.GetLetsEncryptPort(),
)
// Start the LetsEncrypt autocert manager HTTP server.
@@ -144,8 +139,6 @@ func (r *router) Stop(ctx context.Context) error {
// The given DB is only used in the New function for parsing config values, and is not otherwise
// pinned to the router.
func New(ctx context.Context, db db.DB) (Router, error) {
- keys := config.Keys
-
gin.SetMode(gin.ReleaseMode)
// create the actual engine here -- this is the core request routing handler for gts
@@ -158,7 +151,7 @@ func New(ctx context.Context, db db.DB) (Router, error) {
engine.MaxMultipartMemory = 8 << 20
// set up IP forwarding via x-forward-* headers.
- trustedProxies := viper.GetStringSlice(keys.TrustedProxies)
+ trustedProxies := config.GetTrustedProxies()
if err := engine.SetTrustedProxies(trustedProxies); err != nil {
return nil, err
}
@@ -187,8 +180,8 @@ func New(ctx context.Context, db db.DB) (Router, error) {
}
// create the http server here, passing the gin engine as handler
- bindAddress := viper.GetString(keys.BindAddress)
- port := viper.GetInt(keys.Port)
+ bindAddress := config.GetBindAddress()
+ port := config.GetPort()
listen := fmt.Sprintf("%s:%d", bindAddress, port)
s := &http.Server{
Addr: listen,
@@ -201,14 +194,14 @@ func New(ctx context.Context, db db.DB) (Router, error) {
// We need to spawn the underlying server slightly differently depending on whether lets encrypt is enabled or not.
// In either case, the gin engine will still be used for routing requests.
- leEnabled := viper.GetBool(keys.LetsEncryptEnabled)
+ leEnabled := config.GetLetsEncryptEnabled()
var m *autocert.Manager
if leEnabled {
// le IS enabled, so roll up an autocert manager for handling letsencrypt requests
- host := viper.GetString(keys.Host)
- leCertDir := viper.GetString(keys.LetsEncryptCertDir)
- leEmailAddress := viper.GetString(keys.LetsEncryptEmailAddress)
+ host := config.GetHost()
+ leCertDir := config.GetLetsEncryptCertDir()
+ leEmailAddress := config.GetLetsEncryptEmailAddress()
m = &autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(host),
diff --git a/internal/router/session.go b/internal/router/session.go
index a2cbff7d1..f94b0a22a 100644
--- a/internal/router/session.go
+++ b/internal/router/session.go
@@ -28,7 +28,6 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/memstore"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"golang.org/x/net/idna"
@@ -38,19 +37,19 @@ import (
func SessionOptions() sessions.Options {
return sessions.Options{
Path: "/",
- Domain: viper.GetString(config.Keys.Host),
- MaxAge: 120, // 2 minutes
- Secure: viper.GetString(config.Keys.Protocol) == "https", // only use cookie over https
- HttpOnly: true, // exclude javascript from inspecting cookie
- SameSite: http.SameSiteStrictMode, // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1
+ Domain: config.GetHost(),
+ MaxAge: 120, // 2 minutes
+ Secure: config.GetProtocol() == "https", // only use cookie over https
+ HttpOnly: true, // exclude javascript from inspecting cookie
+ SameSite: http.SameSiteStrictMode, // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1
}
}
// SessionName is a utility function that derives an appropriate session name from the hostname.
func SessionName() (string, error) {
// parse the protocol + host
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
u, err := url.Parse(fmt.Sprintf("%s://%s", protocol, host))
if err != nil {
return "", err
diff --git a/internal/router/session_test.go b/internal/router/session_test.go
index d36da9596..5f4777a48 100644
--- a/internal/router/session_test.go
+++ b/internal/router/session_test.go
@@ -21,7 +21,6 @@ package router_test
import (
"testing"
- "github.com/spf13/viper"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/router"
@@ -37,8 +36,8 @@ func (suite *SessionTestSuite) SetupTest() {
}
func (suite *SessionTestSuite) TestDeriveSessionNameLocalhostWithPort() {
- viper.Set(config.Keys.Protocol, "http")
- viper.Set(config.Keys.Host, "localhost:8080")
+ config.SetProtocol("http")
+ config.SetHost("localhost:8080")
sessionName, err := router.SessionName()
suite.NoError(err)
@@ -46,8 +45,8 @@ func (suite *SessionTestSuite) TestDeriveSessionNameLocalhostWithPort() {
}
func (suite *SessionTestSuite) TestDeriveSessionNameLocalhost() {
- viper.Set(config.Keys.Protocol, "http")
- viper.Set(config.Keys.Host, "localhost")
+ config.SetProtocol("http")
+ config.SetHost("localhost")
sessionName, err := router.SessionName()
suite.NoError(err)
@@ -55,8 +54,8 @@ func (suite *SessionTestSuite) TestDeriveSessionNameLocalhost() {
}
func (suite *SessionTestSuite) TestDeriveSessionNoProtocol() {
- viper.Set(config.Keys.Protocol, "")
- viper.Set(config.Keys.Host, "localhost")
+ config.SetProtocol("")
+ config.SetHost("localhost")
sessionName, err := router.SessionName()
suite.EqualError(err, "parse \"://localhost\": missing protocol scheme")
@@ -64,9 +63,9 @@ func (suite *SessionTestSuite) TestDeriveSessionNoProtocol() {
}
func (suite *SessionTestSuite) TestDeriveSessionNoHost() {
- viper.Set(config.Keys.Protocol, "https")
- viper.Set(config.Keys.Host, "")
- viper.Set(config.Keys.Port, 0)
+ config.SetProtocol("https")
+ config.SetHost("")
+ config.SetPort(0)
sessionName, err := router.SessionName()
suite.EqualError(err, "could not derive hostname without port from https://")
@@ -74,8 +73,8 @@ func (suite *SessionTestSuite) TestDeriveSessionNoHost() {
}
func (suite *SessionTestSuite) TestDeriveSessionOK() {
- viper.Set(config.Keys.Protocol, "https")
- viper.Set(config.Keys.Host, "example.org")
+ config.SetProtocol("https")
+ config.SetHost("example.org")
sessionName, err := router.SessionName()
suite.NoError(err)
@@ -83,8 +82,8 @@ func (suite *SessionTestSuite) TestDeriveSessionOK() {
}
func (suite *SessionTestSuite) TestDeriveSessionIDNOK() {
- viper.Set(config.Keys.Protocol, "https")
- viper.Set(config.Keys.Host, "fóid.org")
+ config.SetProtocol("https")
+ config.SetHost("fóid.org")
sessionName, err := router.SessionName()
suite.NoError(err)
diff --git a/internal/router/template.go b/internal/router/template.go
index 315f44a56..c033c8f07 100644
--- a/internal/router/template.go
+++ b/internal/router/template.go
@@ -26,16 +26,15 @@ import (
"time"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
// LoadTemplates loads html templates for use by the given engine
func loadTemplates(engine *gin.Engine) error {
- templateBaseDir := viper.GetString(config.Keys.WebTemplateBaseDir)
+ templateBaseDir := config.GetWebTemplateBaseDir()
if templateBaseDir == "" {
- return fmt.Errorf("%s cannot be empty and must be a relative or absolute path", config.Keys.WebTemplateBaseDir)
+ return fmt.Errorf("%s cannot be empty and must be a relative or absolute path", config.WebTemplateBaseDirFlag())
}
templateBaseDir, err := filepath.Abs(templateBaseDir)
diff --git a/internal/transport/controller.go b/internal/transport/controller.go
index 280d4bc0b..45eb4fd79 100644
--- a/internal/transport/controller.go
+++ b/internal/transport/controller.go
@@ -25,13 +25,11 @@ import (
"encoding/json"
"fmt"
"net/url"
- "runtime/debug"
"time"
"codeberg.org/gruf/go-byteutil"
"codeberg.org/gruf/go-cache/v2"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/activity/pub"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -59,11 +57,9 @@ type controller struct {
// NewController returns an implementation of the Controller interface for creating new transports
func NewController(db db.DB, federatingDB federatingdb.DB, clock pub.Clock, client pub.HttpClient) Controller {
- applicationName := viper.GetString(config.Keys.ApplicationName)
- host := viper.GetString(config.Keys.Host)
-
- // Determine build information
- build, _ := debug.ReadBuildInfo()
+ applicationName := config.GetApplicationName()
+ host := config.GetHost()
+ version := config.GetSoftwareVersion()
c := &controller{
db: db,
@@ -71,7 +67,7 @@ func NewController(db db.DB, federatingDB federatingdb.DB, clock pub.Clock, clie
clock: clock,
client: client,
cache: cache.New[string, *transport](),
- userAgent: fmt.Sprintf("%s; %s (gofed/activity gotosocial-%s)", applicationName, host, build.Main.Version),
+ userAgent: fmt.Sprintf("%s; %s (gofed/activity gotosocial-%s)", applicationName, host, version),
}
// Transport cache has TTL=1hr freq=1m
@@ -128,7 +124,7 @@ func (c *controller) NewTransportForUsername(ctx context.Context, username strin
// Otherwise, we can take the instance account and use those credentials to make the request.
var u string
if username == "" {
- u = viper.GetString(config.Keys.Host)
+ u = config.GetHost()
} else {
u = username
}
diff --git a/internal/transport/deliver.go b/internal/transport/deliver.go
index bacaa9b3a..0405116ad 100644
--- a/internal/transport/deliver.go
+++ b/internal/transport/deliver.go
@@ -27,7 +27,6 @@ import (
"strings"
"sync"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -69,7 +68,7 @@ outer:
func (t *transport) Deliver(ctx context.Context, b []byte, to *url.URL) error {
// if the 'to' host is our own, just skip this delivery since we by definition already have the message!
- if to.Host == viper.GetString(config.Keys.Host) || to.Host == viper.GetString(config.Keys.AccountDomain) {
+ if to.Host == config.GetHost() || to.Host == config.GetAccountDomain() {
return nil
}
diff --git a/internal/transport/dereference.go b/internal/transport/dereference.go
index 3d252525b..ba48488d7 100644
--- a/internal/transport/dereference.go
+++ b/internal/transport/dereference.go
@@ -25,7 +25,6 @@ import (
"net/http"
"net/url"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/uris"
)
@@ -33,7 +32,7 @@ import (
func (t *transport) Dereference(ctx context.Context, iri *url.URL) ([]byte, error) {
// if the request is to us, we can shortcut for certain URIs rather than going through
// the normal request flow, thereby saving time and energy
- if iri.Host == viper.GetString(config.Keys.Host) {
+ if iri.Host == config.GetHost() {
if uris.IsFollowersPath(iri) {
// the request is for followers of one of our accounts, which we can shortcut
return t.controller.dereferenceLocalFollowers(ctx, iri)
diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go
index d939ecc1c..81f4d9a31 100644
--- a/internal/typeutils/internaltoas.go
+++ b/internal/typeutils/internaltoas.go
@@ -26,7 +26,6 @@ import (
"net/url"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/activity/pub"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
@@ -629,9 +628,9 @@ func (c *converter) MentionToAS(ctx context.Context, m *gtsmodel.Mention) (vocab
// name -- this should be the namestring of the mentioned user, something like @whatever@example.org
var domain string
if m.TargetAccount.Domain == "" {
- accountDomain := viper.GetString(config.Keys.AccountDomain)
+ accountDomain := config.GetAccountDomain()
if accountDomain == "" {
- accountDomain = viper.GetString(config.Keys.Host)
+ accountDomain = config.GetHost()
}
domain = accountDomain
} else {
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
index 8ad601f0c..364e7152c 100644
--- a/internal/typeutils/internaltofrontend.go
+++ b/internal/typeutils/internaltofrontend.go
@@ -24,7 +24,6 @@ import (
"strings"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -575,9 +574,7 @@ func (c *converter) InstanceToAPIInstance(ctx context.Context, i *gtsmodel.Insta
}
// if the requested instance is *this* instance, we can add some extra information
- keys := config.Keys
- host := viper.GetString(keys.Host)
- if i.Domain == host {
+ if host := config.GetHost(); i.Domain == host {
userCount, err := c.db.CountInstanceUsers(ctx, host)
if err == nil {
mi.Stats["user_count"] = userCount
@@ -593,14 +590,14 @@ func (c *converter) InstanceToAPIInstance(ctx context.Context, i *gtsmodel.Insta
mi.Stats["domain_count"] = domainCount
}
- mi.Registrations = viper.GetBool(keys.AccountsRegistrationOpen)
- mi.ApprovalRequired = viper.GetBool(keys.AccountsApprovalRequired)
+ mi.Registrations = config.GetAccountsRegistrationOpen()
+ mi.ApprovalRequired = config.GetAccountsApprovalRequired()
mi.InvitesEnabled = false // TODO
- mi.MaxTootChars = uint(viper.GetInt(keys.StatusesMaxChars))
+ mi.MaxTootChars = uint(config.GetStatusesMaxChars())
mi.URLS = &model.InstanceURLs{
StreamingAPI: fmt.Sprintf("wss://%s", host),
}
- mi.Version = viper.GetString(keys.SoftwareVersion)
+ mi.Version = config.GetSoftwareVersion()
}
// get the instance account if it exists and just skip if it doesn't
diff --git a/internal/uris/uri.go b/internal/uris/uri.go
index e38024ac2..a9fcc9386 100644
--- a/internal/uris/uri.go
+++ b/internal/uris/uri.go
@@ -22,7 +22,6 @@ import (
"fmt"
"net/url"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/regexes"
)
@@ -79,47 +78,47 @@ type UserURIs struct {
// GenerateURIForFollow returns the AP URI for a new follow -- something like:
// https://example.org/users/whatever_user/follow/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForFollow(username string, thisFollowID string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s/%s/%s/%s", protocol, host, UsersPath, username, FollowPath, thisFollowID)
}
// GenerateURIForLike returns the AP URI for a new like/fave -- something like:
// https://example.org/users/whatever_user/liked/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForLike(username string, thisFavedID string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s/%s/%s/%s", protocol, host, UsersPath, username, LikedPath, thisFavedID)
}
// GenerateURIForUpdate returns the AP URI for a new update activity -- something like:
// https://example.org/users/whatever_user#updates/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForUpdate(username string, thisUpdateID string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s/%s#%s/%s", protocol, host, UsersPath, username, UpdatePath, thisUpdateID)
}
// GenerateURIForBlock returns the AP URI for a new block activity -- something like:
// https://example.org/users/whatever_user/blocks/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForBlock(username string, thisBlockID string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s/%s/%s/%s", protocol, host, UsersPath, username, BlocksPath, thisBlockID)
}
// GenerateURIForEmailConfirm returns a link for email confirmation -- something like:
// https://example.org/confirm_email?token=490e337c-0162-454f-ac48-4b22bb92a205
func GenerateURIForEmailConfirm(token string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s?token=%s", protocol, host, ConfirmEmailPath, token)
}
// GenerateURIsForAccount throws together a bunch of URIs for the given username, with the given protocol and host.
func GenerateURIsForAccount(username string) *UserURIs {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
+ protocol := config.GetProtocol()
+ host := config.GetHost()
// The below URLs are used for serving web requests
hostURL := fmt.Sprintf("%s://%s", protocol, host)
@@ -157,17 +156,15 @@ func GenerateURIsForAccount(username string) *UserURIs {
// GenerateURIForAttachment generates a URI for an attachment/emoji/header etc.
// Will produced something like https://example.org/fileserver/01FPST95B8FC3HG3AGCDKPQNQ2/attachment/original/01FPST9QK4V5XWS3F9Z4F2G1X7.gif
func GenerateURIForAttachment(accountID string, mediaType string, mediaSize string, mediaID string, extension string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
-
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s/%s/%s/%s/%s.%s", protocol, host, FileserverPath, accountID, mediaType, mediaSize, mediaID, extension)
}
// GenerateURIForEmoji generates an activitypub uri for a new emoji.
func GenerateURIForEmoji(emojiID string) string {
- protocol := viper.GetString(config.Keys.Protocol)
- host := viper.GetString(config.Keys.Host)
-
+ protocol := config.GetProtocol()
+ host := config.GetHost()
return fmt.Sprintf("%s://%s/%s/%s", protocol, host, EmojiPath, emojiID)
}
diff --git a/internal/web/base.go b/internal/web/base.go
index fff61043a..d203522ae 100644
--- a/internal/web/base.go
+++ b/internal/web/base.go
@@ -27,7 +27,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/processing"
@@ -54,9 +53,9 @@ type Module struct {
// New returns a new api.ClientModule for web pages.
func New(processor processing.Processor) (api.ClientModule, error) {
- assetsBaseDir := viper.GetString(config.Keys.WebAssetBaseDir)
+ assetsBaseDir := config.GetWebAssetBaseDir()
if assetsBaseDir == "" {
- return nil, fmt.Errorf("%s cannot be empty and must be a relative or absolute path", config.Keys.WebAssetBaseDir)
+ return nil, fmt.Errorf("%s cannot be empty and must be a relative or absolute path", config.WebAssetBaseDirFlag())
}
assetsPath, err := filepath.Abs(assetsBaseDir)
@@ -106,7 +105,7 @@ func (m *Module) baseHandler(c *gin.Context) {
l := logrus.WithField("func", "BaseGETHandler")
l.Trace("serving index html")
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
instance, err := m.processor.InstanceGet(c.Request.Context(), host)
if err != nil {
l.Debugf("error getting instance from processor: %s", err)
@@ -124,7 +123,7 @@ func (m *Module) NotFoundHandler(c *gin.Context) {
l := logrus.WithField("func", "404")
l.Trace("serving 404 html")
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
instance, err := m.processor.InstanceGet(c.Request.Context(), host)
if err != nil {
l.Debugf("error getting instance from processor: %s", err)
diff --git a/internal/web/confirmemail.go b/internal/web/confirmemail.go
index 9488c5d52..7c8aa464f 100644
--- a/internal/web/confirmemail.go
+++ b/internal/web/confirmemail.go
@@ -23,7 +23,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -45,7 +44,7 @@ func (m *Module) confirmEmailGETHandler(c *gin.Context) {
return
}
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
instance, err := m.processor.InstanceGet(ctx, host)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
diff --git a/internal/web/profile.go b/internal/web/profile.go
index 7fad7f4c6..66419dcc7 100644
--- a/internal/web/profile.go
+++ b/internal/web/profile.go
@@ -27,7 +27,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -52,7 +51,7 @@ func (m *Module) profileTemplateHandler(c *gin.Context) {
return
}
- instance, errWithCode := m.processor.InstanceGet(ctx, viper.GetString(config.Keys.Host))
+ instance, errWithCode := m.processor.InstanceGet(ctx, config.GetHost())
if errWithCode != nil {
l.Debugf("error getting instance from processor: %s", errWithCode.Error())
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
diff --git a/internal/web/thread.go b/internal/web/thread.go
index 0450f6b26..3a9839281 100644
--- a/internal/web/thread.go
+++ b/internal/web/thread.go
@@ -23,7 +23,6 @@ import (
"strings"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/config"
@@ -57,7 +56,7 @@ func (m *Module) threadTemplateHandler(c *gin.Context) {
return
}
- host := viper.GetString(config.Keys.Host)
+ host := config.GetHost()
instance, err := m.processor.InstanceGet(ctx, host)
if err != nil {
l.Debugf("error getting instance from processor: %s", err)
diff --git a/test/cliparsing.sh b/test/cliparsing.sh
index b06c66d44..98fc6fd0f 100755
--- a/test/cliparsing.sh
+++ b/test/cliparsing.sh
@@ -5,7 +5,7 @@ set -e
echo "STARTING CLI TESTS"
echo "TEST_1 Make sure defaults are set correctly."
-TEST_1_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_1_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","email":"","host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_1="$(go run ./cmd/gotosocial/... debug config)"
if [ "${TEST_1}" != "${TEST_1_EXPECTED}" ]; then
echo "TEST_1 not equal TEST_1_EXPECTED"
@@ -15,7 +15,7 @@ else
fi
echo "TEST_2 Override db-address from default using cli flag."
-TEST_2_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_2_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","email":"","host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_2="$(go run ./cmd/gotosocial/... --db-address some.db.address debug config)"
if [ "${TEST_2}" != "${TEST_2_EXPECTED}" ]; then
echo "TEST_2 not equal TEST_2_EXPECTED"
@@ -25,7 +25,7 @@ else
fi
echo "TEST_3 Override db-address from default using env var."
-TEST_3_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_3_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","email":"","host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_3="$(GTS_DB_ADDRESS=some.db.address go run ./cmd/gotosocial/... debug config)"
if [ "${TEST_3}" != "${TEST_3_EXPECTED}" ]; then
echo "TEST_3 not equal TEST_3_EXPECTED"
@@ -35,7 +35,7 @@ else
fi
echo "TEST_4 Override db-address from default using both env var and cli flag. The cli flag should take priority."
-TEST_4_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.other.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_4_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.other.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","email":"","host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_4="$(GTS_DB_ADDRESS=some.db.address go run ./cmd/gotosocial/... --db-address some.other.db.address debug config)"
if [ "${TEST_4}" != "${TEST_4_EXPECTED}" ]; then
echo "TEST_4 not equal TEST_4_EXPECTED"
@@ -45,7 +45,7 @@ else
fi
echo "TEST_5 Test loading a config file by passing an env var."
-TEST_5_EXPECTED='{"account-domain":"example.org","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_5_EXPECTED='{"account-domain":"example.org","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","email":"","host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_5="$(GTS_CONFIG_PATH=./test/test.yaml go run ./cmd/gotosocial/... debug config)"
if [ "${TEST_5}" != "${TEST_5_EXPECTED}" ]; then
echo "TEST_5 not equal TEST_5_EXPECTED"
@@ -55,7 +55,7 @@ else
fi
echo "TEST_6 Test loading a config file by passing cli flag."
-TEST_6_EXPECTED='{"account-domain":"example.org","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_6_EXPECTED='{"account-domain":"example.org","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","email":"","host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_6="$(go run ./cmd/gotosocial/... --config-path ./test/test.yaml debug config)"
if [ "${TEST_6}" != "${TEST_6_EXPECTED}" ]; then
echo "TEST_6 not equal TEST_6_EXPECTED"
@@ -65,7 +65,7 @@ else
fi
echo "TEST_7 Test loading a config file and overriding one of the variables with a cli flag."
-TEST_7_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_7_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","email":"","host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_7="$(go run ./cmd/gotosocial/... --config-path ./test/test.yaml --account-domain '' debug config)"
if [ "${TEST_7}" != "${TEST_7_EXPECTED}" ]; then
echo "TEST_7 not equal TEST_7_EXPECTED"
@@ -75,7 +75,7 @@ else
fi
echo "TEST_8 Test loading a config file and overriding one of the variables with an env var."
-TEST_8_EXPECTED='{"account-domain":"peepee","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_8_EXPECTED='{"account-domain":"peepee","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","email":"","host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_8="$(GTS_ACCOUNT_DOMAIN='peepee' go run ./cmd/gotosocial/... --config-path ./test/test.yaml debug config)"
if [ "${TEST_8}" != "${TEST_8_EXPECTED}" ]; then
echo "TEST_8 not equal TEST_8_EXPECTED"
@@ -85,7 +85,7 @@ else
fi
echo "TEST_9 Test loading a config file and overriding one of the variables with both an env var and a cli flag. The cli flag should have priority."
-TEST_9_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_9_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.yaml","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","email":"","host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_9="$(GTS_ACCOUNT_DOMAIN='peepee' go run ./cmd/gotosocial/... --config-path ./test/test.yaml --account-domain '' debug config)"
if [ "${TEST_9}" != "${TEST_9_EXPECTED}" ]; then
echo "TEST_9 not equal TEST_9_EXPECTED"
@@ -95,7 +95,7 @@ else
fi
echo "TEST_10 Test loading a config file from json."
-TEST_10_EXPECTED='{"account-domain":"example.org","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.json","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_10_EXPECTED='{"account-domain":"example.org","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test.json","db-address":"127.0.0.1","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","email":"","host":"gts.example.org","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":false,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","email","profile","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"someone@example.org","smtp-host":"verycoolemailhost.mail","smtp-password":"smtp-password","smtp-port":8888,"smtp-username":"smtp-username","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","0.0.0.0/0"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_10="$(go run ./cmd/gotosocial/... --config-path ./test/test.json debug config)"
if [ "${TEST_10}" != "${TEST_10_EXPECTED}" ]; then
echo "TEST_10 not equal TEST_10_EXPECTED"
@@ -105,7 +105,7 @@ else
fi
echo "TEST_11 Test loading a partial config file. Default values should be used apart from those set in the config file."
-TEST_11_EXPECTED='{"account-domain":"peepee.poopoo","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test2.yaml","db-address":"","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"trace","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
+TEST_11_EXPECTED='{"account-domain":"peepee.poopoo","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test2.yaml","db-address":"","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","email":"","host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":false,"letsencrypt-port":80,"log-db-queries":false,"log-level":"trace","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-remote-cache-days":30,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"password":"","path":"","port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"username":"","web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
TEST_11="$(go run ./cmd/gotosocial/... --config-path ./test/test2.yaml debug config)"
if [ "${TEST_11}" != "${TEST_11_EXPECTED}" ]; then
echo "TEST_11 not equal TEST_11_EXPECTED"
diff --git a/testrig/config.go b/testrig/config.go
index ccc28d17c..64b8649aa 100644
--- a/testrig/config.go
+++ b/testrig/config.go
@@ -19,45 +19,19 @@
package testrig
import (
- "reflect"
-
"github.com/coreos/go-oidc/v3/oidc"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
-// InitTestConfig resets + initializes the viper configuration with test defaults.
+// InitTestConfig initializes viper configuration with test defaults.
func InitTestConfig() {
- // reset viper to an empty state
- viper.Reset()
-
- // get the field names of config.Keys
- keyFields := reflect.VisibleFields(reflect.TypeOf(config.Keys))
-
- // get the field values of config.Keys
- keyValues := reflect.ValueOf(config.Keys)
-
- // get the field values of TestDefaults
- testDefaults := reflect.ValueOf(TestDefaults)
-
- // for each config field...
- for _, field := range keyFields {
- // the viper config key should be the value of the key
- key, ok := keyValues.FieldByName(field.Name).Interface().(string)
- if !ok {
- panic("could not convert config.Keys value to string")
- }
-
- // the value should be the test default corresponding to the given fieldName
- value := testDefaults.FieldByName(field.Name).Interface()
-
- // actually set the value in viper -- this will override everything
- viper.Set(key, value)
- }
+ config.Config(func(cfg *config.Configuration) {
+ *cfg = TestDefaults
+ })
}
// TestDefaults returns a Values struct with values set that are suitable for local testing.
-var TestDefaults = config.Values{
+var TestDefaults = config.Configuration{
LogLevel: "trace",
LogDbQueries: true,
ApplicationName: "gotosocial",
diff --git a/testrig/db.go b/testrig/db.go
index 61d80e6ae..67bc681c6 100644
--- a/testrig/db.go
+++ b/testrig/db.go
@@ -24,7 +24,6 @@ import (
"strconv"
"github.com/sirupsen/logrus"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/bundb"
@@ -69,11 +68,15 @@ var testModels = []interface{}{
// value as the port instead.
func NewTestDB() db.DB {
if alternateAddress := os.Getenv("GTS_DB_ADDRESS"); alternateAddress != "" {
- viper.Set(config.Keys.DbAddress, alternateAddress)
+ config.Config(func(cfg *config.Configuration) {
+ cfg.DbAddress = alternateAddress
+ })
}
if alternateDBType := os.Getenv("GTS_DB_TYPE"); alternateDBType != "" {
- viper.Set(config.Keys.DbType, alternateDBType)
+ config.Config(func(cfg *config.Configuration) {
+ cfg.DbType = alternateDBType
+ })
}
if alternateDBPort := os.Getenv("GTS_DB_PORT"); alternateDBPort != "" {
@@ -81,7 +84,9 @@ func NewTestDB() db.DB {
if err != nil {
panic(err)
}
- viper.Set(config.Keys.DbPort, port)
+ config.Config(func(cfg *config.Configuration) {
+ cfg.DbPort = int(port)
+ })
}
testDB, err := bundb.NewBunDBService(context.Background())
diff --git a/testrig/email.go b/testrig/email.go
index 5873ee442..eb1ac4e06 100644
--- a/testrig/email.go
+++ b/testrig/email.go
@@ -19,7 +19,6 @@
package testrig
import (
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/email"
)
@@ -30,7 +29,9 @@ import (
// the map, with email address of the recipient as the key, and the value as the
// parsed email message as it would have been sent.
func NewEmailSender(templateBaseDir string, sentEmails map[string]string) email.Sender {
- viper.Set(config.Keys.WebTemplateBaseDir, templateBaseDir)
+ config.Config(func(cfg *config.Configuration) {
+ cfg.WebTemplateBaseDir = templateBaseDir
+ })
var sendCallback func(toAddress string, message string)
diff --git a/testrig/router.go b/testrig/router.go
index 468b468c6..e06e21bd4 100644
--- a/testrig/router.go
+++ b/testrig/router.go
@@ -26,7 +26,6 @@ import (
"runtime"
"github.com/gin-gonic/gin"
- "github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/router"
@@ -38,11 +37,13 @@ import (
// value as the template base directory instead.
func NewTestRouter(db db.DB) router.Router {
if alternativeTemplateBaseDir := os.Getenv("GTS_WEB_TEMPLATE_BASE_DIR"); alternativeTemplateBaseDir != "" {
- viper.Set(config.Keys.WebTemplateBaseDir, alternativeTemplateBaseDir)
+ config.Config(func(cfg *config.Configuration) {
+ cfg.WebTemplateBaseDir = alternativeTemplateBaseDir
+ })
}
if alternativeBindAddress := os.Getenv("GTS_BIND_ADDRESS"); alternativeBindAddress != "" {
- viper.Set(config.Keys.BindAddress, alternativeBindAddress)
+ config.SetBindAddress(alternativeBindAddress)
}
r, err := router.New(context.Background(), db)
@@ -56,7 +57,7 @@ func NewTestRouter(db db.DB) router.Router {
func ConfigureTemplatesWithGin(engine *gin.Engine) {
router.LoadTemplateFunctions(engine)
- templateBaseDir := viper.GetString(config.Keys.WebTemplateBaseDir)
+ templateBaseDir := config.GetWebTemplateBaseDir()
if !filepath.IsAbs(templateBaseDir) {
// https://stackoverflow.com/questions/31873396/is-it-possible-to-get-the-current-root-of-package-structure-as-a-string-in-golan