Add view tokens for non-public gallery images and per-mode gate pages.

<img> tags cannot send Authorization headers, so non-public gallery photos
were invisible even to authorized viewers. The server now mints short-lived
HMAC view tokens (gallery-scoped, hour-bucketed) and embeds them in every
file URL for non-public galleries. Access denials return distinct 403
messages per visibility mode, and the frontend renders a matching gate page
(private, link-only, ticket-holders, login prompt) with an inline login
modal so visitors never leave the gallery page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michilis
2026-07-26 06:48:05 +00:00
co-authored by Claude Opus 4.6
parent 93476ac72a
commit 617c884012
9 changed files with 453 additions and 64 deletions
+10
View File
@@ -60,6 +60,16 @@ type photoJSON struct {
URLs photoURLs `json:"urls"`
}
// viewTokenFor returns the token to embed in a gallery's file URLs: none
// for public galleries (files are anonymously accessible), a short-lived
// gallery-scoped view token otherwise (see viewtoken.go).
func (s *Server) viewTokenFor(g store.Gallery) string {
if g.Visibility == store.VisibilityPublic {
return ""
}
return mintViewToken([]byte(s.cfg.JWTSecret), g.ID)
}
func isoTime(t time.Time) string {
if t.IsZero() {
return ""