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
|
|
@ -5,6 +5,7 @@ pub mod config;
|
|||
pub mod device;
|
||||
pub mod error;
|
||||
pub mod grpc;
|
||||
pub mod mail;
|
||||
|
||||
use accounts::handlers::AccountsState;
|
||||
use auth::handlers::AuthState;
|
||||
|
|
@ -19,11 +20,12 @@ use device::{handlers::DeviceState, store::DeviceStore};
|
|||
use tower_http::trace::TraceLayer;
|
||||
|
||||
pub fn build_app(pool: sqlx::PgPool, cfg: &Config) -> Router {
|
||||
build_app_with_mail(pool, cfg, auth::reset::MailBox::Log)
|
||||
let mail = auth::reset::MailBox::from_config(cfg).expect("invalid mail configuration");
|
||||
build_app_with_mail(pool, cfg, mail)
|
||||
}
|
||||
|
||||
/// Same router with a custom reset-email back-end: production uses the log
|
||||
/// mailer, tests capture tokens through the queue variant.
|
||||
/// Same router with an explicit mail back-end: production derives it from
|
||||
/// the config (SMTP / LOG / Disabled), tests capture tokens via the queue.
|
||||
pub fn build_app_with_mail(pool: sqlx::PgPool, cfg: &Config, mail: auth::reset::MailBox) -> Router {
|
||||
let auth_state = AuthState::with_mail(
|
||||
pool.clone(),
|
||||
|
|
@ -63,6 +65,14 @@ pub fn build_app_with_mail(pool: sqlx::PgPool, cfg: &Config, mail: auth::reset::
|
|||
"/auth/reset-password",
|
||||
post(auth::reset::handlers::reset_password),
|
||||
)
|
||||
.route(
|
||||
"/auth/verify-email",
|
||||
post(auth::verify::handlers::verify_email),
|
||||
)
|
||||
.route(
|
||||
"/auth/resend-verification",
|
||||
post(auth::verify::handlers::resend_verification),
|
||||
)
|
||||
.with_state(auth_state);
|
||||
|
||||
let device_routes = Router::new()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue