mfa fixing

This commit is contained in:
2026-08-13 10:40:27 +01:00
parent bc4bbe6e56
commit 6063f95504
22 changed files with 834 additions and 158 deletions
+37 -4
View File
@@ -88,18 +88,51 @@ func (a *App) requireMailboxAuth(next http.Handler) http.Handler {
return
}
// enforce_mailbox_mfa: login itself is never blocked (see webmailLoginSubmit) —
// instead, a mailbox with no MFA configured and no domain/mailbox exemption is
// sent to the isolated /mfa-setup page (no other route reachable except the
// actual totp/passkey setup actions) until they configure one. This never
// touches IMAP/SMTP app-password auth — a completely separate, non-interactive
// protocol path this gate has no bearing on; see mailboxNeedsMFASetup's doc
// comment.
if a.mailboxNeedsMFASetup(mbox) {
if !mailboxMFASetupExempt(r.Method, r.URL.Path) {
http.Redirect(w, r, MailboxPrefix+"/mfa-setup", http.StatusFound)
return
}
}
ctx := context.WithValue(r.Context(), ctxMailboxKey, mbox)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// mailboxMFASetupExempt mirrors adminMFASetupExempt for the webmail portal: the
// isolated setup page itself, plus the actual form/API actions needed to complete
// TOTP or passkey enrollment. Everything else — including the dashboard itself —
// redirects to /mfa-setup.
func mailboxMFASetupExempt(method, path string) bool {
if method == http.MethodGet {
return path == MailboxPrefix+"/mfa-setup"
}
if method != http.MethodPost {
return false
}
switch path {
case MailboxPrefix + "/account/totp/setup", MailboxPrefix + "/account/totp/confirm",
MailboxPrefix + "/account/passkey/begin", MailboxPrefix + "/account/passkey/finish":
return true
}
return false
}
// mailboxNeedsMFASetup reports whether [Auth] enforce_mailbox_mfa applies to this
// mailbox and it doesn't have a second factor configured yet — false if enforcement
// is off, MFA is already set up, or the mailbox/its domain is explicitly exempt.
// Used at webmail login time (see webmailLoginSubmit) to block the login outright,
// not any specific action once logged in — app passwords (creating or using them)
// are never gated by this, since IMAP/SMTP AUTH has no interactive MFA step to
// enforce one on regardless.
// Login is never blocked by this (see webmailLoginSubmit) — it gates every other
// webmail route (see requireMailboxAuth/mailboxMFASetupExempt). Never applies to
// IMAP/SMTP app-password auth, which has no interactive step to enforce MFA on
// regardless.
func (a *App) mailboxNeedsMFASetup(mbox *db.Mailbox) bool {
if !a.Cfg.Section("Auth").Key("enforce_mailbox_mfa").MustBool(false) {
return false