Commit Graph

5 Commits

Author SHA1 Message Date
a4355e1ef3 refactor(auth): drop JWT_EXPIRY env var (family TTL is canonical)
The JWT lifetime is now pinned to SESSION_TTL_SECONDS (30 days)
inside issueSessionCookie, so JWT_EXPIRY had no effect after the
prior commits. Removing the field from Config and the env read in
loadConfig lets the TypeScript compiler verify no caller was still
relying on it.

Per the family invariant ('coherence across apps is a feature'),
the per-app override is intentionally gone — a deploy with stale
JWT_EXPIRY in .env will now silently use the 30-day family default
regardless of the value.

Test fixtures (Config literals in setup.ts, login-handler.test.ts,
lockout-service.test.ts) and config.test.ts assertions updated to
match the new shape.
2026-05-09 10:17:04 -07:00
623a3374cf feat(auth): rename session cookie to nanodrop_session
Flips SESSION_COOKIE_NAME from 'token' to 'nanodrop_session' per the
family per-app naming convention (<app>_session). fastify-jwt's
cookieName in server.ts is now sourced from the constant so a future
rename only needs to touch constants.ts.

Hard-cut migration with no dual-cookie shim: the existing 'token'
cookie has no Max-Age so it dies on browser close anyway, and this
is a single-user deployment per CLAUDE.md. Users re-log in once
after deploy.

Test files updated mechanically: cookies: { token } → cookies: {
nanodrop_session: token } (variable name 'token' kept locally),
clearCookie regex updated, login response now also asserts
Max-Age=2592000 from the family TTL.
2026-05-09 10:12:25 -07:00
bbd292c085 feat(auth): wire lockout, rate-limit, and constant-time login into both routes
All checks were successful
Deploy to Homelab / deploy (push) Successful in 18s
Both POST /login (HTML form) and POST /api/v1/auth/login now flow through
the shared attemptLogin() handler. Locked accounts respond with 401 +
Retry-After (generic body "Invalid credentials" / "Invalid username or
password") so attackers can't use lockout state as a username-existence
oracle.

@fastify/rate-limit registered with global=false; only the two login
routes opt in via per-route rateLimit config. File uploads and downloads
keep full throughput. Custom errorResponseBuilder logs AUTH_RATE_LIMITED
fire-and-forget so fail2ban can pick it up.

createTestApp now accepts Partial<Config> overrides so integration tests
can dial thresholds down without env-var mutation.
2026-05-03 03:41:51 -07:00
418a553429 refactor: remove unused exported type interfaces
All checks were successful
Deploy to Homelab / deploy (push) Successful in 19s
CreateFileParams, UserRow, CreateUserParams, and MultipartFile were
exported but never imported outside their own modules. Narrowed visibility
to module-local to keep the public surface minimal.

Confirmed with knip (zero findings) and all 61 tests passing.
2026-03-17 10:44:23 -07:00
8fd1464b9d Add server, routes, views, CLI, CSS, and integration tests
- Server factory with Fastify plugins (JWT, cookie, multipart, formbody, static)
- Auth middleware: requireAuth preHandler (401 for API, redirect for pages)
- Auth API routes: POST /api/v1/auth/login, POST /api/v1/auth/logout
- File API routes: GET/POST /api/v1/files, DELETE /api/v1/files/:id
- Page routes: /, /login, /logout, /upload, /files, /files/:id/delete, /f/:id, /f/:id/raw
- HTML views: layout, login, upload, file-list, file-view, not-found
- CLI register-user script
- public/style.css dark theme
- Test helpers: createTestApp, loginAs, buildMultipart
- Integration tests for auth API, file API, and page routes (51 tests passing)
- Update CLAUDE.md with red/green TDD and commit instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:55:14 -08:00