Show management links and a signed-in indicator when logged in

Add GET /api/session, an unguarded probe that reports whether the request
carries valid credentials. It returns 200 with {"authenticated":bool} and never
sends WWW-Authenticate, so the static public pages can check login state without
triggering the browser's Basic-auth dialog. To keep it from being a
password-guessing oracle that bypasses the /upload limiter, a request with no
credentials is answered cheaply as false, while wrong credentials go through the
same failed-attempt limiter (429 once drained).

static/session.js, loaded by every page template, calls it and, only when
authenticated, builds a fixed toolbar: Upload / Manage links, an "Edit this"
link on photo pages (via <body data-slug>, deep-linking to /manage?edit=<slug>,
which scrolls to and focuses that row), a signed-in indicator, and a log-out
control. Logged-out visitors see nothing and get no dialog.

Log out is best-effort: HTTP Basic has no reliable sign-out (the browser caches
credentials until the window closes), so it overwrites the cached credential and
reloads, which works in some browsers but not all. A dependable logout would
need cookie sessions.
This commit is contained in:
puttaalu committed 2026-10-18 22:52:59 +02:00
1 parent c4aa345914
commit 94859fb0d6
13 files changed
+163 -1

No files matched your search

+12
View File
@@ -41,6 +41,18 @@ credentials matching a line in that file; `GET /health` stays open. `$2y$`
`$apr1$`, SHA, crypt) are skipped with a warning. Empty `-htpasswd` disables
auth entirely (dev default) and logs a warning — `/upload` is then open.
`GET /api/session` is a deliberately **unguarded** probe (`handleSession`): it
reads `r.BasicAuth()`, returns `200 {"authenticated":bool}` and never sends
`WWW-Authenticate`, so a public page can ask without triggering the browser's
login dialog. To stop it becoming a password oracle that sidesteps the limiter,
a request with no credentials is answered cheaply as `false`, while one with
*wrong* credentials runs through the same failed-attempt limiter (429 once
drained). `static/session.js` (loaded by every page template) calls it and, when
authenticated, builds a fixed toolbar with Upload / Manage / "Edit this"
(`/manage?edit=<slug>`, from the photo pages' `data-slug`) links and a
signed-in indicator. "Log out" is best-effort only — HTTP Basic has no reliable
sign-out; a dependable one would need cookie sessions.
Verification lives in `auth.go`: unknown users still pay for one bcrypt
comparison (against a dummy hash) so timing can't enumerate usernames, and
**failed** attempts draw from a token-bucket limiter (`golang.org/x/time/rate`,