Commit Graph
3 Commits
Author SHA1 Message Date
John O'Keefe 431fec05ad feat(security): library visibility enforced at the source; per-library series; annotation ownership; admin user creation
The family-lens hardening: library_visibility was only enforced where
file bytes flowed (download/reader/OPDS) — metadata surfaces leaked
hidden libraries to any authenticated account, and registration was
open by default with no admin-side user creation.

- Series are grouped PER LIBRARY now (same name in two libraries =
  two entries: manga adaptations / LN splits no longer merge);
  /api/series aggregates only the requester's VISIBLE libraries and
  /api/series/books REQUIRES a visible library_id (breaking contract;
  web + app clients updated in the same change).
- /api/media-items, item detail, and the reader content endpoints
  (chapters/panels/outline/THUMBNAILS — page images leaked unguarded
  next to a gated GetPage) all enforce the visible set; resolveLibrary
  no longer honors a hand-typed library_id outside the visible set.
- Annotation/note/bookmark mutations (update/delete/tombstone, sync
  LWW paths incl. conflict resolution) carry ownership predicates:
  another account's bare row id is a 404, not a silent delete.
- Admin user creation: POST /api/auth/users (AdminMiddleware) + a
  Create User card in the admin Users UI — accounts stay creatable
  with self-service registration OFF, which is now the schema default
  (fresh installs; the first-admin bootstrap exception is unchanged).
- Tests: series contract re-pinned (per-library, visibility 403s),
  new ownership + admin-create integration suites, OPDS all=1 test
  now passes an explicit page size (shared-DB growth made the fresh
  books fall off page 1), device-cap helper switched to the admin
  endpoint.
2026-10-13 12:03:01 -04:00
john-okeefe a6f5d8d693 refactor(handlers): relax library_id validation for All Libraries
- dashboard.go: library_id query param is now optional. Empty/missing
  library_id is passed as pgtype.UUID{Valid: false} to the service
  layer, enabling All Libraries mode.

- series.go: library_id is optional for series listing. GetSeriesBooks
  no longer receives a libraryID — it always returns all books in a
  series regardless of library.

- collections.go: Restructure GetCollection to handle system
  collections (query_type != "") with an optional libraryID. When
  libraryID is empty (All Libraries), GetDashboardSections receives
  pgtype.UUID{Valid: false} so no library filter is applied.
2026-05-18 17:52:37 -04:00
john-okeefe 004b761381 feat(series): add SeriesHandler, API routes, and SSR browse page
Create SeriesHandler with two API endpoints:
- GET /api/series (paginated series list with covers)
- GET /api/series/books (books in a specific series)
Uses query param ?name=X instead of path param to avoid URL encoding
issues with special characters in series names.

Add GetSeriesCardsData helper returning services.SeriesInfo for use
by the SSR route (avoids handlers→templates import cycle).

Register /api/series routes via registerSeriesRoutes in router.
Add /series SSR route in frontend.go with library-scoped pagination
and error handling, matching the dashboard/bookshelf patterns.

Add SeriesHandler to router Config and instantiate in main.go.

Add SeriesCardData type to templates/types.go.

Add Continue Series as the 5th valid system collection in
dashboard handler and auth handler's CreateDefaultCollectionsForUser.
2026-05-08 20:27:01 -04:00