feat(auth): signup bot-guard foundation - honeypot + submit-timing (BUNYIP-377) #374
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/BUNYIP-377-signup-bot-prevention"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Server-side foundation for the signup bot guard (BUNYIP-377), inert behind an opt-in flag. Honeypot + submit-timing was chosen over a third-party CAPTCHA to keep the self-hosted stack dependency-free.
Ships the enforcement + the token endpoint that feeds it, so the register forms can adopt the hidden fields next and the flag can be flipped once they do. Registration behaviour is unchanged until then.
What's in
SignupChallengeClaims+JwtService::create/verify_signup_challenge_token: a short-lived (30-min) HMAC-signed issued-at token, distinctpurposeso it can't be crossed with the 2FA / login-approval challenges.AuthService::create_signup_challenge+verify_signup_not_bot: rejects a filled honeypot, or a missing / forged / expired / too-fast (< SIGNUP_MIN_FILL_SECONDS) token, all via one uniform error so no individual check is an oracle a bot could tune against. The puresignup_submitted_too_fastdecision is unit-tested.GET /v1/auth/register-challengeissues the token;RegisterRequestgains optionalcontact_channel(honeypot) +signup_tokenfields; the register handler enforces the guard only whenConfig::signup_bot_guard_enabled(SIGNUP_BOT_GUARD_ENABLED, default off).Staged rollout (PMS-289 lesson)
Off by default and no form change yet, so a real signup (which does not carry the fields) is only rejected once the flag is on. Remaining before enabling:
register_postto bunyip-api.SIGNUP_BOT_GUARD_ENABLED=true.Relates to BUNYIP-379 (real client IP) - without it the per-IP registration rate limit collapses to one container IP, so the per-IP layer of the defence is meaningless until that lands.
Testing
just check-containergreen (fmt + clippy-D warnings+cargo test --workspace --all-targets, 278 domain / 73 api / 104 web, 0 failed), including the newsignup_rejects_submits_faster_than_min_fillunit test.