// Package httpx holds the door's HTTP helpers: the session cookie, the client // IP resolution (trusted proxies, A6), the security headers, log redaction, and // the CSRF token (SPEC-003 §6/§8). // // It imports only net/http + the standard library — the door owns HTTP; the // pure routing model (internal/core/routing) must never import this. package httpx import "net/http" // SessionCookieName is the base name of the session cookie (SPEC-003 §6). The // value is an opaque random id; the server-side session row is authoritative. const SessionCookieName = "myday_session" // HostPrefix is the `__Host-` cookie-name prefix (L1s). A browser only accepts // a `__Host-` cookie when it is Secure · Path=/ · has no Domain attribute, so // the cookie is pinned to the exact origin — a sibling subdomain cannot shadow // it (a cookie-fixation / session-shadowing DoS). const HostPrefix = "__Host-" // SessionCookieNameFor returns the session cookie's name for the transport: // `__Host-myday_session` over https (Secure is set — required by the prefix) // and the bare name otherwise, because a browser REJECTS a `__Host-` cookie // sent without Secure over plain http (the loopback bootstrap / human test). // // The `secure` decision is made PER REQUEST by the door (D-043): TLS, or a // trusted proxy's `X-Forwarded-Proto: https`. Over the plain-http bootstrap it // is false, so the bare name is used. func SessionCookieNameFor(secure bool) string { if secure { return HostPrefix + SessionCookieName } return SessionCookieName } // SetSessionCookie writes the hardened session cookie (SPEC-003 §6): // HttpOnly · Secure · SameSite=Lax · Path=/. The lifetime is server-side, so // no Max-Age is set (a browser-session cookie). func SetSessionCookie(w http.ResponseWriter, name, value string, secure bool) { http.SetCookie(w, &http.Cookie{ Name: name, Value: value, Path: "/", HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, }) } // ClearSessionCookie expires the session cookie (logout, or an invalid session). func ClearSessionCookie(w http.ResponseWriter, name string, secure bool) { http.SetCookie(w, &http.Cookie{ Name: name, Value: "", Path: "/", HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, MaxAge: -1, }) }