diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go index 7a4b315da..70d8cd4dc 100644 --- a/cmd/gotosocial/action/server/server.go +++ b/cmd/gotosocial/action/server/server.go @@ -184,20 +184,29 @@ ) // create required middleware + // rate limiting limit := config.GetAdvancedRateLimitRequests() - gzip := middleware.Gzip() // all except fileserver clLimit := middleware.RateLimit(limit) // client api s2sLimit := middleware.RateLimit(limit) // server-to-server (AP) fsLimit := middleware.RateLimit(limit) // fileserver / web templates - // these should be routed in order - authModule.Route(router, clLimit, gzip) - clientModule.Route(router, clLimit, gzip) - fileserverModule.Route(router, fsLimit) - wellKnownModule.Route(router, gzip, s2sLimit) - nodeInfoModule.Route(router, s2sLimit, gzip) - activityPubModule.Route(router, s2sLimit, gzip) - webModule.Route(router, fsLimit, gzip) + // throttling + cpuMultiplier := config.GetAdvancedThrottlingMultiplier() + clThrottle := middleware.Throttle(cpuMultiplier) // client api + s2sThrottle := middleware.Throttle(cpuMultiplier) // server-to-server (AP) + fsThrottle := middleware.Throttle(cpuMultiplier) // fileserver / web templates + + gzip := middleware.Gzip() // applied to all except fileserver + + // these should be routed in order; + // apply throttling *after* rate limiting + authModule.Route(router, clLimit, clThrottle, gzip) + clientModule.Route(router, clLimit, clThrottle, gzip) + fileserverModule.Route(router, fsLimit, fsThrottle) + wellKnownModule.Route(router, gzip, s2sLimit, s2sThrottle) + nodeInfoModule.Route(router, s2sLimit, s2sThrottle, gzip) + activityPubModule.Route(router, s2sLimit, s2sThrottle, gzip) + webModule.Route(router, fsLimit, fsThrottle, gzip) gts, err := gotosocial.NewServer(dbService, router, federator, mediaManager) if err != nil { diff --git a/docs/api/ratelimiting.md b/docs/api/ratelimiting.md index 09b554093..2bdcdf2ba 100644 --- a/docs/api/ratelimiting.md +++ b/docs/api/ratelimiting.md @@ -1,4 +1,4 @@ -# Rate Limit +# Request Rate Limiting To mitigate abuse + scraping of your instance, IP-based HTTP rate limiting is in place. diff --git a/docs/api/throttling.md b/docs/api/throttling.md new file mode 100644 index 000000000..a2386053a --- /dev/null +++ b/docs/api/throttling.md @@ -0,0 +1,35 @@ +# Request Throttling + +GoToSocial uses request throttling to limit the number of open connections to the API of your instance. This is designed to prevent your instance from accidentally being DDOS'd (aka [the hug of death](https://en.wikipedia.org/wiki/Slashdot_effect)) if a post gets boosted or replied to by an account with many thousands of followers. + +Throttling means that only a limited number of HTTP requests to the API will be handled concurrently, in order to provide a snappy response to each request and move on quickly. The rationale is that it's better to handle fewer requests quickly, than to try to handle all incoming requests at once and take multiple seconds per request. + +Throttling limits are applied across router groups, similar to the way that [rate limiting](./ratelimiting.md) is organized, so if one part of the API is currently being throttled, that doesn't mean they all are. + +Throttling limits are calculated based on the number of CPUs available to GoToSocial, and the configuration value `advanced-throttling-multiplier`. The calculation is performed as follows: + +- In-process queue limit = number of CPUs * CPU multiplier. +- Backlog queue limit = in-process queue limit * CPU multiplier. + +This leads to the following values for the default multiplier (8): + +```text +1 cpu = 08 in-process, 064 backlog +2 cpu = 16 in-process, 128 backlog +4 cpu = 32 in-process, 256 backlog +8 cpu = 64 in-process, 512 backlog +``` + +New requests that overflow the in-process limit are held in the backlog queue, and processed as soon as a spot is freed up (ie., when a currently in-process request is finished). Requests that cannot be processed, and cannot fit in the backlog queue will be responded to with http code [503 - Service Unavailable](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503), and the `Retry-After` header will be set to `30` (seconds), to indicate that the caller should try again later. + +Requests are not held in the backlog queue indefinitely: if requests in the backlog cannot be processed within 30 seconds of being received, they will also receive a code 503 and a 30s retry-after. + +## Throttling FAQs + +### Can I tune the request throttling? + +Yes, just change the value of `advanced-throttling-multiplier` higher (if you have very powerful CPUs) or lower (if you have relatively less powerful CPUs). + +### Can I disable the request throttling? + +Yes. To do so, just set `advanced-throttling-multiplier` to `0` or less. This will disable HTTP request throttling entirely, and instead attempt to process all incoming requests at once. This is useful in cases where you want to do request throttling using an external service or a reverse-proxy, and you don't want GoToSocial to interfere with your setup. diff --git a/docs/configuration/advanced.md b/docs/configuration/advanced.md index f4b8c5ffa..7cf962903 100644 --- a/docs/configuration/advanced.md +++ b/docs/configuration/advanced.md @@ -36,9 +36,8 @@ These are set to sensible defaults, so most server admins won't need to touch th # Default: "lax" advanced-cookies-samesite: "lax" -# Int. Amount of requests to permit from a single IP address within a span of 5 minutes. -# If this amount is exceeded, a 429 HTTP error code will be returned. -# See https://docs.gotosocial.org/en/latest/api/swagger/#rate-limit. +# Int. Amount of requests to permit per router grouping from a single IP address within +# a span of 5 minutes. If this amount is exceeded, a 429 HTTP error code will be returned. # # If you find yourself adjusting this limit because it's regularly being exceeded, # you should first verify that your settings for `trusted-proxies` (above) are correct. @@ -50,6 +49,34 @@ advanced-cookies-samesite: "lax" # If you set this to 0 or less, rate limiting will be disabled entirely. # # Examples: [1000, 500, 0] -# Default: 1000 -advanced-rate-limit-requests: 1000 +# Default: 300 +advanced-rate-limit-requests: 300 + +# Int. Amount of open requests to permit per CPU, per router grouping, before applying http +# request throttling. Any requests beyond the calculated limit are held in a backlog queue for +# up to 30 seconds before either being processed or timing out. Requests that don't fit in the backlog +# queue will have status 503 returned to them, and the header 'Retry-After' will be set to 30 seconds. +# +# Open request limit is available CPUs * multiplier; backlog queue limit is limit * multiplier. +# +# Example values for multiplier 8: +# +# 1 cpu = 08 open, 064 backlog +# 2 cpu = 16 open, 128 backlog +# 4 cpu = 32 open, 256 backlog +# +# Example values for multiplier 4: +# +# 1 cpu = 04 open, 016 backlog +# 2 cpu = 08 open, 032 backlog +# 4 cpu = 16 open, 064 backlog +# +# A multiplier of 8 is a sensible default, but you may wish to increase this for instances +# running on very performant hardware, or decrease it for instances using v. slow CPUs. +# +# If you set this to 0 or less, http request throttling will be disabled entirely. +# +# Examples: [8, 4, 9, 0] +# Default: 8 +advanced-throttling-multiplier: 8 ``` diff --git a/docs/faq.md b/docs/faq.md index 1d523ee69..b5e1d0e8e 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -8,7 +8,9 @@ - **Why aren't my posts showing up on other servers?** First check the visibility as noted above. TODO: explain how to debug common federation issues -- **Why am I getting frequent error responses?** GoToSocial is configured to use per-IP [rate limiting](https://docs.gotosocial.org/en/latest/api/ratelimiting/) by default, but in certain situations it can't accurately identify the remote IP and will treat all connections as coming from the same place. In those cases, the rate limiting needs to be disabled or reconfigured. +- **Why am I getting frequent http 429 error responses?** GoToSocial is configured to use per-IP [rate limiting](./api/ratelimiting.md) by default, but in certain situations it can't accurately identify the remote IP and will treat all connections as coming from the same place. In those cases, the rate limiting needs to be disabled or reconfigured. + +- **Why am I getting frequent http 503 error responses?** Code 503 is returned to callers when your instance is under heavy load and requests are being throttled. This behavior can be tuned as desired, or turned off entirely, see [here](./api/throttling.md). - **My instance is deployed and I'm logged in to a client but my timelines are empty, what's up there?** To see posts, you have to start following people! Once you've followed a few people and they've posted or boosted things, you'll start seeing them in your timelines. Right now GoToSocial doesn't have a way of 'backfilling' posts -- that is, fetching previous posts from other instances -- so you'll only see new posts of people you follow. If you want to interact with an older post of theirs, you can copy the link to the post from their web profile, and paste it in to your client's search bar. diff --git a/docs/federation/behaviors/request_throttling.md b/docs/federation/behaviors/request_throttling.md new file mode 100644 index 000000000..e44e26811 --- /dev/null +++ b/docs/federation/behaviors/request_throttling.md @@ -0,0 +1,3 @@ +# Request Throttling and Rate Limiting + +GoToSocial applies rate limiting and http request throttling to the ActivityPub API endpoints (inboxes, user endpoints, emojis, etc). For more details on this, please see the [throttling](../../api/throttling.md) and [rate limiting](../../api/ratelimiting.md) documents. diff --git a/docs/index.md b/docs/index.md index 911768cc2..3d75eb1ac 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,7 +34,7 @@ It began as a solo project, and then picked up steam as more developers became i ## Known Issues -Since GoToSocial is still in alpha, there are plenty of bugs. We use [GitHub issues](https://github.com/superseriousbusiness/gotosocial/issues?q=is%3Aissue+is%3Aopen+label%3Abug) to track these. The [FAQ](docs/faq.md) also describes some of the features that haven't been implemented yet. +Since GoToSocial is still in alpha, there are plenty of bugs. We use [GitHub issues](https://github.com/superseriousbusiness/gotosocial/issues?q=is%3Aissue+is%3Aopen+label%3Abug) to track these. The [FAQ](./faq.md) also describes some of the features that haven't been implemented yet. ### Client App Issues diff --git a/example/config.yaml b/example/config.yaml index 03c9c74cd..5a6634317 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -644,9 +644,6 @@ advanced-cookies-samesite: "lax" # Int. Amount of requests to permit per router grouping from a single IP address within # a span of 5 minutes. If this amount is exceeded, a 429 HTTP error code will be returned. # -# Router groupings and rate limit headers are described here: -# https://docs.gotosocial.org/en/latest/api/swagger/#rate-limit. -# # If you find yourself adjusting this limit because it's regularly being exceeded, # you should first verify that your settings for `trusted-proxies` (above) are correct. # In many cases, when the rate limit is exceeded it is because your instance sees all @@ -659,3 +656,31 @@ advanced-cookies-samesite: "lax" # Examples: [1000, 500, 0] # Default: 300 advanced-rate-limit-requests: 300 + +# Int. Amount of open requests to permit per CPU, per router grouping, before applying http +# request throttling. Any requests beyond the calculated limit are held in a backlog queue for +# up to 30 seconds before either being processed or timing out. Requests that don't fit in the backlog +# queue will have status 503 returned to them, and the header 'Retry-After' will be set to 30 seconds. +# +# Open request limit is available CPUs * multiplier; backlog queue limit is limit * multiplier. +# +# Example values for multiplier 8: +# +# 1 cpu = 08 open, 064 backlog +# 2 cpu = 16 open, 128 backlog +# 4 cpu = 32 open, 256 backlog +# +# Example values for multiplier 4: +# +# 1 cpu = 04 open, 016 backlog +# 2 cpu = 08 open, 032 backlog +# 4 cpu = 16 open, 064 backlog +# +# A multiplier of 8 is a sensible default, but you may wish to increase this for instances +# running on very performant hardware, or decrease it for instances using v. slow CPUs. +# +# If you set this to 0 or less, http request throttling will be disabled entirely. +# +# Examples: [8, 4, 9, 0] +# Default: 8 +advanced-throttling-multiplier: 8 diff --git a/internal/config/config.go b/internal/config/config.go index 8a2c041e1..d057afe37 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -127,8 +127,9 @@ 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."` + 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."` + AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."` // Cache configuration vars. Cache CacheConfiguration `name:"cache"` diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 6d589439a..4873c5c47 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -104,8 +104,9 @@ SyslogProtocol: "udp", SyslogAddress: "localhost:514", - AdvancedCookiesSamesite: "lax", - AdvancedRateLimitRequests: 300, // 1 per second per 5 minutes + AdvancedCookiesSamesite: "lax", + AdvancedRateLimitRequests: 300, // 1 per second per 5 minutes + AdvancedThrottlingMultiplier: 8, // 8 open requests per CPU Cache: CacheConfiguration{ GTS: GTSCacheConfiguration{ diff --git a/internal/config/flags.go b/internal/config/flags.go index c5df1c8b2..3a5d69f25 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -132,6 +132,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().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage")) }) } diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go index 62894b4d5..de5b93762 100644 --- a/internal/config/helpers.gen.go +++ b/internal/config/helpers.gen.go @@ -1824,6 +1824,31 @@ func GetAdvancedRateLimitRequests() int { return global.GetAdvancedRateLimitRequ // SetAdvancedRateLimitRequests safely sets the value for global configuration 'AdvancedRateLimitRequests' field func SetAdvancedRateLimitRequests(v int) { global.SetAdvancedRateLimitRequests(v) } +// GetAdvancedThrottlingMultiplier safely fetches the Configuration value for state's 'AdvancedThrottlingMultiplier' field +func (st *ConfigState) GetAdvancedThrottlingMultiplier() (v int) { + st.mutex.Lock() + v = st.config.AdvancedThrottlingMultiplier + st.mutex.Unlock() + return +} + +// SetAdvancedThrottlingMultiplier safely sets the Configuration value for state's 'AdvancedThrottlingMultiplier' field +func (st *ConfigState) SetAdvancedThrottlingMultiplier(v int) { + st.mutex.Lock() + defer st.mutex.Unlock() + st.config.AdvancedThrottlingMultiplier = v + st.reloadToViper() +} + +// AdvancedThrottlingMultiplierFlag returns the flag name for the 'AdvancedThrottlingMultiplier' field +func AdvancedThrottlingMultiplierFlag() string { return "advanced-throttling-multiplier" } + +// GetAdvancedThrottlingMultiplier safely fetches the value for global configuration 'AdvancedThrottlingMultiplier' field +func GetAdvancedThrottlingMultiplier() int { return global.GetAdvancedThrottlingMultiplier() } + +// SetAdvancedThrottlingMultiplier safely sets the value for global configuration 'AdvancedThrottlingMultiplier' field +func SetAdvancedThrottlingMultiplier(v int) { global.SetAdvancedThrottlingMultiplier(v) } + // GetCacheGTSAccountMaxSize safely fetches the Configuration value for state's 'Cache.GTS.AccountMaxSize' field func (st *ConfigState) GetCacheGTSAccountMaxSize() (v int) { st.mutex.Lock() diff --git a/internal/middleware/throttling.go b/internal/middleware/throttling.go new file mode 100644 index 000000000..0f98387dd --- /dev/null +++ b/internal/middleware/throttling.go @@ -0,0 +1,153 @@ +/* + 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 . +*/ + +/* + The code in this file is adapted from MIT-licensed code in github.com/go-chi/chi. Thanks chi (thi)! + + See: https://github.com/go-chi/chi/blob/e6baba61759b26ddf7b14d1e02d1da81a4d76c08/middleware/throttle.go + + And: https://github.com/sponsors/pkieltyka +*/ + +package middleware + +import ( + "net/http" + "runtime" + "time" + + "github.com/gin-gonic/gin" +) + +const ( + errCapacityExceeded = "server capacity exceeded" + errTimedOut = "timed out while waiting for a pending request to complete" + errContextCanceled = "context canceled" +) + +// token represents a request that is being processed. +type token struct{} + +// Throttle returns a gin middleware that performs throttling of incoming requests, +// ensuring that only a certain number of requests are handled concurrently, to reduce +// congestion of the server. +// +// Limits are configured using available CPUs and the given cpuMultiplier value. +// Open request limit is available CPUs * multiplier; backlog limit is limit * multiplier. +// +// Example values for multiplier 8: +// +// 1 cpu = 08 open, 064 backlog +// 2 cpu = 16 open, 128 backlog +// 4 cpu = 32 open, 256 backlog +// +// Example values for multiplier 4: +// +// 1 cpu = 04 open, 016 backlog +// 2 cpu = 08 open, 032 backlog +// 4 cpu = 16 open, 064 backlog +// +// Callers will first attempt to get a backlog token. Once they have that, they will +// wait in the backlog queue until they can get a token to allow their request to be +// processed. +// +// If the backlog queue is full, the request context is closed, or the caller has been +// waiting in the backlog for too long, this function will abort the request chain, +// write a JSON error into the response, set an appropriate Retry-After value, and set +// the HTTP response code to 503: Service Unavailable. +// +// If the multiplier is <= 0, a noop middleware will be returned instead. +// +// Useful links: +// +// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After +// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503 +func Throttle(cpuMultiplier int) gin.HandlerFunc { + if cpuMultiplier <= 0 { + // throttling is disabled, return a noop middleware + return func(c *gin.Context) {} + } + + var ( + limit = runtime.GOMAXPROCS(0) * cpuMultiplier + backlogLimit = limit * cpuMultiplier + backlogChannelSize = limit + backlogLimit + tokens = make(chan token, limit) + backlogTokens = make(chan token, backlogChannelSize) + retryAfter = "30" // seconds + backlogDuration = 30 * time.Second + ) + + // prefill token channels + for i := 0; i < limit; i++ { + tokens <- token{} + } + + for i := 0; i < backlogChannelSize; i++ { + backlogTokens <- token{} + } + + // bail instructs the requester to return after retryAfter seconds, returns a 503, + // and writes the given message into the "error" field of a returned json object + bail := func(c *gin.Context, msg string) { + c.Header("Retry-After", retryAfter) + c.JSON(http.StatusServiceUnavailable, gin.H{"error": msg}) + c.Abort() + } + + return func(c *gin.Context) { + // inside this select, the caller tries to get a backlog token + select { + case <-c.Request.Context().Done(): + // request context has been canceled already + bail(c, errContextCanceled) + case btok := <-backlogTokens: + // take a backlog token and wait + timer := time.NewTimer(backlogDuration) + defer func() { + // when we're finished, return the backlog token to the bucket + backlogTokens <- btok + }() + + // inside *this* select, the caller has a backlog token, + // and they're waiting for their turn to be processed + select { + case <-timer.C: + // waiting too long in the backlog + bail(c, errTimedOut) + case <-c.Request.Context().Done(): + // the request context has been canceled already + timer.Stop() + bail(c, errContextCanceled) + case tok := <-tokens: + // the caller gets a token, so their request can now be processed + timer.Stop() + defer func() { + // whatever happens to the request, put the + // token back in the bucket when we're finished + tokens <- tok + }() + c.Next() // <- finally process the caller's request + } + + default: + // we don't have space in the backlog queue + bail(c, errCapacityExceeded) + } + } +} diff --git a/mkdocs.yml b/mkdocs.yml index 00c88ef75..3fc6ec71a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,6 +59,8 @@ nav: - "federation/security.md" - "federation/behaviors/outbox.md" - "federation/behaviors/conversation_threads.md" + - "federation/behaviors/request_throttling.md" - "API Documentation": - "api/swagger.md" - "api/ratelimiting.md" + - "api/throttling.md" diff --git a/test/envparsing.sh b/test/envparsing.sh index 2fc9c055a..0de6d0bcf 100755 --- a/test/envparsing.sh +++ b/test/envparsing.sh @@ -2,7 +2,7 @@ set -eu -EXPECT='{"account-domain":"peepee","accounts-allow-custom-css":true,"accounts-approval-required":false,"accounts-reason-required":false,"accounts-registration-open":true,"advanced-cookies-samesite":"strict","advanced-rate-limit-requests":6969,"application-name":"gts","bind-address":"127.0.0.1","cache":{"gts":{"account-max-size":99,"account-sweep-freq":1000000000,"account-ttl":10800000000000,"block-max-size":100,"block-sweep-freq":10000000000,"block-ttl":300000000000,"domain-block-max-size":1000,"domain-block-sweep-freq":60000000000,"domain-block-ttl":86400000000000,"emoji-category-max-size":100,"emoji-category-sweep-freq":10000000000,"emoji-category-ttl":300000000000,"emoji-max-size":500,"emoji-sweep-freq":10000000000,"emoji-ttl":300000000000,"mention-max-size":500,"mention-sweep-freq":10000000000,"mention-ttl":300000000000,"notification-max-size":500,"notification-sweep-freq":10000000000,"notification-ttl":300000000000,"status-max-size":500,"status-sweep-freq":10000000000,"status-ttl":300000000000,"tombstone-max-size":100,"tombstone-sweep-freq":10000000000,"tombstone-ttl":300000000000,"user-max-size":100,"user-sweep-freq":10000000000,"user-ttl":300000000000}},"config-path":"internal/config/testdata/test.yaml","db-address":":memory:","db-database":"gotosocial_prod","db-password":"hunter2","db-port":6969,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"sqlite","db-user":"sex-haver","dry-run":false,"email":"","host":"example.com","instance-deliver-to-shared-inboxes":false,"instance-expose-peers":true,"instance-expose-public-timeline":true,"instance-expose-suspended":true,"landing-page-user":"admin","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":true,"log-level":"info","media-description-max-chars":5000,"media-description-min-chars":69,"media-emoji-local-max-size":420,"media-emoji-remote-max-size":420,"media-image-max-size":420,"media-remote-cache-days":30,"media-video-max-size":420,"oidc-client-id":"1234","oidc-client-secret":"shhhh its a secret","oidc-enabled":true,"oidc-idp-name":"sex-haver","oidc-issuer":"whoknows","oidc-link-existing":true,"oidc-scopes":["read","write"],"oidc-skip-verification":true,"password":"","path":"","port":6969,"protocol":"http","smtp-from":"queen.rip.in.piss@terfisland.org","smtp-host":"example.com","smtp-password":"hunter2","smtp-port":4269,"smtp-username":"sex-haver","software-version":"","statuses-cw-max-chars":420,"statuses-max-chars":69,"statuses-media-max-files":1,"statuses-poll-max-options":1,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/root/store","storage-s3-access-key":"minio","storage-s3-bucket":"gts","storage-s3-endpoint":"localhost:9000","storage-s3-proxy":true,"storage-s3-secret-key":"miniostorage","storage-s3-use-ssl":false,"syslog-address":"127.0.0.1:6969","syslog-enabled":true,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","docker.host.local"],"username":"","web-asset-base-dir":"/root","web-template-base-dir":"/root"}' +EXPECT='{"account-domain":"peepee","accounts-allow-custom-css":true,"accounts-approval-required":false,"accounts-reason-required":false,"accounts-registration-open":true,"advanced-cookies-samesite":"strict","advanced-rate-limit-requests":6969,"advanced-throttling-multiplier":-1,"application-name":"gts","bind-address":"127.0.0.1","cache":{"gts":{"account-max-size":99,"account-sweep-freq":1000000000,"account-ttl":10800000000000,"block-max-size":100,"block-sweep-freq":10000000000,"block-ttl":300000000000,"domain-block-max-size":1000,"domain-block-sweep-freq":60000000000,"domain-block-ttl":86400000000000,"emoji-category-max-size":100,"emoji-category-sweep-freq":10000000000,"emoji-category-ttl":300000000000,"emoji-max-size":500,"emoji-sweep-freq":10000000000,"emoji-ttl":300000000000,"mention-max-size":500,"mention-sweep-freq":10000000000,"mention-ttl":300000000000,"notification-max-size":500,"notification-sweep-freq":10000000000,"notification-ttl":300000000000,"status-max-size":500,"status-sweep-freq":10000000000,"status-ttl":300000000000,"tombstone-max-size":100,"tombstone-sweep-freq":10000000000,"tombstone-ttl":300000000000,"user-max-size":100,"user-sweep-freq":10000000000,"user-ttl":300000000000}},"config-path":"internal/config/testdata/test.yaml","db-address":":memory:","db-database":"gotosocial_prod","db-password":"hunter2","db-port":6969,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"sqlite","db-user":"sex-haver","dry-run":false,"email":"","host":"example.com","instance-deliver-to-shared-inboxes":false,"instance-expose-peers":true,"instance-expose-public-timeline":true,"instance-expose-suspended":true,"landing-page-user":"admin","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-db-queries":true,"log-level":"info","media-description-max-chars":5000,"media-description-min-chars":69,"media-emoji-local-max-size":420,"media-emoji-remote-max-size":420,"media-image-max-size":420,"media-remote-cache-days":30,"media-video-max-size":420,"oidc-client-id":"1234","oidc-client-secret":"shhhh its a secret","oidc-enabled":true,"oidc-idp-name":"sex-haver","oidc-issuer":"whoknows","oidc-link-existing":true,"oidc-scopes":["read","write"],"oidc-skip-verification":true,"password":"","path":"","port":6969,"protocol":"http","smtp-from":"queen.rip.in.piss@terfisland.org","smtp-host":"example.com","smtp-password":"hunter2","smtp-port":4269,"smtp-username":"sex-haver","software-version":"","statuses-cw-max-chars":420,"statuses-max-chars":69,"statuses-media-max-files":1,"statuses-poll-max-options":1,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/root/store","storage-s3-access-key":"minio","storage-s3-bucket":"gts","storage-s3-endpoint":"localhost:9000","storage-s3-proxy":true,"storage-s3-secret-key":"miniostorage","storage-s3-use-ssl":false,"syslog-address":"127.0.0.1:6969","syslog-enabled":true,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32","docker.host.local"],"username":"","web-asset-base-dir":"/root","web-template-base-dir":"/root"}' # Set all the environment variables to # ensure that these are parsed without panic @@ -76,6 +76,7 @@ GTS_SYSLOG_PROTOCOL='udp' \ GTS_SYSLOG_ADDRESS='127.0.0.1:6969' \ GTS_ADVANCED_COOKIES_SAMESITE='strict' \ GTS_ADVANCED_RATE_LIMIT_REQUESTS=6969 \ +GTS_ADVANCED_THROTTLING_MULTIPLIER=-1 \ go run ./cmd/gotosocial/... --config-path internal/config/testdata/test.yaml debug config) OUTPUT_OUT=$(mktemp) diff --git a/testrig/config.go b/testrig/config.go index a1d7e5d54..d815f36fa 100644 --- a/testrig/config.go +++ b/testrig/config.go @@ -106,8 +106,9 @@ func InitTestConfig() { SyslogProtocol: "udp", SyslogAddress: "localhost:514", - AdvancedCookiesSamesite: "lax", - AdvancedRateLimitRequests: 0, // disabled + AdvancedCookiesSamesite: "lax", + AdvancedRateLimitRequests: 0, // disabled + AdvancedThrottlingMultiplier: 0, // disabled SoftwareVersion: "0.0.0-testrig",