Commit Graph

5 Commits

Author SHA1 Message Date
1b917540f4 test: Phase 4 — vitest setup + unit tests for admin-session and rate-limit
Establishes the test suite. The repo previously had zero tests and no
test framework installed.

Tooling:
- Vitest 2 added as devDependency. Chosen for ESM-native + TypeScript
  out-of-the-box, no Babel/ts-node, and fast cold starts.
- vitest.config.ts sets environment=node and wires the '@/'
  path alias so tests can import app modules by the same path the
  app uses.
- package.json scripts: 'test' (vitest run, CI-friendly) and
  'test:watch'; also adds the long-missing 'typecheck' wrapper for
  'tsc --noEmit'.
- tsconfig.json now excludes *.test.ts from the app's build graph so
  the production bundle doesn't pull in test files (the editor still
  type-checks them via vitest).

Tests:
- admin-session.test.ts (8 cases): sign/verify round-trip for ADMIN
  and SUPER_ADMIN, tampered payload rejection (privilege-escalation
  attempt — should be rejected because the HMAC no longer matches),
  tampered signature rejection, missing-separator token, invalid
  base64/JSON payload, and cookie option flags (httpOnly, sameSite,
  path, secure under NODE_ENV=test vs production).
- rate-limit.test.ts (4 cases): basic token bucket within window,
  independent key tracking, refill after window elapses (fake
  timers), and remaining-counter accounting.

12 tests, all green.
2026-08-02 13:05:06 +02:00
3ff24cda0b feat(security): Phase 1 — harden auth, rate limiting, CSRF, upload validation
Security hardening covering credentials, brute-force protection, CSRF,
TOCTOU races, upload validation, and migration failure handling.

Secret rotation is deferred; the existing secrets in .env will be
rotated in a later phase. This phase reduces the attack surface and
removes the most exploitable issues.

Removed:
- Hardcoded 'super'/'admin' super-admin credentials in
  src/app/api/admin/login/route.ts. Username/hash are now loaded from
  env (SUPER_ADMIN_USERNAME / SUPER_ADMIN_PASSWORD_HASH) and verified
  via bcrypt like regular admins.

Added:
- src/lib/config.ts: single source of truth for APP_DOMAIN,
  APP_URL, subdomain regex/lengths, validation bounds, admin password
  policy, image-key allow-list regex, and super-admin env credentials.
- src/lib/rate-limit.ts: in-memory LRU (via lru-cache) rate limiters —
  admin login (5/min), validate-code (20/min), check-subdomain
  (60/min), upload (10/min) — keyed by client IP, returning 429 with
  X-RateLimit-* headers.
- requireAdmin / requireAdminPost / requireSuperAdminPost guards in
  src/lib/admin-session.ts. All admin mutating routes now enforce
  same-origin (Origin/Referer/Host check against NEXT_PUBLIC_APP_URL)
  before running — CSRF protection for the custom admin auth layer.
- Logout now imports COOKIE_NAME_ADMIN instead of hardcoding the string.
- Server-side magic-byte detection for image uploads (no new dep) —
  rejects spoofed Content-Type. GIF removed from allowed types.
- /api/publish is now transactional (prisma.) with
  explicit P2002 → 409 handling for subdomain collisions.
- /api/image validates the key against an allow-list regex and returns
  Macedonian error messages (was the only English-localized file).
- /api/validate-code enforces a 12-hex-char pattern and uses
  updateMany with usedByUserId=null guard to make the claim atomic.
- /api/check-subdomain validates the slug against the shared regex
  before hitting the DB and returns a short private Cache-Control.
- Admin password minimum length bumped from 6 to 12 with letter+digit
  complexity requirement across change-password, users POST and
  users/[id] PUT.

Changed:
- scripts/start.sh: prisma migrate deploy failures now exit non-zero
  instead of silently continuing (prevents schema drift in prod).
- .env.example: documents SUPER_ADMIN_USERNAME /
  SUPER_ADMIN_PASSWORD_HASH with example bcrypt-hash generation.
- package.json: lru-cache added as direct dependency (already present
  transitively, promoted to explicit).
2026-08-02 10:24:28 +02:00
8569b506d2 feat(db): add AdminUser and Code models with migration
- Add AdminUser model (username, passwordHash, role enum)
- Add Code model (code, createdBy, usedByUserId, timestamps)
- Install bcryptjs for password hashing
- Run migration add_admin_and_code
2026-07-29 18:54:40 +02:00
6bb72dc97f local dev setup 2026-07-29 16:52:54 +02:00
4fdb51f583 init 2026-06-20 18:17:30 +02:00