lockout

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package lockout implements per-(email, ip) login throttling for the airlock auth path. The mechanism is intentionally application-only — per-IP rate limiting is the operator's reverse-proxy job. See airlock/AGENTS.md and the project README for the threat-model rationale.

Index

Constants

View Source
const UnknownIP = "unknown"

UnknownIP is the bucket assigned to requests whose RemoteAddr cannot be parsed. Aligns with the "fail loud" rule in airlock/AGENTS.md: never silently skip the lockout — pool the unparseable requests instead.

Variables

View Source
var Default = Policy{
	WindowMinutes: 15,
	Threshold:     10,
	TierDelays:    []time.Duration{5 * time.Minute, 15 * time.Minute, 60 * time.Minute},
	PadDuration:   400 * time.Millisecond,
}

Functions

func NormalizeIP

func NormalizeIP(remoteAddr string) string

NormalizeIP turns an http.Request RemoteAddr into a stable bucket key. IPv4 round-trips to canonical form; IPv6 collapses to its /64 prefix because a single attacker controls their entire /64 trivially.

Types

type Policy

type Policy struct {
	WindowMinutes int
	Threshold     int
	TierDelays    []time.Duration
	PadDuration   time.Duration
}

func (Policy) Check

func (p Policy) Check(ctx context.Context, pool *pgxpool.Pool, email, ip string) (Status, error)

Check returns the active lockout for (email, ip), if any.

func (Policy) ClearOnSuccess

func (p Policy) ClearOnSuccess(ctx context.Context, pool *pgxpool.Pool, email, ip string) error

ClearOnSuccess wipes failure history + lockout state for a successful login. Best-effort: the caller logs errors but does not block the successful login response on this.

func (Policy) CooldownFor

func (p Policy) CooldownFor(tier int) time.Duration

func (Policy) PadResponse

func (p Policy) PadResponse(start time.Time)

PadResponse sleeps so total elapsed time since `start` reaches p.PadDuration. No-op if already past. Used on the auth-failure paths to collapse the timing channel between unknown-email (fast), wrong-password (bcrypt-slow), and lockout (fast) responses.

func (Policy) RecordFailure

func (p Policy) RecordFailure(ctx context.Context, pool *pgxpool.Pool, email, ip string) error

RecordFailure logs an auth failure for (email, ip) and applies an escalating lockout when the rolling-window threshold is reached. The whole thing runs in one transaction so concurrent triggers agree on the next tier.

type Status

type Status struct {
	Locked      bool
	LockedUntil time.Time
	Tier        int
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL