- Session-based login (username/password, 30-day cookie) - SQLite user store with bcrypt password hashing (modernc.org/sqlite) - Per-user upload permission (can_upload flag) - Admin CLI (cmd/admin) for user management: user add/list/delete/set-upload - Upload handler for EPUB/PDF with path-traversal protection - All routes protected by requireAuth middleware; /upload additionally requires requireUpload - Login/logout UI, upload form, logout button in header - New env var: USERS_DB (default: users.db, gitignored) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
68 lines
3.3 KiB
Markdown
68 lines
3.3 KiB
Markdown
# eBook Library (Go + templ)
|
|
|
|
Minimalistic, no-JS eBook library web app for reading files (EPUB/PDF) on a
|
|
Tolino e-reader browser. UI text/comments are in German.
|
|
|
|
## Build & run
|
|
|
|
```bash
|
|
go mod tidy # install deps
|
|
templ generate # regenerate views/*_templ.go from views/*.templ (required after editing .templ files)
|
|
go build ./... # build check
|
|
go run ./cmd/server # run dev server on :8080
|
|
```
|
|
|
|
- `templ` CLI is required whenever `views/pages.templ` changes — generated
|
|
Go code lives in `views/pages_templ.go` and is checked into the repo, so it
|
|
must be regenerated and committed together with template edits.
|
|
- No test suite exists yet.
|
|
- Config via env vars: `ADDR` (default `:8080`), `BOOKS_DIR` (default `books`),
|
|
`USERS_DB` (default `users.db`).
|
|
|
|
## Admin CLI
|
|
|
|
```bash
|
|
go run ./cmd/admin user add <name> [--upload] # Benutzer anlegen
|
|
go run ./cmd/admin user list # alle Benutzer
|
|
go run ./cmd/admin user delete <name> # löschen
|
|
go run ./cmd/admin user set-upload <name> <true|false>
|
|
```
|
|
|
|
## Architecture
|
|
|
|
- `cmd/server/main.go` — entrypoint; wires `library.Service`, `users.Store` and
|
|
`web.Handler` together and starts the HTTP server.
|
|
- `internal/library` — core domain logic, no HTTP dependency (unchanged).
|
|
- `internal/users/store.go` — SQLite-backed user store (`modernc.org/sqlite`,
|
|
pure Go driver). Tables: `users` (id, username, password_hash bcrypt,
|
|
can_upload), `sessions` (token, user_id FK, expires_at unix timestamp).
|
|
Sessions TTL = 30 days. Key methods: `Authenticate`, `CreateSession`,
|
|
`LookupSession`, `DeleteSession`, `CreateUser`, `SetUpload`, `DeleteUser`, `ListUsers`.
|
|
- `cmd/admin/main.go` — CLI binary for user management; reads `USERS_DB` env var.
|
|
- `internal/web/handlers.go` — HTTP handlers including `loginPage`,
|
|
`loginSubmit`, `logout`, `uploadPage`, `uploadSubmit`.
|
|
- `internal/web/middleware.go` — `requireAuth` and `requireUpload` middleware;
|
|
session resolved from `"session"` cookie; stored in request context via `sessionKey`.
|
|
- `views/pages.templ` — `LoginPage(errMsg)`, `UploadPage(errMsg)` added;
|
|
`IndexPage` now takes `canUpload bool`; `Layout` includes logout button.
|
|
|
|
## Conventions
|
|
|
|
- Path traversal guards matter: `downloadBook` validates the resolved book
|
|
path stays within `BooksDir()` before serving; `cleanEPUBPath` rejects
|
|
`../`-escaping hrefs inside EPUB zips; `uploadSubmit` validates the
|
|
destination path stays within `BooksDir()`. Preserve these checks in any
|
|
related changes.
|
|
- Cover image reads are capped (`maxCoverBytes = 10 MiB`) to avoid decompression
|
|
abuse — keep similar limits when reading zip entries.
|
|
- Handlers return `404` for missing/empty `id` and `500` on internal errors;
|
|
keep that pattern for new routes.
|
|
- Auth: `/login` and `/static/` are the only public routes — everything else
|
|
goes through `requireAuth`. Routes needing upload permission use `requireUpload`
|
|
(which wraps `requireAuth`).
|
|
- Session cookie: `HttpOnly`, `SameSite=Lax`, 30-day expiry; no `Secure` flag
|
|
set (intended for LAN use without TLS).
|
|
- `modernc.org/sqlite` is a pure-Go SQLite driver (no CGo). `MaxOpenConns(1)`
|
|
is set because SQLite doesn't support concurrent writers.
|
|
- `users.db` is gitignored; create it at runtime with the admin CLI.
|