package middleware import ( "context" "net/http" "time" ) // NewLoggingResponseWriterForTest wraps newLoggingResponseWriter // for use in external test packages. func NewLoggingResponseWriterForTest( w http.ResponseWriter, ) *loggingResponseWriter { return newLoggingResponseWriter(w) } // LoggingResponseWriterStatusCode returns the status code // captured by the loggingResponseWriter. func LoggingResponseWriterStatusCode( lrw *loggingResponseWriter, ) int { return lrw.statusCode } // IPFromHostPort exposes ipFromHostPort for testing. func IPFromHostPort(hp string) string { return ipFromHostPort(hp) } // ClientKeyForTest exposes clientKey for testing. func ClientKeyForTest(m *Middleware, r *http.Request) string { return m.clientKey(r) } // IsClientTLS exposes isClientTLS for testing. func IsClientTLS(r *http.Request) bool { return isClientTLS(r) } // LoginRateLimitConst exposes the loginRateLimit constant: the // number of FAILED login attempts one client may make against one // submitted username per interval. const LoginRateLimitConst = loginRateLimit // LoginFailureMaxKeysConst exposes the cap on each of the login // guard's key sets. const LoginFailureMaxKeysConst = loginFailureMaxKeys // PasswordVerifyConcurrencyConst exposes the bound on concurrent // Argon2id verifications. const PasswordVerifyConcurrencyConst = passwordVerifyConcurrency // PasswordVerifyMaxWaitersConst exposes the bound on how many // requests may queue for a verification slot. const PasswordVerifyMaxWaitersConst = passwordVerifyMaxWaiters // LoginGuard is the login failure counter and verification // semaphore, exposed for direct testing. type LoginGuard = loginGuard // NewLoginGuardForTest builds a guard with test-sized parameters. func NewLoginGuardForTest( limit int, interval time.Duration, maxKeys, concurrency, maxWaiters int, wait time.Duration, ) *LoginGuard { return newLoginGuard( limit, interval, maxKeys, concurrency, maxWaiters, wait, ) } // QueuedWaitersForTest reports how many requests are currently // queued for a verification slot. func (g *LoginGuard) QueuedWaitersForTest() int { return len(g.queue) } // SetNowForTest replaces the guard's clock. func (g *LoginGuard) SetNowForTest(now func() time.Time) { g.mu.Lock() defer g.mu.Unlock() g.now = now } // FailForTest exposes fail. func (g *LoginGuard) FailForTest(clientKey, username string) bool { return g.fail(clientKey, username) } // SucceedForTest exposes succeed. func (g *LoginGuard) SucceedForTest(clientKey, username string) { g.succeed(clientKey, username) } // AcquireForTest exposes acquire. func (g *LoginGuard) AcquireForTest( ctx context.Context, ) (func(), bool) { return g.acquire(ctx) } // TrackedKeysForTest reports how many failure counters the guard // holds, per-username and per-address respectively. func (g *LoginGuard) TrackedKeysForTest() (int, int) { g.mu.Lock() defer g.mu.Unlock() return len(g.byUser), len(g.byAddr) } // PasswordChangeRateLimitConst exposes the // passwordChangeRateLimit constant. const PasswordChangeRateLimitConst = passwordChangeRateLimit // ReceiverAggregateMultiplierConst exposes the // receiverAggregateMultiplier constant. const ReceiverAggregateMultiplierConst = receiverAggregateMultiplier // ReceiverAggregateLimitForTest exposes receiverAggregateLimit for // testing. func ReceiverAggregateLimitForTest(perEntrypoint int) int { return receiverAggregateLimit(perEntrypoint) }