`extractToken` only ever looked up `cookieValue(cookie, "session")`. After the
M-1 fix switched cookie parsing from substring to exact-name matching
(fafee12), a consumer that sets its session cookie under the hardened
`__Host-session` name (fewo-webapp, #535) stopped resolving — every browser
cookie request extracted an empty token and 401'd. The bare-`session`
substring used to incidentally match inside `__Host-session=`; exact matching
correctly no longer does.
Fix: add `sessionCookieToken(cookieHeader)` which tries the bare `session`
name and falls back to `__Host-session` (the `__Host-` prefix is strictly more
secure, so recognizing it is safe), and route `extractToken` through it. The
bare name is preferred when both are present. `cookieValue` keeps its exact
generic semantics unchanged. Backward-compatible: consumers using `session=`
are unaffected.
Tests: new `test_session_cookie_token` covering both names, precedence, and
substring traps. All 20 ctest targets pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
M-1 TokenExtract: exact-name cookie parse (new pure cookieValue helper) —
a substring find("session=") could be shadowed by a sibling xsession=,
defeating __Host-/__Secure- prefix guarantees.
M-2 AuthInterceptor: gate setup-mode pseudo-admin on a loopback bind and log
the grant; document that IAuthBackend::hasActiveUsers() must fail closed.
M-3 ws/Hub: empty propertyIds now means NO access for non-admins (was "all") —
a non-admin whose scope set failed to populate no longer gets every
property's notifications. Admins still get all via role.
M-4 new util/OriginCheck.hpp (originHostname/sameOrigin/originAllowed) +
Hub doc: WSController must validate Origin at the handshake (CSWSH).
M-6 RedactedFieldRepository: ctor throws on an unknown redaction field name
(a typo would silently redact nothing, leaving credentials in history).
M-7 RateLimiter: ctor validates capacity (finite >=1) / refillRate (finite >0),
throws std::invalid_argument — zero/negative/NaN silently disabled it.
M-8 TokenExtract: document that clientIpTrusted's "unknown"/"invalid" sentinels
collapse to one shared rate-limit bucket off-proxy.
M-9 new util/SessionCookie.hpp: safe-by-default Set-Cookie builder
(HttpOnly+Secure+SameSite=Strict+Path=/), rejects control chars / ';'.
M-10 AuthInterceptor: Origin/Referer-vs-Host check on session mutations
(defence in depth atop X-Requested-With); cert path documented as
non-browser / not CSRF-gated.
M-11 AuthInterceptor: optional injected RateLimiter throttles invalid-token
attempts per client IP → 429.
M-12 AuthInterceptor: sanitize request method/path (strip control chars, cap
length) before logging — closes log-line forging (CWE-117).
(M-5 — temporal non-atomic save — was already resolved by the H-4 fix.)
Tests: new test_token_extract / test_rate_limiter / test_origin_check /
test_session_cookie; extended test_redacted_field_repository. All 19 ctest
targets pass. README + header docs updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>