v0.165.0: Indítópult megosztása — guest launcher via capability URL (+ optional password, QR)

Mint a 160-bit capability URL (/s/<token>) serving a standalone read-only guest
launcher: same tiles, opens apps in new tabs, no account, no admin session.
Information only, zero control — every privilege stays behind each app's own auth.

- /s/ pre-auth pass-through (after the claim gate) + session-CSRF exemption; guest
  password POST carries its own pre-auth HMAC CSRF.
- Constant-time token match; empty stored token = disabled = byte-identical mux 404.
- Optional per-share password: separate bcrypt hash + own attempt map; signed cookie
  = HMAC(token|passwordHash) keyed with web.session_secret, so rotate/change invalidates.
- Guest labels ride the v0.164.0 ruling; never expose internal state vocabulary.
- Token redacted in logs (/s/<redacted>); never in CHANGELOG/REPORT/CONTEXT.
- Admin modal: copy-link, QR (go-qrcode), set/clear password, rotate, disable.
- Tests: Groups A-G (14) + 3 red-proofs verified red.
This commit is contained in:
2026-07-24 12:08:43 +02:00
parent 8e5edb2865
commit 15206314ab
19 changed files with 1341 additions and 115 deletions
+4 -1
View File
@@ -34,7 +34,10 @@ func (s *Server) CsrfProtect(next http.Handler) http.Handler {
// Claim/reset POSTs carry their OWN pre-auth HMAC CSRF (validated in the handler) — the
// customer resetting a claimed box has no session yet, so the session-CSRF path can't apply.
if r.URL.Path == "/claim" || r.URL.Path == "/claim/request-new-code" {
// The guest launcher share password POST (/s/<token>, v0.165.0) is the same shape: no admin
// session, own pre-auth HMAC CSRF (validShareCSRF). The admin share-management POSTs live
// under /launcher/share/* and are NOT exempted — they ride the normal session CSRF below.
if r.URL.Path == "/claim" || r.URL.Path == "/claim/request-new-code" || strings.HasPrefix(r.URL.Path, "/s/") {
next.ServeHTTP(w, r)
return
}