package api import ( "time" "github.com/owncord/server/config" ) // ─── Rate limits ──────────────────────────────────────────────────────────── // // Each constant defines either a request cap or a sliding-window duration used // by the per-endpoint rate limiters. const ( // registerRateLimitPerMinute is the maximum registration attempts per IP per minute. registerRateLimitPerMinute = 3 // loginRateLimitPerMinute is the maximum login attempts per IP per minute. loginRateLimitPerMinute = 5 // verifyTOTPRateLimitPerMinute is the maximum TOTP verification attempts per IP per minute. verifyTOTPRateLimitPerMinute = 10 // sensitiveEndpointRateLimitPerMinute is the rate limit applied to destructive // or sensitive endpoints (account deletion, TOTP enable/confirm/disable). sensitiveEndpointRateLimitPerMinute = 5 // searchRateLimitPerMinute is the maximum full-text search requests per IP per minute. searchRateLimitPerMinute = 30 // livekitProxyRateLimitPerMinute is the maximum LiveKit proxy requests per IP per minute. livekitProxyRateLimitPerMinute = 30 // clientUpdateRateLimitPerMinute is the maximum client-update checks per IP per minute. clientUpdateRateLimitPerMinute = 30 // gifRateLimitPerMinute is the maximum GIF proxy requests per IP per minute. // The picker debounces at 300ms, so a user typing continuously for a minute // stays under this; it exists to bound abuse of the operator's Klipy quota. gifRateLimitPerMinute = 30 // loginFailureThreshold is the number of failed login attempts (within // loginFailureWindow) before the IP is locked out. loginFailureThreshold = 9 // loginFailureWindow is the sliding window for counting login failures. loginFailureWindow = 15 * time.Minute // loginLockoutDuration is how long an IP is locked out after exceeding // loginFailureThreshold. loginLockoutDuration = 15 * time.Minute // deleteAccountFailureThreshold is the number of wrong-password attempts // before the per-user lockout kicks in. deleteAccountFailureThreshold = 3 // deleteAccountFailureWindow is the sliding window for counting // delete-account password failures. deleteAccountFailureWindow = 15 * time.Minute // deleteAccountLockoutDuration is how long the account-deletion endpoint // is locked after exceeding deleteAccountFailureThreshold. deleteAccountLockoutDuration = 15 * time.Minute // totpFailureRateLimit is the maximum TOTP verification failures per user // within totpFailureWindow before the user is rate-limited. totpFailureRateLimit = 10 // totpFailureWindow is the sliding window for counting per-user TOTP failures. totpFailureWindow = 15 * time.Minute // partialAuthMaxFailures is the number of failed TOTP attempts on a single // partial-auth challenge before it is revoked. partialAuthMaxFailures = 5 // profilePasswordRateLimitPerMinute is the maximum password change attempts // per IP per minute. profilePasswordRateLimitPerMinute = 5 // profileUpdateRateLimitPerMinute is the maximum profile update attempts // per user per minute. profileUpdateRateLimitPerMinute = 10 // loginUserFailureThreshold is the number of failed login attempts for a // specific username (regardless of source IP) before the account is locked. loginUserFailureThreshold = 9 // loginUserFailureWindow is the sliding window for per-username login failures. loginUserFailureWindow = 15 * time.Minute // loginUserLockoutDuration is how long a username is locked after exceeding // loginUserFailureThreshold. loginUserLockoutDuration = 15 * time.Minute // pwConfirmFailureThreshold is the number of wrong-password attempts on // password-confirmation endpoints before per-user lockout kicks in. pwConfirmFailureThreshold = 3 // pwConfirmFailureWindow is the sliding window for per-user password // confirmation failures. pwConfirmFailureWindow = 15 * time.Minute // pwConfirmLockoutDuration is how long password-confirmation endpoints are // locked after exceeding pwConfirmFailureThreshold. pwConfirmLockoutDuration = 15 * time.Minute // uploadRateLimitPerMinute is the maximum file uploads per user per minute. uploadRateLimitPerMinute = 10 ) // ─── Timeouts & TTLs ──────────────────────────────────────────────────────── const ( // partialAuthStoreTTL is the lifetime of a partial-auth (2FA) challenge token. partialAuthStoreTTL = 10 * time.Minute // pendingTOTPStoreTTL is the lifetime of a pending TOTP enrollment secret. pendingTOTPStoreTTL = 10 * time.Minute // rateLimiterCleanupInterval is how often stale rate-limiter entries are reaped. rateLimiterCleanupInterval = 5 * time.Minute // rateLimiterCleanupMaxWindow is the maximum window considered when pruning // stale rate-limiter entries. rateLimiterCleanupMaxWindow = 15 * time.Minute // hstsMaxAgeSeconds is the max-age value for the Strict-Transport-Security header. hstsMaxAgeSeconds = 31536000 ) // ─── Size limits ──────────────────────────────────────────────────────────── const ( // defaultMaxBodySize is the default request body size limit (1 MiB). defaultMaxBodySize = config.MaxMessageBytes // uploadMaxBodySize is the request body size limit for file uploads (100 MiB). uploadMaxBodySize = 100 << 20 // multipartMemoryLimit is the in-memory limit for multipart form parsing; // data beyond this is spilled to disk. multipartMemoryLimit = 10 << 20 // maxUploadFilenameLength is the maximum length of an upload filename // (filesystem-safe limit). maxUploadFilenameLength = 255 // maxAvatarURLLen is the maximum length of a user avatar URL. maxAvatarURLLen = 512 // maxRequestIDLen bounds a client-supplied X-Request-Id. chi's // middleware.RequestID adopts that header verbatim, and the value then // reaches every log record for the request (logctx, requestLogger, // recoverer) and the echoed response header — while the admin ring buffer // retains 2000 records, so an unbounded id becomes long-lived heap. // 128 bytes fits every common correlation-id format (UUID, 32-hex, // W3C traceparent, chi's own "host/prefix-000001"). maxRequestIDLen = 128 // maxLoggedPathLen bounds the request path attached to a log record. The // URL is client-controlled and net/http accepts one up to MaxHeaderBytes // (~1 MiB), so an unbounded path fills the ring buffer the same way an // unbounded request id does. Well past the longest real route. maxLoggedPathLen = 256 )