feat(accounts): outgoing mail over SMTP (Resend), email verification, fail-closed password reset
- mail/ module (lettre, ru/en templates), links built only from PUBLIC_BASE_URL - migration 0006: accounts.email_verified_at, shared email_tokens table (verify + reset), existing accounts marked verified - reset mailer no longer logs tokens; RESET_MAIL_MODE=log is dev-only and refused with COOKIE_SECURE=true; Disabled by default answers 503 - forgot-password and resend-verification do their work in a background task (no timing oracle) - device linking requires a verified email; email_verified exposed via /me and gRPC - gateway rate limits, SMTP_* in compose and .env.example - frontend: verify, forgot-password, reset-password pages, verify banner, ru/en strings
This commit is contained in:
parent
12ce6216b6
commit
c57f851a8b
48 changed files with 1810 additions and 120 deletions
|
|
@ -60,6 +60,22 @@ pub fn rules() -> Vec<Rule> {
|
|||
Quota::per_minute(n(10)),
|
||||
Ip,
|
||||
),
|
||||
// Verification tokens are 256-bit random, so this limit exists to
|
||||
// keep the route cheap, not to stop brute force.
|
||||
rule(
|
||||
Method::POST,
|
||||
"/auth/verify-email",
|
||||
Quota::per_minute(n(10)),
|
||||
Ip,
|
||||
),
|
||||
// Requires login: per account (IP until the credential resolves),
|
||||
// tight enough that one session cannot spam the mailbox.
|
||||
rule(
|
||||
Method::POST,
|
||||
"/auth/resend-verification",
|
||||
Quota::per_hour(n(3)),
|
||||
Account,
|
||||
),
|
||||
rule(Method::POST, "/auth/refresh", Quota::per_minute(n(30)), Ip),
|
||||
rule(Method::POST, "/device/code", Quota::per_minute(n(10)), Ip),
|
||||
// The mod polls every 2–3 s for up to 10 min: 10/min would break linking.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue