From b1a4d54c14647827aaf3c8174e2896b12d0f9608 Mon Sep 17 00:00:00 2001 From: kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:32:13 +0000 Subject: [PATCH] [chore] add IPPrefixes type so we don't need separate rate limit parsed field (#3982) * add IPPrefixes type so we don't need separate rate limit parsed field * sshhhh please linter, mommy's working --- cmd/gotosocial/action/server/server.go | 9 ++-- internal/api/util/template.go | 2 +- internal/config/config.go | 18 ++++---- internal/config/defaults.go | 2 +- internal/config/flags.go | 2 +- internal/config/gen/gen.go | 1 - internal/config/helpers.gen.go | 38 ++-------------- internal/config/types.go | 62 ++++++++++++++++++++++++++ internal/config/validate.go | 18 -------- test/envparsing.sh | 1 - 10 files changed, 82 insertions(+), 71 deletions(-) create mode 100644 internal/config/types.go diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go index f934aaadd..4caf44cad 100644 --- a/cmd/gotosocial/action/server/server.go +++ b/cmd/gotosocial/action/server/server.go @@ -530,10 +530,11 @@ var Start action.GTSAction = func(ctx context.Context) error { // Create per-route / per-grouping middlewares. // rate limiting rlLimit := config.GetAdvancedRateLimitRequests() - clLimit := middleware.RateLimit(rlLimit, config.GetAdvancedRateLimitExceptionsParsed()) // client api - s2sLimit := middleware.RateLimit(rlLimit, config.GetAdvancedRateLimitExceptionsParsed()) // server-to-server (AP) - fsMainLimit := middleware.RateLimit(rlLimit, config.GetAdvancedRateLimitExceptionsParsed()) // fileserver / web templates - fsEmojiLimit := middleware.RateLimit(rlLimit*2, config.GetAdvancedRateLimitExceptionsParsed()) // fileserver (emojis only, use high limit) + exceptions := config.GetAdvancedRateLimitExceptions() + clLimit := middleware.RateLimit(rlLimit, exceptions) // client api + s2sLimit := middleware.RateLimit(rlLimit, exceptions) // server-to-server (AP) + fsMainLimit := middleware.RateLimit(rlLimit, exceptions) // fileserver / web templates + fsEmojiLimit := middleware.RateLimit(rlLimit*2, exceptions) // fileserver (emojis only, use high limit) // throttling cpuMultiplier := config.GetAdvancedThrottlingMultiplier() diff --git a/internal/api/util/template.go b/internal/api/util/template.go index 38e79484f..86d179cdc 100644 --- a/internal/api/util/template.go +++ b/internal/api/util/template.go @@ -171,7 +171,7 @@ func injectTrustedProxiesRec( return } - except := config.GetAdvancedRateLimitExceptionsParsed() + except := config.GetAdvancedRateLimitExceptions() for _, prefix := range except { if prefix.Contains(ip) { // This ip is exempt from diff --git a/internal/config/config.go b/internal/config/config.go index 8ce2105b4..d4b3901e7 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -18,7 +18,6 @@ package config import ( - "net/netip" "reflect" "time" @@ -168,15 +167,14 @@ type Configuration struct { 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."` - AdvancedCookiesSamesite string `name:"advanced-cookies-samesite" usage:"'strict' or 'lax', see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite"` - AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."` - AdvancedRateLimitExceptions []string `name:"advanced-rate-limit-exceptions" usage:"Slice of CIDRs to exclude from rate limit restrictions."` - AdvancedRateLimitExceptionsParsed []netip.Prefix `name:"advanced-rate-limit-exceptions-parsed"` - AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."` - AdvancedThrottlingRetryAfter time.Duration `name:"advanced-throttling-retry-after" usage:"Retry-After duration response to send for throttled requests."` - AdvancedSenderMultiplier int `name:"advanced-sender-multiplier" usage:"Multiplier to use per cpu for batching outgoing fedi messages. 0 or less turns batching off (not recommended)."` - AdvancedCSPExtraURIs []string `name:"advanced-csp-extra-uris" usage:"Additional URIs to allow when building content-security-policy for media + images."` - AdvancedHeaderFilterMode string `name:"advanced-header-filter-mode" usage:"Set incoming request header filtering mode."` + AdvancedCookiesSamesite string `name:"advanced-cookies-samesite" usage:"'strict' or 'lax', see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite"` + AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."` + AdvancedRateLimitExceptions IPPrefixes `name:"advanced-rate-limit-exceptions" usage:"Slice of CIDRs to exclude from rate limit restrictions."` + AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."` + AdvancedThrottlingRetryAfter time.Duration `name:"advanced-throttling-retry-after" usage:"Retry-After duration response to send for throttled requests."` + AdvancedSenderMultiplier int `name:"advanced-sender-multiplier" usage:"Multiplier to use per cpu for batching outgoing fedi messages. 0 or less turns batching off (not recommended)."` + AdvancedCSPExtraURIs []string `name:"advanced-csp-extra-uris" usage:"Additional URIs to allow when building content-security-policy for media + images."` + AdvancedHeaderFilterMode string `name:"advanced-header-filter-mode" usage:"Set incoming request header filtering mode."` // HTTPClient configuration vars. HTTPClient HTTPClientConfiguration `name:"http-client"` diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 78a8230d5..9a507b421 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -136,7 +136,7 @@ var Defaults = Configuration{ AdvancedCookiesSamesite: "lax", AdvancedRateLimitRequests: 300, // 1 per second per 5 minutes - AdvancedRateLimitExceptions: []string{}, + AdvancedRateLimitExceptions: IPPrefixes{}, AdvancedThrottlingMultiplier: 8, // 8 open requests per CPU AdvancedThrottlingRetryAfter: time.Second * 30, AdvancedSenderMultiplier: 2, // 2 senders per CPU diff --git a/internal/config/flags.go b/internal/config/flags.go index 3a2564c94..eaf16990c 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -156,7 +156,7 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) { // Advanced flags cmd.Flags().String(AdvancedCookiesSamesiteFlag(), cfg.AdvancedCookiesSamesite, fieldtag("AdvancedCookiesSamesite", "usage")) cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage")) - cmd.Flags().StringSlice(AdvancedRateLimitExceptionsFlag(), cfg.AdvancedRateLimitExceptions, fieldtag("AdvancedRateLimitExceptions", "usage")) + cmd.Flags().StringSlice(AdvancedRateLimitExceptionsFlag(), cfg.AdvancedRateLimitExceptions.Strings(), fieldtag("AdvancedRateLimitExceptions", "usage")) cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage")) cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage")) cmd.Flags().Int(AdvancedSenderMultiplierFlag(), cfg.AdvancedSenderMultiplier, fieldtag("AdvancedSenderMultiplier", "usage")) diff --git a/internal/config/gen/gen.go b/internal/config/gen/gen.go index a3742ee15..9130f8606 100644 --- a/internal/config/gen/gen.go +++ b/internal/config/gen/gen.go @@ -65,7 +65,6 @@ func main() { fmt.Fprint(output, license) fmt.Fprint(output, "package config\n\n") fmt.Fprint(output, "import (\n") - fmt.Fprint(output, "\t\"net/netip\"\n") fmt.Fprint(output, "\t\"time\"\n\n") fmt.Fprint(output, "\t\"codeberg.org/gruf/go-bytesize\"\n") fmt.Fprint(output, "\t\"github.com/superseriousbusiness/gotosocial/internal/language\"\n") diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go index 156c19fd5..ac41a73e9 100644 --- a/internal/config/helpers.gen.go +++ b/internal/config/helpers.gen.go @@ -19,7 +19,6 @@ package config import ( - "net/netip" "time" "codeberg.org/gruf/go-bytesize" @@ -2758,7 +2757,7 @@ func GetAdvancedRateLimitRequests() int { return global.GetAdvancedRateLimitRequ func SetAdvancedRateLimitRequests(v int) { global.SetAdvancedRateLimitRequests(v) } // GetAdvancedRateLimitExceptions safely fetches the Configuration value for state's 'AdvancedRateLimitExceptions' field -func (st *ConfigState) GetAdvancedRateLimitExceptions() (v []string) { +func (st *ConfigState) GetAdvancedRateLimitExceptions() (v IPPrefixes) { st.mutex.RLock() v = st.config.AdvancedRateLimitExceptions st.mutex.RUnlock() @@ -2766,7 +2765,7 @@ func (st *ConfigState) GetAdvancedRateLimitExceptions() (v []string) { } // SetAdvancedRateLimitExceptions safely sets the Configuration value for state's 'AdvancedRateLimitExceptions' field -func (st *ConfigState) SetAdvancedRateLimitExceptions(v []string) { +func (st *ConfigState) SetAdvancedRateLimitExceptions(v IPPrefixes) { st.mutex.Lock() defer st.mutex.Unlock() st.config.AdvancedRateLimitExceptions = v @@ -2777,39 +2776,10 @@ func (st *ConfigState) SetAdvancedRateLimitExceptions(v []string) { func AdvancedRateLimitExceptionsFlag() string { return "advanced-rate-limit-exceptions" } // GetAdvancedRateLimitExceptions safely fetches the value for global configuration 'AdvancedRateLimitExceptions' field -func GetAdvancedRateLimitExceptions() []string { return global.GetAdvancedRateLimitExceptions() } +func GetAdvancedRateLimitExceptions() IPPrefixes { return global.GetAdvancedRateLimitExceptions() } // SetAdvancedRateLimitExceptions safely sets the value for global configuration 'AdvancedRateLimitExceptions' field -func SetAdvancedRateLimitExceptions(v []string) { global.SetAdvancedRateLimitExceptions(v) } - -// GetAdvancedRateLimitExceptionsParsed safely fetches the Configuration value for state's 'AdvancedRateLimitExceptionsParsed' field -func (st *ConfigState) GetAdvancedRateLimitExceptionsParsed() (v []netip.Prefix) { - st.mutex.RLock() - v = st.config.AdvancedRateLimitExceptionsParsed - st.mutex.RUnlock() - return -} - -// SetAdvancedRateLimitExceptionsParsed safely sets the Configuration value for state's 'AdvancedRateLimitExceptionsParsed' field -func (st *ConfigState) SetAdvancedRateLimitExceptionsParsed(v []netip.Prefix) { - st.mutex.Lock() - defer st.mutex.Unlock() - st.config.AdvancedRateLimitExceptionsParsed = v - st.reloadToViper() -} - -// AdvancedRateLimitExceptionsParsedFlag returns the flag name for the 'AdvancedRateLimitExceptionsParsed' field -func AdvancedRateLimitExceptionsParsedFlag() string { return "advanced-rate-limit-exceptions-parsed" } - -// GetAdvancedRateLimitExceptionsParsed safely fetches the value for global configuration 'AdvancedRateLimitExceptionsParsed' field -func GetAdvancedRateLimitExceptionsParsed() []netip.Prefix { - return global.GetAdvancedRateLimitExceptionsParsed() -} - -// SetAdvancedRateLimitExceptionsParsed safely sets the value for global configuration 'AdvancedRateLimitExceptionsParsed' field -func SetAdvancedRateLimitExceptionsParsed(v []netip.Prefix) { - global.SetAdvancedRateLimitExceptionsParsed(v) -} +func SetAdvancedRateLimitExceptions(v IPPrefixes) { global.SetAdvancedRateLimitExceptions(v) } // GetAdvancedThrottlingMultiplier safely fetches the Configuration value for state's 'AdvancedThrottlingMultiplier' field func (st *ConfigState) GetAdvancedThrottlingMultiplier() (v int) { diff --git a/internal/config/types.go b/internal/config/types.go new file mode 100644 index 000000000..c2296975f --- /dev/null +++ b/internal/config/types.go @@ -0,0 +1,62 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package config + +import ( + "net/netip" + + "codeberg.org/gruf/go-byteutil" +) + +// IPPrefixes is a type-alias for []netip.Prefix +// to allow parsing by CLI "flag"-like utilities. +type IPPrefixes []netip.Prefix + +func (p *IPPrefixes) Set(in string) error { + prefix, err := netip.ParsePrefix(in) + if err != nil { + return err + } + (*p) = append((*p), prefix) + return nil +} + +func (p *IPPrefixes) String() string { + if p == nil || len(*p) == 0 { + return "" + } + var buf byteutil.Buffer + for _, prefix := range *p { + str := prefix.String() + buf.B = append(buf.B, str...) + buf.B = append(buf.B, ',') + } + buf.Truncate(1) + return buf.String() +} + +func (p *IPPrefixes) Strings() []string { + if p == nil || len(*p) == 0 { + return nil + } + strs := make([]string, len(*p)) + for i, prefix := range *p { + strs[i] = prefix.String() + } + return strs +} diff --git a/internal/config/validate.go b/internal/config/validate.go index a4ed08106..d36d18ba4 100644 --- a/internal/config/validate.go +++ b/internal/config/validate.go @@ -19,7 +19,6 @@ package config import ( "fmt" - "net/netip" "net/url" "strings" @@ -182,22 +181,5 @@ func Validate() error { ) } - // Parse `advanced-rate-limit-exceptions` and set - // parsed versions on config to avoid reparsing calls. - rles := GetAdvancedRateLimitExceptions() - rlesParsed := make([]netip.Prefix, 0, len(rles)) - for _, rle := range rles { - parsed, err := netip.ParsePrefix(rle) - if err != nil { - errf( - "invalid entry %s in %s: %w", - rle, AdvancedRateLimitExceptionsFlag(), err, - ) - continue - } - rlesParsed = append(rlesParsed, parsed) - } - SetAdvancedRateLimitExceptionsParsed(rlesParsed) - return errs.Combine() } diff --git a/test/envparsing.sh b/test/envparsing.sh index fc6afbcc2..66295f1f6 100755 --- a/test/envparsing.sh +++ b/test/envparsing.sh @@ -18,7 +18,6 @@ EXPECT=$(cat << "EOF" "192.0.2.0/24", "127.0.0.1/32" ], - "advanced-rate-limit-exceptions-parsed": null, "advanced-rate-limit-requests": 6969, "advanced-sender-multiplier": -1, "advanced-throttling-multiplier": -1,