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:
co-authored by
Claude Opus 4.6
parent
93476ac72a
commit
617c884012
@@ -76,7 +76,7 @@ func (s *Server) createGallery(w http.ResponseWriter, r *http.Request, user auth
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, map[string]any{
|
||||
"gallery": s.galleryToJSON(r.Context(), g, "", true),
|
||||
"gallery": s.galleryToJSON(r.Context(), g, s.viewTokenFor(g), true),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func (s *Server) listGalleries(w http.ResponseWriter, r *http.Request, _ auth.Us
|
||||
}
|
||||
out := make([]galleryJSON, 0, len(galleries))
|
||||
for _, g := range galleries {
|
||||
out = append(out, s.galleryToJSON(r.Context(), g, "", true))
|
||||
out = append(out, s.galleryToJSON(r.Context(), g, s.viewTokenFor(g), true))
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"galleries": out})
|
||||
}
|
||||
@@ -106,12 +106,13 @@ func (s *Server) getGallery(w http.ResponseWriter, r *http.Request, _ auth.User)
|
||||
writeStoreError(w, err, "")
|
||||
return
|
||||
}
|
||||
urlToken := s.viewTokenFor(g)
|
||||
out := make([]photoJSON, 0, len(photos))
|
||||
for _, p := range photos {
|
||||
out = append(out, s.photoToJSON(p, "", true))
|
||||
out = append(out, s.photoToJSON(p, urlToken, true))
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"gallery": s.galleryToJSON(r.Context(), g, "", true),
|
||||
"gallery": s.galleryToJSON(r.Context(), g, urlToken, true),
|
||||
"photos": out,
|
||||
})
|
||||
}
|
||||
@@ -174,7 +175,7 @@ func (s *Server) updateGallery(w http.ResponseWriter, r *http.Request, _ auth.Us
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"gallery": s.galleryToJSON(r.Context(), g, "", true),
|
||||
"gallery": s.galleryToJSON(r.Context(), g, s.viewTokenFor(g), true),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -211,7 +212,7 @@ func (s *Server) rotateShareToken(w http.ResponseWriter, r *http.Request, _ auth
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"gallery": s.galleryToJSON(r.Context(), g, "", true),
|
||||
"gallery": s.galleryToJSON(r.Context(), g, s.viewTokenFor(g), true),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user