- store: SQLite (WAL, foreign keys ON, CGO-free driver) + the embedded migration runner; each module's migrations are name-prefixed (D-012) - audit: the append-only audit log; the actor threads via context (R-1) - users: the user_id/GUID/email anchors (D-013) - config: the YAML settings file (D-035) + validation - httpx: cookies · loopback detection · trusted-proxy XFF · CSRF · security headers · redaction - middleware: correlation id · audit · rate limiting - mail: the invite/recovery mailer seam - server: the core DOOR — the resolution switch, the dispatch registry (RegisterModule), the role gates, /setup · enroll/login · recovery flows, the reserved `static` workflow, and the loopback-only bootstrap (D-025)
49 lines
2.2 KiB
Go
49 lines
2.2 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"git.lohmar.co.uk/cclohmar/NextMyDay/internal/core/auth/flow"
|
|
)
|
|
|
|
// authModule is the `do` module name carrying the SPEC-006 enroll/login
|
|
// actions. The GUID still rides the path — `do`/`action` never carry identity
|
|
// (D-032/D-039).
|
|
const authModule = "auth"
|
|
|
|
// RegisterAuthFlow registers the SPEC-006 core screens (enroll · login) and the
|
|
// `auth` action module into reg. It is the wiring the door needs to make
|
|
// `POST /{GUID}?do=auth&action=…` resolve and dispatch.
|
|
func RegisterAuthFlow(reg *MapRegistry, a *flow.Actions) {
|
|
reg.RegisterCore("enroll", adaptFlow(a.EnrollScreen))
|
|
reg.RegisterCore("login", adaptFlow(a.LoginScreen))
|
|
|
|
reg.RegisterModule(NewModule(authModule).
|
|
// SPEC-006 §8 (D-041): the session-gated passkey-nudge screen. It is a
|
|
// ROUTE on the auth module (GET /{GUID}/auth/passkey) — the redirect
|
|
// target of a nudged TOTP login.
|
|
AddRoute("passkey", "passkey.prompt", adaptFlow(a.PasskeyPrompt)).
|
|
AddAction("enroll.begin", "enroll.begin", adaptFlow(a.EnrollBegin)).
|
|
AddAction("enroll.finish", "enroll.finish", adaptFlow(a.EnrollFinish)).
|
|
AddAction("totp.begin", "totp.begin", adaptFlow(a.TOTPBegin)).
|
|
AddAction("totp.verify", "totp.verify", adaptFlow(a.TOTPVerify)).
|
|
AddAction("login.begin", "login.begin", adaptFlow(a.LoginBegin)).
|
|
AddAction("login.finish", "login.finish", adaptFlow(a.LoginFinish)).
|
|
AddAction("logout", "logout", adaptFlow(a.Logout)).
|
|
// The nudge actions carry a session, so the door session-gates them
|
|
// (serveAuthAction forwards the `passkey.` prefix to serveGUID).
|
|
AddAction("passkey.add", "passkey.add", adaptFlow(a.PasskeyAdd)).
|
|
AddAction("passkey.later", "passkey.later", adaptFlow(a.PasskeyLater)).
|
|
AddAction("passkey.never", "passkey.never", adaptFlow(a.PasskeyNever)))
|
|
}
|
|
|
|
// flowFunc is a flow handler: the GUID comes from the RequestContext (the door
|
|
// resolves it from the path; the flow never parses a raw path).
|
|
type flowFunc func(w http.ResponseWriter, r *http.Request, guid string) error
|
|
|
|
// adaptFlow adapts a flow handler to the door's Handler signature.
|
|
func adaptFlow(f flowFunc) Handler {
|
|
return func(w http.ResponseWriter, r *http.Request, rc *RequestContext) error {
|
|
return f(w, r, rc.Workflow)
|
|
}
|
|
}
|