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:
1 parent
c4aa345914
commit
94859fb0d6
13 files changed
+163
-1
No files matched your search
@@ -26,6 +26,39 @@ type photoJSON struct {
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// handleSession reports whether the request carries valid credentials, so the
|
||||
// UI can reveal management links and a signed-in indicator. It always returns
|
||||
// 200 and never sends WWW-Authenticate, so calling it from a public page does
|
||||
// not trigger the browser's Basic-auth dialog.
|
||||
//
|
||||
// It must not become a password-probing oracle that sidesteps the /upload
|
||||
// limiter: a request with no credentials (a logged-out browser) is answered
|
||||
// cheaply as "not authenticated", but one carrying wrong credentials is run
|
||||
// through the same failed-attempt limiter and gets 429 once that is drained.
|
||||
func (s *Server) handleSession(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
|
||||
if s.auth == nil { // auth disabled → everything is open
|
||||
writeJSON(w, map[string]bool{"authenticated": true})
|
||||
return
|
||||
}
|
||||
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
writeJSON(w, map[string]bool{"authenticated": false})
|
||||
return
|
||||
}
|
||||
if s.auth.check(user, pass) {
|
||||
writeJSON(w, map[string]bool{"authenticated": true})
|
||||
return
|
||||
}
|
||||
if !s.authLimit.Allow() {
|
||||
http.Error(w, "too many attempts", http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
writeJSON(w, map[string]bool{"authenticated": false})
|
||||
}
|
||||
|
||||
// handleManagePage serves the (auth-gated) edit/delete UI.
|
||||
func (s *Server) handleManagePage(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := assets.ReadFile("templates/manage.html")
|
||||
|
||||
Reference in new issue
Block a user