store, web: cite the source of what they rely on (assumptions part D)
Comments only, no behaviour changed. modernc.org/sqlite v1.60.1 (the _pragma list on every connection, busy_timeout first; extended result codes; a deferred BEGIN; multi-statement Exec) and SQLite 3.53.4's documentation (transactions, WAL, foreign keys, NOCASE, upsert, julianday, partial indexes); htmx 2.0.4 src/htmx.js; the Fetch and HTML standards for Sec-Fetch-Site, Origin, SameSite, __Host-, CSP and defer order; Go's html/template. Comments the source contradicts are corrected - the driver does not serialise writes (SetMaxOpenConns(1) does), htmx:load fires per swapped element, no-store does not keep a page out of history. Left for their own commits: D-S3 a migration two processes can both run, D-S20 recipient case, D-B3 Origin: null under Referrer-Policy: no-referrer, D-H5/H6/H7/H9 (audit M11, stage 4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,9 @@ import (
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// draft-ietf-httpbis-rfc6265bis § 4.1.3.2: a cookie named __Host- is accepted
|
||||
// only with Secure, Path=/ and no Domain, from a secure origin - so no other
|
||||
// host can set or overwrite it, and clearing it needs Secure as well.
|
||||
const (
|
||||
sessionCookieBase = "selfpost_session"
|
||||
sessionCookiePrefixed = "__Host-" + sessionCookieBase
|
||||
@@ -46,6 +49,9 @@ func (m *Module) sessionToken(r *http.Request) (string, bool) {
|
||||
case 1:
|
||||
return token, true
|
||||
default:
|
||||
// RFC 6265 § 5.4: the Cookie header carries every cookie that
|
||||
// matches, a parent domain's of the same name included. The prefixed
|
||||
// name cannot be planted that way (see sessionCookiePrefixed).
|
||||
logf("panel: %s %s carries %d cookies named %q — treating the request as signed out; "+
|
||||
"another host on this domain is overwriting the session cookie, clear the cookies for the parent domain",
|
||||
r.Method, r.URL.Path, n, name)
|
||||
@@ -130,6 +136,9 @@ func (m *Module) submitLogin(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// setSessionCookie sets the session cookie. SameSite=Lax withholds it from a
|
||||
// cross-site request unless that is a top-level navigation with a safe method
|
||||
// (rfc6265bis § 5.8.3, § 5.6.7.1), so a cross-site POST arrives without it.
|
||||
func (m *Module) setSessionCookie(w http.ResponseWriter, token string) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: m.sessionCookie(),
|
||||
|
||||
@@ -34,6 +34,10 @@ func (m *Module) RequireAuth(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// isSessionActivity: a GET from htmx is a background poll - every panel hx-get
|
||||
// is a load or a poll - and does not renew the session. htmx 2.0.4, src/htmx.js
|
||||
// getHeaders(): every request it issues carries HX-Request: true (and
|
||||
// loadHistoryFromServer() sets it too).
|
||||
func isSessionActivity(r *http.Request) bool {
|
||||
return !(r.Method == http.MethodGet && r.Header.Get("HX-Request") != "")
|
||||
}
|
||||
|
||||
@@ -31,7 +31,10 @@ func newSessionStore(st *store.Store, idle time.Duration) *sessionStore {
|
||||
|
||||
// MaxAge is the session cookie's Max-Age in seconds, kept equal to the
|
||||
// sliding idle window so the browser drops the cookie no later than the
|
||||
// server would have expired it anyway.
|
||||
// server would have expired it anyway. RFC 6265 § 5.2.2: Max-Age sets the
|
||||
// expiry to now plus that many seconds, and a cookie set again under the same
|
||||
// name, domain and path replaces the old one (§ 5.3 step 11), so each renewal
|
||||
// slides it.
|
||||
func (s *sessionStore) MaxAge() int {
|
||||
return int(s.idle.Seconds())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user