[chore] Global server configuration overhaul (#575)

* move config flag names and usage to config package, rewrite config package to use global Configuration{} struct

Signed-off-by: kim <grufwub@gmail.com>

* improved code comment

Signed-off-by: kim <grufwub@gmail.com>

* linter

Signed-off-by: kim <grufwub@gmail.com>

* fix unmarshaling

Signed-off-by: kim <grufwub@gmail.com>

* remove kim's custom go compiler changes

Signed-off-by: kim <grufwub@gmail.com>

* generate setter and flag-name functions, implement these in codebase

Signed-off-by: kim <grufwub@gmail.com>

* update deps

Signed-off-by: kim <grufwub@gmail.com>

* small change

Signed-off-by: kim <grufwub@gmail.com>

* appease the linter...

Signed-off-by: kim <grufwub@gmail.com>

* move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync

Signed-off-by: kim <grufwub@gmail.com>

* lint

Signed-off-by: kim <grufwub@gmail.com>

* update code comments

Signed-off-by: kim <grufwub@gmail.com>

* fix merge issue

Signed-off-by: kim <grufwub@gmail.com>

* fix merge issue

Signed-off-by: kim <grufwub@gmail.com>

* improved version string (removes time + go version)

Signed-off-by: kim <grufwub@gmail.com>

* fix version string build to pass test script + consolidate logic in func

Signed-off-by: kim <grufwub@gmail.com>

* add license text, update config.Defaults comment

Signed-off-by: kim <grufwub@gmail.com>

* add license text to generated config helpers file

Signed-off-by: kim <grufwub@gmail.com>

* defer unlock on config.Set___(), to ensure unlocked on panic

Signed-off-by: kim <grufwub@gmail.com>

* make it more obvious which cmd flags are being attached

Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2022-05-30 13:41:24 +01:00 committed by GitHub
parent ae5402ada6
commit 43ac0cdb9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 2450 additions and 1125 deletions

View file

@ -24,7 +24,6 @@
"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 @@
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 @@
return err
}
email := viper.GetString(config.Keys.AdminAccountEmail)
email := config.GetAdminAccountEmail()
if email == "" {
return errors.New("no email set")
}
@ -57,7 +56,7 @@
return err
}
password := viper.GetString(config.Keys.AdminAccountPassword)
password := config.GetAdminAccountPassword()
if password == "" {
return errors.New("no password set")
}
@ -80,7 +79,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
return err
}
password := viper.GetString(config.Keys.AdminAccountPassword)
password := config.GetAdminAccountPassword()
if password == "" {
return errors.New("no password set")
}

View file

@ -23,7 +23,6 @@
"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 @@
exporter := trans.NewExporter(dbConn)
path := viper.GetString(config.Keys.AdminTransPath)
path := config.GetAdminTransPath()
if path == "" {
return errors.New("no path set")
}

View file

@ -23,7 +23,6 @@
"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 @@
importer := trans.NewImporter(dbConn)
path := viper.GetString(config.Keys.AdminTransPath)
path := config.GetAdminTransPath()
if path == "" {
return errors.New("no path set")
}

View file

@ -23,17 +23,29 @@
"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
}

View file

@ -29,7 +29,6 @@
"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 @@
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 @@
// 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 @@
}
// 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)
}

View file

@ -22,7 +22,6 @@
"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

View file

@ -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 {

View file

@ -21,7 +21,6 @@
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
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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)
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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)
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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)
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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",
}

View file

@ -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 @@
//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, " ")
}

View file

@ -21,7 +21,6 @@
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
}

2
go.mod
View file

@ -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

View file

@ -8,7 +8,6 @@
"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)

View file

@ -24,7 +24,6 @@
"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
}

View file

@ -26,7 +26,6 @@
"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)

View file

@ -24,7 +24,6 @@
"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
}

View file

@ -26,7 +26,6 @@
"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

View file

@ -25,7 +25,6 @@
"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)

View file

@ -26,7 +26,6 @@
"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)

View file

@ -4,7 +4,6 @@
"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 {

View file

@ -24,7 +24,6 @@
"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

View file

@ -33,7 +33,6 @@
"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"]

View file

@ -24,7 +24,6 @@
"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 {

View file

@ -31,7 +31,6 @@
"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"]

View file

@ -24,7 +24,6 @@
"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 != "" {

View file

@ -26,7 +26,6 @@
"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)

View file

@ -27,7 +27,6 @@
"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()

139
internal/config/config.go Normal file
View file

@ -0,0 +1,139 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
import (
"reflect"
"github.com/mitchellh/mapstructure"
)
// cfgtype is the reflected type information of Configuration{}.
var cfgtype = reflect.TypeOf(Configuration{})
// fieldtag will fetch the string value for the given tag name
// on the given field name in the Configuration{} struct.
func fieldtag(field, tag string) string {
sfield, ok := cfgtype.FieldByName(field)
if !ok {
panic("unknown struct field")
}
return sfield.Tag.Get(tag)
}
// Configuration represents global GTS server runtime configuration.
//
// Please note that if you update this struct's fields or tags, you
// will need to regenerate the global Getter/Setter helpers by running:
// `go run ./internal/config/gen/ -out ./internal/config/helpers.gen.go`
type Configuration struct {
LogLevel string `name:"log-level" usage:"Log level to run at: [trace, debug, info, warn, fatal]"`
LogDbQueries bool `name:"log-db-queries" usage:"Log database queries verbosely when log-level is trace or debug"`
ApplicationName string `name:"application-name" usage:"Name of the application, used in various places internally"`
ConfigPath string `name:"config-path" usage:"Path to a file containing gotosocial configuration. Values set in this file will be overwritten by values set as env vars or arguments"`
Host string `name:"host" usage:"Hostname to use for the server (eg., example.org, gotosocial.whatever.com). DO NOT change this on a server that's already run!"`
AccountDomain string `name:"account-domain" usage:"Domain to use in account names (eg., example.org, whatever.com). If not set, will default to the setting for host. DO NOT change this on a server that's already run!"`
Protocol string `name:"protocol" usage:"Protocol to use for the REST api of the server (only use http if you are debugging or behind a reverse proxy!)"`
BindAddress string `name:"bind-address" usage:"Bind address to use for the GoToSocial server (eg., 0.0.0.0, 172.138.0.9, [::], localhost). For ipv6, enclose the address in square brackets, eg [2001:db8::fed1]. Default binds to all interfaces."`
Port int `name:"port" usage:"Port to use for GoToSocial. Change this to 443 if you're running the binary directly on the host machine."`
TrustedProxies []string `name:"trusted-proxies" usage:"Proxies to trust when parsing x-forwarded headers into real IPs."`
SoftwareVersion string `name:"software-version" usage:""`
DbType string `name:"db-type" usage:"Database type: eg., postgres"`
DbAddress string `name:"db-address" usage:"Database ipv4 address, hostname, or filename"`
DbPort int `name:"db-port" usage:"Database port"`
DbUser string `name:"db-user" usage:"Database username"`
DbPassword string `name:"db-password" usage:"Database password"`
DbDatabase string `name:"db-database" usage:"Database name"`
DbTLSMode string `name:"db-tls-mode" usage:"Database tls mode"`
DbTLSCACert string `name:"db-tls-ca-cert" usage:"Path to CA cert for db tls connection"`
WebTemplateBaseDir string `name:"web-template-base-dir" usage:"Basedir for html templating files for rendering pages and composing emails."`
WebAssetBaseDir string `name:"web-asset-base-dir" usage:"Directory to serve static assets from, accessible at example.org/assets/"`
AccountsRegistrationOpen bool `name:"accounts-registration-open" usage:"Allow anyone to submit an account signup request. If false, server will be invite-only."`
AccountsApprovalRequired bool `name:"accounts-approval-required" usage:"Do account signups require approval by an admin or moderator before user can log in? If false, new registrations will be automatically approved."`
AccountsReasonRequired bool `name:"accounts-reason-required" usage:"Do new account signups require a reason to be submitted on registration?"`
MediaImageMaxSize int `name:"media-image-max-size" usage:"Max size of accepted images in bytes"`
MediaVideoMaxSize int `name:"media-video-max-size" usage:"Max size of accepted videos in bytes"`
MediaDescriptionMinChars int `name:"media-description-min-chars" usage:"Min required chars for an image description"`
MediaDescriptionMaxChars int `name:"media-description-max-chars" usage:"Max permitted chars for an image description"`
MediaRemoteCacheDays int `name:"media-remote-cache-days" usage:"Number of days to locally cache media from remote instances. If set to 0, remote media will be kept indefinitely."`
StorageBackend string `name:"storage-backend" usage:"Storage backend to use for media attachments"`
StorageLocalBasePath string `name:"storage-local-base-path" usage:"Full path to an already-created directory where gts should store/retrieve media files. Subfolders will be created within this dir."`
StatusesMaxChars int `name:"statuses-max-chars" usage:"Max permitted characters for posted statuses"`
StatusesCWMaxChars int `name:"statuses-cw-max-chars" usage:"Max permitted characters for content/spoiler warnings on statuses"`
StatusesPollMaxOptions int `name:"statuses-poll-max-options" usage:"Max amount of options permitted on a poll"`
StatusesPollOptionMaxChars int `name:"statuses-poll-option-max-chars" usage:"Max amount of characters for a poll option"`
StatusesMediaMaxFiles int `name:"statuses-media-max-files" usage:"Maximum number of media files/attachments per status"`
LetsEncryptEnabled bool `name:"letsencrypt-enabled" usage:"Enable letsencrypt TLS certs for this server. If set to true, then cert dir also needs to be set (or take the default)."`
LetsEncryptPort int `name:"letsencrypt-port" usage:"Port to listen on for letsencrypt certificate challenges. Must not be the same as the GtS webserver/API port."`
LetsEncryptCertDir string `name:"letsencrypt-cert-dir" usage:"Directory to store acquired letsencrypt certificates."`
LetsEncryptEmailAddress string `name:"letsencrypt-email-address" usage:"Email address to use when requesting letsencrypt certs. Will receive updates on cert expiry etc."`
OIDCEnabled bool `name:"oidc-enabled" usage:"Enabled OIDC authorization for this instance. If set to true, then the other OIDC flags must also be set."`
OIDCIdpName string `name:"oidc-idp-name" usage:"Name of the OIDC identity provider. Will be shown to the user when logging in."`
OIDCSkipVerification bool `name:"oidc-skip-verification" usage:"Skip verification of tokens returned by the OIDC provider. Should only be set to 'true' for testing purposes, never in a production environment!"`
OIDCIssuer string `name:"oidc-issuer" usage:"Address of the OIDC issuer. Should be the web address, including protocol, at which the issuer can be reached. Eg., 'https://example.org/auth'"`
OIDCClientID string `name:"oidc-client-id" usage:"ClientID of GoToSocial, as registered with the OIDC provider."`
OIDCClientSecret string `name:"oidc-client-secret" usage:"ClientSecret of GoToSocial, as registered with the OIDC provider."`
OIDCScopes []string `name:"oidc-scopes" usage:"OIDC scopes."`
SMTPHost string `name:"smtp-host" usage:"Host of the smtp server. Eg., 'smtp.eu.mailgun.org'"`
SMTPPort int `name:"smtp-port" usage:"Port of the smtp server. Eg., 587"`
SMTPUsername string `name:"smtp-username" usage:"Username to authenticate with the smtp server as. Eg., 'postmaster@mail.example.org'"`
SMTPPassword string `name:"smtp-password" usage:"Password to pass to the smtp server."`
SMTPFrom string `name:"smtp-from" usage:"Address to use as the 'from' field of the email. Eg., 'gotosocial@example.org'"`
SyslogEnabled bool `name:"syslog-enabled" usage:"Enable the syslog logging hook. Logs will be mirrored to the configured destination."`
SyslogProtocol string `name:"syslog-protocol" usage:"Protocol to use when directing logs to syslog. Leave empty to connect to local syslog."`
SyslogAddress string `name:"syslog-address" usage:"Address:port to send syslog logs to. Leave empty to connect to local syslog."`
// TODO: move these elsewhere, these are more ephemeral vs long-running flags like above
AdminAccountUsername string `name:"username" usage:"the username to create/delete/etc"`
AdminAccountEmail string `name:"email" usage:"the email address of this account"`
AdminAccountPassword string `name:"password" usage:"the password to set for this account"`
AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"`
}
// MarshalMap will marshal current Configuration into a map structure (useful for JSON).
func (cfg *Configuration) MarshalMap() (map[string]interface{}, error) {
var dst map[string]interface{}
dec, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "name",
Result: &dst,
})
if err := dec.Decode(cfg); err != nil {
return nil, err
}
return dst, nil
}
// UnmarshalMap will unmarshal a map structure into the receiving Configuration.
func (cfg *Configuration) UnmarshalMap(src map[string]interface{}) error {
dec, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "name",
Result: cfg,
})
return dec.Decode(src)
}

View file

@ -20,9 +20,9 @@
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",

View file

@ -1,38 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
import (
"github.com/spf13/viper"
)
// ReadFromFile checks if there's already a path to the config file set in viper.
// If there is, it will attempt to read the config file into viper.
func ReadFromFile() error {
// config file stuff
// check if we have a config path set (either by cli arg or env var)
if configPath := viper.GetString(Keys.ConfigPath); configPath != "" {
viper.SetConfigFile(configPath)
if err := viper.ReadInConfig(); err != nil {
return err
}
}
return nil
}

157
internal/config/flags.go Normal file
View file

@ -0,0 +1,157 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
import (
"github.com/spf13/cobra"
)
// TODO: consolidate these methods into the Configuration{} or ConfigState{} structs.
// AddGlobalFlags will attach global configuration flags to given cobra command, loading defaults from global config.
func AddGlobalFlags(cmd *cobra.Command) {
Config(func(cfg *Configuration) {
// General
cmd.PersistentFlags().String(ApplicationNameFlag(), cfg.ApplicationName, fieldtag("ApplicationName", "usage"))
cmd.PersistentFlags().String(HostFlag(), cfg.Host, fieldtag("Host", "usage"))
cmd.PersistentFlags().String(AccountDomainFlag(), cfg.AccountDomain, fieldtag("AccountDomain", "usage"))
cmd.PersistentFlags().String(ProtocolFlag(), cfg.Protocol, fieldtag("Protocol", "usage"))
cmd.PersistentFlags().String(LogLevelFlag(), cfg.LogLevel, fieldtag("LogLevel", "usage"))
cmd.PersistentFlags().Bool(LogDbQueriesFlag(), cfg.LogDbQueries, fieldtag("LogDbQueries", "usage"))
cmd.PersistentFlags().String(ConfigPathFlag(), cfg.ConfigPath, fieldtag("ConfigPath", "usage"))
// Database
cmd.PersistentFlags().String(DbTypeFlag(), cfg.DbType, fieldtag("DbType", "usage"))
cmd.PersistentFlags().String(DbAddressFlag(), cfg.DbAddress, fieldtag("DbAddress", "usage"))
cmd.PersistentFlags().Int(DbPortFlag(), cfg.DbPort, fieldtag("DbPort", "usage"))
cmd.PersistentFlags().String(DbUserFlag(), cfg.DbUser, fieldtag("DbUser", "usage"))
cmd.PersistentFlags().String(DbPasswordFlag(), cfg.DbPassword, fieldtag("DbPassword", "usage"))
cmd.PersistentFlags().String(DbDatabaseFlag(), cfg.DbDatabase, fieldtag("DbDatabase", "usage"))
cmd.PersistentFlags().String(DbTLSModeFlag(), cfg.DbTLSMode, fieldtag("DbTLSMode", "usage"))
cmd.PersistentFlags().String(DbTLSCACertFlag(), cfg.DbTLSCACert, fieldtag("DbTLSCACert", "usage"))
})
}
// AddServerFlags will attach server configuration flags to given cobra command, loading defaults from global config.
func AddServerFlags(cmd *cobra.Command) {
Config(func(cfg *Configuration) {
// Router
cmd.PersistentFlags().String(BindAddressFlag(), cfg.BindAddress, fieldtag("BindAddress", "usage"))
cmd.PersistentFlags().Int(PortFlag(), cfg.Port, fieldtag("Port", "usage"))
cmd.PersistentFlags().StringSlice(TrustedProxiesFlag(), cfg.TrustedProxies, fieldtag("TrustedProxies", "usage"))
// Template
cmd.Flags().String(WebTemplateBaseDirFlag(), cfg.WebTemplateBaseDir, fieldtag("WebTemplateBaseDir", "usage"))
cmd.Flags().String(WebAssetBaseDirFlag(), cfg.WebAssetBaseDir, fieldtag("WebAssetBaseDir", "usage"))
// Accounts
cmd.Flags().Bool(AccountsRegistrationOpenFlag(), cfg.AccountsRegistrationOpen, fieldtag("AccountsRegistrationOpen", "usage"))
cmd.Flags().Bool(AccountsApprovalRequiredFlag(), cfg.AccountsApprovalRequired, fieldtag("AccountsApprovalRequired", "usage"))
cmd.Flags().Bool(AccountsReasonRequiredFlag(), cfg.AccountsReasonRequired, fieldtag("AccountsReasonRequired", "usage"))
// Media
cmd.Flags().Int(MediaImageMaxSizeFlag(), cfg.MediaImageMaxSize, fieldtag("MediaImageMaxSize", "usage"))
cmd.Flags().Int(MediaVideoMaxSizeFlag(), cfg.MediaVideoMaxSize, fieldtag("MediaVideoMaxSize", "usage"))
cmd.Flags().Int(MediaDescriptionMinCharsFlag(), cfg.MediaDescriptionMinChars, fieldtag("MediaDescriptionMinChars", "usage"))
cmd.Flags().Int(MediaDescriptionMaxCharsFlag(), cfg.MediaDescriptionMaxChars, fieldtag("MediaDescriptionMaxChars", "usage"))
cmd.Flags().Int(MediaRemoteCacheDaysFlag(), cfg.MediaRemoteCacheDays, fieldtag("MediaRemoteCacheDays", "usage"))
// Storage
cmd.Flags().String(StorageBackendFlag(), cfg.StorageBackend, fieldtag("StorageBackend", "usage"))
cmd.Flags().String(StorageLocalBasePathFlag(), cfg.StorageLocalBasePath, fieldtag("StorageLocalBasePath", "usage"))
// Statuses
cmd.Flags().Int(StatusesMaxCharsFlag(), cfg.StatusesMaxChars, fieldtag("StatusesMaxChars", "usage"))
cmd.Flags().Int(StatusesCWMaxCharsFlag(), cfg.StatusesCWMaxChars, fieldtag("StatusesCWMaxChars", "usage"))
cmd.Flags().Int(StatusesPollMaxOptionsFlag(), cfg.StatusesPollMaxOptions, fieldtag("StatusesPollMaxOptions", "usage"))
cmd.Flags().Int(StatusesPollOptionMaxCharsFlag(), cfg.StatusesPollOptionMaxChars, fieldtag("StatusesPollOptionMaxChars", "usage"))
cmd.Flags().Int(StatusesMediaMaxFilesFlag(), cfg.StatusesMediaMaxFiles, fieldtag("StatusesMediaMaxFiles", "usage"))
// LetsEncrypt
cmd.Flags().Bool(LetsEncryptEnabledFlag(), cfg.LetsEncryptEnabled, fieldtag("LetsEncryptEnabled", "usage"))
cmd.Flags().Int(LetsEncryptPortFlag(), cfg.LetsEncryptPort, fieldtag("LetsEncryptPort", "usage"))
cmd.Flags().String(LetsEncryptCertDirFlag(), cfg.LetsEncryptCertDir, fieldtag("LetsEncryptCertDir", "usage"))
cmd.Flags().String(LetsEncryptEmailAddressFlag(), cfg.LetsEncryptEmailAddress, fieldtag("LetsEncryptEmailAddress", "usage"))
// OIDC
cmd.Flags().Bool(OIDCEnabledFlag(), cfg.OIDCEnabled, fieldtag("OIDCEnabled", "usage"))
cmd.Flags().String(OIDCIdpNameFlag(), cfg.OIDCIdpName, fieldtag("OIDCIdpName", "usage"))
cmd.Flags().Bool(OIDCSkipVerificationFlag(), cfg.OIDCSkipVerification, fieldtag("OIDCSkipVerification", "usage"))
cmd.Flags().String(OIDCIssuerFlag(), cfg.OIDCIssuer, fieldtag("OIDCIssuer", "usage"))
cmd.Flags().String(OIDCClientIDFlag(), cfg.OIDCClientID, fieldtag("OIDCClientID", "usage"))
cmd.Flags().String(OIDCClientSecretFlag(), cfg.OIDCClientSecret, fieldtag("OIDCClientSecret", "usage"))
cmd.Flags().StringSlice(OIDCScopesFlag(), cfg.OIDCScopes, fieldtag("OIDCScopes", "usage"))
// SMTP
cmd.Flags().String(SMTPHostFlag(), cfg.SMTPHost, fieldtag("SMTPHost", "usage"))
cmd.Flags().Int(SMTPPortFlag(), cfg.SMTPPort, fieldtag("SMTPPort", "usage"))
cmd.Flags().String(SMTPUsernameFlag(), cfg.SMTPUsername, fieldtag("SMTPUsername", "usage"))
cmd.Flags().String(SMTPPasswordFlag(), cfg.SMTPPassword, fieldtag("SMTPPassword", "usage"))
cmd.Flags().String(SMTPFromFlag(), cfg.SMTPFrom, fieldtag("SMTPFrom", "usage"))
// Syslog
cmd.Flags().Bool(SyslogEnabledFlag(), cfg.SyslogEnabled, fieldtag("SyslogEnabled", "usage"))
cmd.Flags().String(SyslogProtocolFlag(), cfg.SyslogProtocol, fieldtag("SyslogProtocol", "usage"))
cmd.Flags().String(SyslogAddressFlag(), cfg.SyslogAddress, fieldtag("SyslogAddress", "usage"))
})
}
// AddAdminAccount attaches flags pertaining to admin account actions.
func AddAdminAccount(cmd *cobra.Command) {
name := AdminAccountUsernameFlag()
usage := fieldtag("AdminAccountUsername", "usage")
cmd.Flags().String(name, "", usage) // REQUIRED
if err := cmd.MarkFlagRequired(name); err != nil {
panic(err)
}
}
// AddAdminAccountPassword attaches flags pertaining to admin account password reset.
func AddAdminAccountPassword(cmd *cobra.Command) {
name := AdminAccountPasswordFlag()
usage := fieldtag("AdminAccountPassword", "usage")
cmd.Flags().String(name, "", usage) // REQUIRED
if err := cmd.MarkFlagRequired(name); err != nil {
panic(err)
}
}
// AddAdminAccountCreate attaches flags pertaining to admin account creation.
func AddAdminAccountCreate(cmd *cobra.Command) {
// Requires both account and password
AddAdminAccount(cmd)
AddAdminAccountPassword(cmd)
name := AdminAccountEmailFlag()
usage := fieldtag("AdminAccountEmail", "usage")
cmd.Flags().String(name, "", usage) // REQUIRED
if err := cmd.MarkFlagRequired(name); err != nil {
panic(err)
}
}
// AddAdminTrans attaches flags pertaining to import/export commands.
func AddAdminTrans(cmd *cobra.Command) {
name := AdminTransPathFlag()
usage := fieldtag("AdminTransPath", "usage")
cmd.Flags().String(name, "", usage) // REQUIRED
if err := cmd.MarkFlagRequired(name); err != nil {
panic(err)
}
}

112
internal/config/gen/gen.go Normal file
View file

@ -0,0 +1,112 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"reflect"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
const license = `/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
`
func main() {
var (
out string
gen string
)
// Load runtime config flags
flag.StringVar(&out, "out", "", "Generated file output path")
flag.StringVar(&gen, "gen", "helpers", "Type of file to generate (helpers)")
flag.Parse()
// Open output file path
output, err := os.OpenFile(out, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
if err != nil {
panic(err)
}
switch gen {
// Generate config field helper methods
case "helpers":
fmt.Fprint(output, "// THIS IS A GENERATED FILE, DO NOT EDIT BY HAND\n")
fmt.Fprint(output, license)
fmt.Fprint(output, "package config\n\n")
t := reflect.TypeOf(config.Configuration{})
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// ConfigState structure helper methods
fmt.Fprintf(output, "// Get%s safely fetches the Configuration value for state's '%s' field\n", field.Name, field.Name)
fmt.Fprintf(output, "func (st *ConfigState) Get%s() (v %s) {\n", field.Name, field.Type.String())
fmt.Fprintf(output, "\tst.mutex.Lock()\n")
fmt.Fprintf(output, "\tv = st.config.%s\n", field.Name)
fmt.Fprintf(output, "\tst.mutex.Unlock()\n")
fmt.Fprintf(output, "\treturn\n")
fmt.Fprintf(output, "}\n\n")
fmt.Fprintf(output, "// Set%s safely sets the Configuration value for state's '%s' field\n", field.Name, field.Name)
fmt.Fprintf(output, "func (st *ConfigState) Set%s(v %s) {\n", field.Name, field.Type.String())
fmt.Fprintf(output, "\tst.mutex.Lock()\n")
fmt.Fprintf(output, "\tdefer st.mutex.Unlock()\n")
fmt.Fprintf(output, "\tst.config.%s = v\n", field.Name)
fmt.Fprintf(output, "\tst.reloadToViper()\n")
fmt.Fprintf(output, "}\n\n")
// Global ConfigState helper methods
// TODO: remove when we pass around a ConfigState{}
fmt.Fprintf(output, "// %sFlag returns the flag name for the '%s' field\n", field.Name, field.Name)
fmt.Fprintf(output, "func %sFlag() string { return \"%s\" }\n\n", field.Name, field.Tag.Get("name"))
fmt.Fprintf(output, "// Get%s safely fetches the value for global configuration '%s' field\n", field.Name, field.Name)
fmt.Fprintf(output, "func Get%[1]s() %[2]s { return global.Get%[1]s() }\n\n", field.Name, field.Type.String())
fmt.Fprintf(output, "// Set%s safely sets the value for global configuration '%s' field\n", field.Name, field.Name)
fmt.Fprintf(output, "func Set%[1]s(v %[2]s) { global.Set%[1]s(v) }\n\n", field.Name, field.Type.String())
}
_ = output.Close()
_ = exec.Command("gofmt", "-w", out).Run()
// The plain here is that eventually we might be able
// to generate an example configuration from struct tags
// Unknown type
default:
panic("unknown generation type: " + gen)
}
}

53
internal/config/global.go Normal file
View file

@ -0,0 +1,53 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
import "github.com/spf13/cobra"
var global *ConfigState
func init() {
// init global state
global = NewState()
}
// TODO: in the future we should move away from using globals in this config
// package, and instead pass the ConfigState round in a global gts state.
// Config provides you safe access to the global configuration.
func Config(fn func(cfg *Configuration)) {
global.Config(fn)
}
// Reload will reload the current configuration values from file.
func Reload() error {
return global.Reload()
}
// LoadEarlyFlags will bind specific flags from given Cobra command to global viper
// instance, and load the current configuration values. This is useful for flags like
// .ConfigPath which have to parsed first in order to perform early configuration load.
func LoadEarlyFlags(cmd *cobra.Command) error {
return global.LoadEarlyFlags(cmd)
}
// BindFlags binds given command's pflags to the global viper instance.
func BindFlags(cmd *cobra.Command) error {
return global.BindFlags(cmd)
}

File diff suppressed because it is too large Load diff

View file

@ -1,182 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
// KeyNames is a struct that just contains the names of configuration keys.
type KeyNames struct {
// root
LogLevel string
LogDbQueries string
ConfigPath string
// general
ApplicationName string
Host string
AccountDomain string
Protocol string
BindAddress string
Port string
TrustedProxies string
SoftwareVersion string
// database
DbType string
DbAddress string
DbPort string
DbUser string
DbPassword string
DbDatabase string
DbTLSMode string
DbTLSCACert string
// template
WebTemplateBaseDir string
WebAssetBaseDir string
// accounts
AccountsRegistrationOpen string
AccountsApprovalRequired string
AccountsReasonRequired string
// media
MediaImageMaxSize string
MediaVideoMaxSize string
MediaDescriptionMinChars string
MediaDescriptionMaxChars string
MediaRemoteCacheDays string
// storage
StorageBackend string
StorageLocalBasePath string
// statuses
StatusesMaxChars string
StatusesCWMaxChars string
StatusesPollMaxOptions string
StatusesPollOptionMaxChars string
StatusesMediaMaxFiles string
// letsencrypt
LetsEncryptEnabled string
LetsEncryptCertDir string
LetsEncryptEmailAddress string
LetsEncryptPort string
// oidc
OIDCEnabled string
OIDCIdpName string
OIDCSkipVerification string
OIDCIssuer string
OIDCClientID string
OIDCClientSecret string
OIDCScopes string
// smtp
SMTPHost string
SMTPPort string
SMTPUsername string
SMTPPassword string
SMTPFrom string
// syslog
SyslogEnabled string
SyslogProtocol string
SyslogAddress string
// admin
AdminAccountUsername string
AdminAccountEmail string
AdminAccountPassword string
AdminTransPath string
}
// Keys contains the names of the various keys used for initializing and storing flag variables,
// and retrieving values from the viper config store.
var Keys = KeyNames{
LogLevel: "log-level",
LogDbQueries: "log-db-queries",
ApplicationName: "application-name",
ConfigPath: "config-path",
Host: "host",
AccountDomain: "account-domain",
Protocol: "protocol",
BindAddress: "bind-address",
Port: "port",
TrustedProxies: "trusted-proxies",
SoftwareVersion: "software-version",
DbType: "db-type",
DbAddress: "db-address",
DbPort: "db-port",
DbUser: "db-user",
DbPassword: "db-password",
DbDatabase: "db-database",
DbTLSMode: "db-tls-mode",
DbTLSCACert: "db-tls-ca-cert",
WebTemplateBaseDir: "web-template-base-dir",
WebAssetBaseDir: "web-asset-base-dir",
AccountsRegistrationOpen: "accounts-registration-open",
AccountsApprovalRequired: "accounts-approval-required",
AccountsReasonRequired: "accounts-reason-required",
MediaImageMaxSize: "media-image-max-size",
MediaVideoMaxSize: "media-video-max-size",
MediaDescriptionMinChars: "media-description-min-chars",
MediaDescriptionMaxChars: "media-description-max-chars",
MediaRemoteCacheDays: "media-remote-cache-days",
StorageBackend: "storage-backend",
StorageLocalBasePath: "storage-local-base-path",
StatusesMaxChars: "statuses-max-chars",
StatusesCWMaxChars: "statuses-cw-max-chars",
StatusesPollMaxOptions: "statuses-poll-max-options",
StatusesPollOptionMaxChars: "statuses-poll-option-max-chars",
StatusesMediaMaxFiles: "statuses-media-max-files",
LetsEncryptEnabled: "letsencrypt-enabled",
LetsEncryptPort: "letsencrypt-port",
LetsEncryptCertDir: "letsencrypt-cert-dir",
LetsEncryptEmailAddress: "letsencrypt-email-address",
OIDCEnabled: "oidc-enabled",
OIDCIdpName: "oidc-idp-name",
OIDCSkipVerification: "oidc-skip-verification",
OIDCIssuer: "oidc-issuer",
OIDCClientID: "oidc-client-id",
OIDCClientSecret: "oidc-client-secret",
OIDCScopes: "oidc-scopes",
SMTPHost: "smtp-host",
SMTPPort: "smtp-port",
SMTPUsername: "smtp-username",
SMTPPassword: "smtp-password",
SMTPFrom: "smtp-from",
SyslogEnabled: "syslog-enabled",
SyslogProtocol: "syslog-protocol",
SyslogAddress: "syslog-address",
AdminAccountUsername: "username",
AdminAccountEmail: "email",
AdminAccountPassword: "password",
AdminTransPath: "path",
}

136
internal/config/state.go Normal file
View file

@ -0,0 +1,136 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
import (
"strings"
"sync"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// ConfigState manages safe concurrent access to Configuration{} values,
// and provides ease of linking them (including reloading) via viper to
// environment, CLI and configuration file variables.
type ConfigState struct { //nolint
viper *viper.Viper
config Configuration
mutex sync.Mutex
}
// NewState returns a new initialized ConfigState instance.
func NewState() *ConfigState {
viper := viper.New()
// Flag 'some-flag-name' becomes env var 'GTS_SOME_FLAG_NAME'
viper.SetEnvPrefix("gts")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
// Load appropriate named vals from env
viper.AutomaticEnv()
// Create new ConfigState with defaults
state := &ConfigState{
viper: viper,
config: Defaults,
}
// Perform initial load into viper
state.reloadToViper()
return state
}
// Config provides safe access to the ConfigState's contained Configuration,
// and will reload the current Configuration back into viper settings.
func (st *ConfigState) Config(fn func(*Configuration)) {
st.mutex.Lock()
defer func() {
st.reloadToViper()
st.mutex.Unlock()
}()
fn(&st.config)
}
// Viper provides safe access to the ConfigState's contained viper instance,
// and will reload the current viper setting state back into Configuration.
func (st *ConfigState) Viper(fn func(*viper.Viper)) {
st.mutex.Lock()
defer func() {
st.reloadFromViper()
st.mutex.Unlock()
}()
fn(st.viper)
}
// LoadEarlyFlags will bind specific flags from given Cobra command to ConfigState's viper
// instance, and load the current configuration values. This is useful for flags like
// .ConfigPath which have to parsed first in order to perform early configuration load.
func (st *ConfigState) LoadEarlyFlags(cmd *cobra.Command) (err error) {
name := ConfigPathFlag()
flag := cmd.Flags().Lookup(name)
st.Viper(func(v *viper.Viper) {
err = v.BindPFlag(name, flag)
})
return
}
// BindFlags will bind given Cobra command's pflags to this ConfigState's viper instance.
func (st *ConfigState) BindFlags(cmd *cobra.Command) (err error) {
st.Viper(func(v *viper.Viper) {
err = v.BindPFlags(cmd.Flags())
})
return
}
// Reload will reload the Configuration values from ConfigState's viper instance, and from file if set.
func (st *ConfigState) Reload() (err error) {
st.Viper(func(v *viper.Viper) {
if st.config.ConfigPath != "" {
// Ensure configuration path is set
v.SetConfigFile(st.config.ConfigPath)
// Read in configuration from file
if err = v.ReadInConfig(); err != nil {
return
}
}
})
return
}
// reloadToViper will reload Configuration{} values into viper.
func (st *ConfigState) reloadToViper() {
raw, err := st.config.MarshalMap()
if err != nil {
panic(err)
}
if err := st.viper.MergeConfigMap(raw); err != nil {
panic(err)
}
}
// reloadFromViper will reload Configuration{} values from viper.
func (st *ConfigState) reloadFromViper() {
err := st.config.UnmarshalMap(st.viper.AllSettings())
if err != nil {
panic(err)
}
}

View file

@ -24,7 +24,6 @@
"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 {

View file

@ -21,7 +21,6 @@
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")

View file

@ -1,93 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
// Values contains contains the type of each configuration value.
type Values struct {
LogLevel string
LogDbQueries bool
ApplicationName string
ConfigPath string
Host string
AccountDomain string
Protocol string
BindAddress string
Port int
TrustedProxies []string
SoftwareVersion string
DbType string
DbAddress string
DbPort int
DbUser string
DbPassword string
DbDatabase string
DbTLSMode string
DbTLSCACert string
WebTemplateBaseDir string
WebAssetBaseDir string
AccountsRegistrationOpen bool
AccountsApprovalRequired bool
AccountsReasonRequired bool
MediaImageMaxSize int
MediaVideoMaxSize int
MediaDescriptionMinChars int
MediaDescriptionMaxChars int
MediaRemoteCacheDays int
StorageBackend string
StorageLocalBasePath string
StatusesMaxChars int
StatusesCWMaxChars int
StatusesPollMaxOptions int
StatusesPollOptionMaxChars int
StatusesMediaMaxFiles int
LetsEncryptEnabled bool
LetsEncryptCertDir string
LetsEncryptEmailAddress string
LetsEncryptPort int
OIDCEnabled bool
OIDCIdpName string
OIDCSkipVerification bool
OIDCIssuer string
OIDCClientID string
OIDCClientSecret string
OIDCScopes []string
SMTPHost string
SMTPPort int
SMTPUsername string
SMTPPassword string
SMTPFrom string
SyslogEnabled bool
SyslogProtocol string
SyslogAddress string
AdminAccountUsername string
AdminAccountEmail string
AdminAccountPassword string
AdminTransPath string
}

View file

@ -1,42 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package config
import (
"strings"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func InitViper(f *pflag.FlagSet) error {
// environment variable stuff
// flag 'some-flag-name' becomes env var 'GTS_SOME_FLAG_NAME'
viper.SetEnvPrefix("gts")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv()
// flag stuff
// bind all of the flags in flagset to viper so that we can retrieve their values from the viper store
if err := viper.BindPFlags(f); err != nil {
return err
}
return nil
}

View file

@ -25,7 +25,6 @@
"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"))
}

View file

@ -30,7 +30,6 @@
"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.

View file

@ -35,7 +35,6 @@
"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 {

View file

@ -22,7 +22,6 @@
"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)

View file

@ -23,7 +23,6 @@
"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
}

View file

@ -22,7 +22,6 @@
"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.

View file

@ -23,7 +23,6 @@
"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)
}

View file

@ -23,7 +23,6 @@
"text/template"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@ -32,7 +31,7 @@
//
// 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 {

View file

@ -23,7 +23,6 @@
"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),

View file

@ -29,7 +29,6 @@
"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 := &gtsmodel.Account{}
requestingLocalAccount := &gtsmodel.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)

View file

@ -24,7 +24,6 @@
"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 @@ func (d *deref) iterateDescendants(ctx context.Context, username string, statusI
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
}

View file

@ -23,7 +23,6 @@
"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)

View file

@ -24,7 +24,6 @@
"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
}

View file

@ -24,7 +24,6 @@
"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

View file

@ -26,7 +26,6 @@
"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.

View file

@ -26,7 +26,6 @@
"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 {

View file

@ -26,7 +26,6 @@
"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)

View file

@ -26,7 +26,6 @@
"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)

View file

@ -23,7 +23,6 @@
"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

View file

@ -23,7 +23,6 @@
"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

View file

@ -25,7 +25,6 @@
"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)
}

View file

@ -23,7 +23,6 @@
"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,

View file

@ -23,7 +23,6 @@
"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 @@
)
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,

View file

@ -22,7 +22,6 @@
"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

View file

@ -22,7 +22,6 @@
"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 := &gtsmodel.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))
}

View file

@ -25,7 +25,6 @@
"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 := &gtsmodel.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)

View file

@ -25,7 +25,6 @@
"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,

View file

@ -25,7 +25,6 @@
"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 @@
"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 := &gtsmodel.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)
}

View file

@ -27,7 +27,6 @@
"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),

View file

@ -28,7 +28,6 @@
"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 @@
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

View file

@ -21,7 +21,6 @@
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)

View file

@ -26,16 +26,15 @@
"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)

View file

@ -25,13 +25,11 @@
"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
}

View file

@ -27,7 +27,6 @@
"strings"
"sync"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@ -69,7 +68,7 @@ func (t *transport) BatchDeliver(ctx context.Context, b []byte, recipients []*ur
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
}

View file

@ -25,7 +25,6 @@
"net/http"
"net/url"
"github.com/spf13/viper"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/uris"
)
@ -33,7 +32,7 @@
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)

View file

@ -26,7 +26,6 @@
"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 {

View file

@ -24,7 +24,6 @@
"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

View file

@ -22,7 +22,6 @@
"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)
}

View file

@ -27,7 +27,6 @@
"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)

View file

@ -23,7 +23,6 @@
"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()})

View file

@ -27,7 +27,6 @@
"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()})

View file

@ -23,7 +23,6 @@
"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)

View file

@ -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"

View file

@ -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",

View file

@ -24,7 +24,6 @@
"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 @@
// 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())

View file

@ -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 @@
// 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)

View file

@ -26,7 +26,6 @@
"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 @@
// 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