diff --git a/docs/configuration/instance.md b/docs/configuration/instance.md index bffec8f70..2a945eed2 100644 --- a/docs/configuration/instance.md +++ b/docs/configuration/instance.md @@ -171,4 +171,17 @@ instance-subscriptions-process-every: "24h" # Options: ["", "zero", "serve", "baffle"] # Default: "" instance-stats-mode: "" + +# Bool. This flag controls whether local accounts may backdate statuses +# using past dates with the scheduled_at param to /api/v1/statuses. +# This flag does not affect scheduling posts in the future +# (which is currently not implemented anyway), +# nor can it prevent remote accounts from backdating their own statuses. +# +# If true, all local accounts may backdate statuses. +# If false, status backdating will be disabled and an error will be returned if it's used. +# +# Options: [true, false] +# Default: true +instance-allow-backdating-statuses: true ``` diff --git a/example/config.yaml b/example/config.yaml index b618ad7ba..2b3a873fb 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -458,6 +458,19 @@ instance-subscriptions-process-every: "24h" # Default: "" instance-stats-mode: "" +# Bool. This flag controls whether local accounts may backdate statuses +# using past dates with the scheduled_at param to /api/v1/statuses. +# This flag does not affect scheduling posts in the future +# (which is currently not implemented anyway), +# nor can it prevent remote accounts from backdating their own statuses. +# +# If true, all local accounts may backdate statuses. +# If false, status backdating will be disabled and an error will be returned if it's used. +# +# Options: [true, false] +# Default: true +instance-allow-backdating-statuses: true + ########################### ##### ACCOUNTS CONFIG ##### ########################### diff --git a/internal/config/config.go b/internal/config/config.go index 33003d0f9..8ce2105b4 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -91,6 +91,7 @@ type Configuration struct { InstanceSubscriptionsProcessFrom string `name:"instance-subscriptions-process-from" usage:"Time of day from which to start running instance subscriptions processing jobs. Should be in the format 'hh:mm:ss', eg., '15:04:05'."` InstanceSubscriptionsProcessEvery time.Duration `name:"instance-subscriptions-process-every" usage:"Period to elapse between instance subscriptions processing jobs, starting from instance-subscriptions-process-from."` InstanceStatsMode string `name:"instance-stats-mode" usage:"Allows you to customize the way stats are served to crawlers: one of '', 'serve', 'zero', 'baffle'. Home page stats remain unchanged."` + InstanceAllowBackdatingStatuses bool `name:"instance-allow-backdating-statuses" usage:"Allow local accounts to backdate statuses using the scheduled_at param to /api/v1/statuses"` AccountsRegistrationOpen bool `name:"accounts-registration-open" usage:"Allow anyone to submit an account signup request. If false, server will be invite-only."` AccountsReasonRequired bool `name:"accounts-reason-required" usage:"Do new account signups require a reason to be submitted on registration?"` diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 7f66e4209..78a8230d5 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -67,6 +67,7 @@ var Defaults = Configuration{ InstanceLanguages: make(language.Languages, 0), InstanceSubscriptionsProcessFrom: "23:00", // 11pm, InstanceSubscriptionsProcessEvery: 24 * time.Hour, // 1/day. + InstanceAllowBackdatingStatuses: true, AccountsRegistrationOpen: false, AccountsReasonRequired: true, diff --git a/internal/config/flags.go b/internal/config/flags.go index d67085d6d..3a2564c94 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -93,6 +93,7 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) { cmd.Flags().String(InstanceSubscriptionsProcessFromFlag(), cfg.InstanceSubscriptionsProcessFrom, fieldtag("InstanceSubscriptionsProcessFrom", "usage")) cmd.Flags().Duration(InstanceSubscriptionsProcessEveryFlag(), cfg.InstanceSubscriptionsProcessEvery, fieldtag("InstanceSubscriptionsProcessEvery", "usage")) cmd.Flags().String(InstanceStatsModeFlag(), cfg.InstanceStatsMode, fieldtag("InstanceStatsMode", "usage")) + cmd.Flags().Bool(InstanceAllowBackdatingStatusesFlag(), cfg.InstanceAllowBackdatingStatuses, fieldtag("InstanceAllowBackdatingStatuses", "usage")) // Accounts cmd.Flags().Bool(AccountsRegistrationOpenFlag(), cfg.AccountsRegistrationOpen, fieldtag("AccountsRegistrationOpen", "usage")) diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go index d3ccf16ea..156c19fd5 100644 --- a/internal/config/helpers.gen.go +++ b/internal/config/helpers.gen.go @@ -1082,6 +1082,31 @@ func GetInstanceStatsMode() string { return global.GetInstanceStatsMode() } // SetInstanceStatsMode safely sets the value for global configuration 'InstanceStatsMode' field func SetInstanceStatsMode(v string) { global.SetInstanceStatsMode(v) } +// GetInstanceAllowBackdatingStatuses safely fetches the Configuration value for state's 'InstanceAllowBackdatingStatuses' field +func (st *ConfigState) GetInstanceAllowBackdatingStatuses() (v bool) { + st.mutex.RLock() + v = st.config.InstanceAllowBackdatingStatuses + st.mutex.RUnlock() + return +} + +// SetInstanceAllowBackdatingStatuses safely sets the Configuration value for state's 'InstanceAllowBackdatingStatuses' field +func (st *ConfigState) SetInstanceAllowBackdatingStatuses(v bool) { + st.mutex.Lock() + defer st.mutex.Unlock() + st.config.InstanceAllowBackdatingStatuses = v + st.reloadToViper() +} + +// InstanceAllowBackdatingStatusesFlag returns the flag name for the 'InstanceAllowBackdatingStatuses' field +func InstanceAllowBackdatingStatusesFlag() string { return "instance-allow-backdating-statuses" } + +// GetInstanceAllowBackdatingStatuses safely fetches the value for global configuration 'InstanceAllowBackdatingStatuses' field +func GetInstanceAllowBackdatingStatuses() bool { return global.GetInstanceAllowBackdatingStatuses() } + +// SetInstanceAllowBackdatingStatuses safely sets the value for global configuration 'InstanceAllowBackdatingStatuses' field +func SetInstanceAllowBackdatingStatuses(v bool) { global.SetInstanceAllowBackdatingStatuses(v) } + // GetAccountsRegistrationOpen safely fetches the Configuration value for state's 'AccountsRegistrationOpen' field func (st *ConfigState) GetAccountsRegistrationOpen() (v bool) { st.mutex.RLock() diff --git a/internal/processing/status/create.go b/internal/processing/status/create.go index 0e0a851bc..46052d0aa 100644 --- a/internal/processing/status/create.go +++ b/internal/processing/status/create.go @@ -24,6 +24,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/ap" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtscontext" "github.com/superseriousbusiness/gotosocial/internal/gtserror" @@ -111,6 +112,25 @@ func (p *Processor) Create( } // If not scheduled into the future, this status is being backfilled. + if !config.GetInstanceAllowBackdatingStatuses() { + const errText = "backdating statuses has been disabled on this instance" + err := gtserror.New(errText) + return nil, gtserror.NewErrorForbidden(err) + } + + // Statuses can't be backdated to or before the UNIX epoch + // since this would prevent generating a ULID. + // If backdated even further to the Go epoch, + // this would also cause issues with time.Time.IsZero() checks + // that normally signify an absent optional time, + // but this check covers both cases. + if scheduledAt.Compare(time.UnixMilli(0)) <= 0 { + const errText = "statuses can't be backdated to or before the UNIX epoch" + err := gtserror.New(errText) + return nil, gtserror.NewErrorNotAcceptable(err, errText) + } + + // Allow the backfill and generate an appropriate ID for the creation time. backfill = true createdAt = scheduledAt var err error diff --git a/test/envparsing.sh b/test/envparsing.sh index 0e7c0db20..fc6afbcc2 100755 --- a/test/envparsing.sh +++ b/test/envparsing.sh @@ -108,6 +108,7 @@ EXPECT=$(cat << "EOF" "timeout": 30000000000, "tls-insecure-skip-verify": false }, + "instance-allow-backdating-statuses": true, "instance-deliver-to-shared-inboxes": false, "instance-expose-peers": true, "instance-expose-public-timeline": true, diff --git a/testrig/config.go b/testrig/config.go index f68a8ffb7..9f17530c4 100644 --- a/testrig/config.go +++ b/testrig/config.go @@ -101,6 +101,7 @@ func testDefaults() config.Configuration { }, InstanceSubscriptionsProcessFrom: "23:00", // 11pm, InstanceSubscriptionsProcessEvery: 24 * time.Hour, // 1/day. + InstanceAllowBackdatingStatuses: true, AccountsRegistrationOpen: true, AccountsReasonRequired: true,