Commit Graph

35 Commits

Author SHA1 Message Date
c0effe6ec9 refactor(quality): Phase 2 — split templates, consolidate constants, in-house QR
Code quality pass driven by the plan. Eliminates the duplicated
constants, breaks the 216-line templates file into per-template files,
and removes the third-party QR dependency that was leaking memorial
URLs to api.qrserver.com.

Templates (src/lib/templates.tsx → src/lib/templates/):
- Split into Elegance.tsx, Cinematic.tsx, Serene.tsx and a shared.tsx
  holding formatDates() and MemorialFooter.
- New index.tsx re-exports everything plus renderTemplate(), so the
  existing '@@/lib/templates' import paths are unchanged.
- Adds eslint-disable-next-line @next/next/no-img-element markers on
  the raw <img> tags so the linter (once it works again) won't flag
  them; full migration to next/image is deferred to a later phase
  pending next.config remotePatterns verification.

QR consolidation:
- dashboard/page.tsx now uses lib/qrcode.ts::generateMonumentQR
  (server-rendered async) instead of api.qrserver.com. The external
  service was logging every memorial URL to a third party.
- lib/qrcode.ts reads APP_DOMAIN from the shared config (was
  process.env.NEXT_PUBLIC_APP_DOMAIN inline). Added
  generateMonumentQRPng() helper for the download path.
- Dashboard 'Превземи QR код' link now points at the data: URL in-app
  and downloads as '{subdomain}-qr.png'.

Config consolidation:
- SubdomainPicker.tsx now imports APP_DOMAIN, SUBDOMAIN_MIN_LENGTH
  and SUBDOMAIN_MAX_LENGTH from lib/config; previously the slug was
  normalized with a regex that didn't match the server's stricter
  /^[a-z0-9][a-z0-9-]*[a-z0-9]$/ rule and the success message
  hardcoded '.testbed.mk'.
- ImageUploader.tsx re-imports MAX_FILE_SIZE / ALLOWED_TYPES /
  MAX_FILES from lib/upload (they were literally redefined inline,
  causing drift risk). The remaining client-side filter uses a
  string-cast to satisfy the readonly-tuple type.
2026-08-02 12:15:19 +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
2418553172 superAdmin and admin implemented 2026-08-01 23:42:42 +02:00
7046c3375f fix: add credentials: include to admin fetch calls for cookie consistency 2026-07-29 20:06:28 +02:00
faa8216716 fix: set cookie path to / so admin API routes receive the session
Cookie path was /admin, but admin API routes live under /api/admin/.
Browser only sends cookies to paths matching the cookie's path, so
all API calls were unauthenticated. Changed path to / for both
cookie creation (login) and deletion (logout).
2026-07-29 19:56:16 +02:00
117f9fadfc fix: exempt /api/admin/login from admin session check in middleware
The login API was blocked by the admin session middleware, preventing
the creation of the session cookie. Now the API endpoint is exempted
alongside the login page.
2026-07-29 19:46:08 +02:00
09acf20b9b fix(admin): restructure routes into groups to prevent redirect loop
- Move login page into (auth) route group — no layout wrapper
- Move dashboard/users/codes + layout into (panel) route group —
  session check and sidebar only apply to these
- URL paths remain unchanged (/admin/login, /admin/dashboard, etc.)
2026-07-29 19:28:44 +02:00
eafefcb1da docs: add implementation plan and gitignore for old build artifacts 2026-07-29 19:08:14 +02:00
0d00b1ec9c fix(build): use Web Crypto API for Edge Runtime compatibility + final build verification
- Rewrite admin-session.ts to use Web Crypto API (crypto.subtle) instead
  of Node.js crypto module, ensuring compatibility with Edge Runtime
  in middleware
- Add ADMIN_SESSION_SECRET to .env.example
- Build passes with zero warnings
2026-07-29 19:07:43 +02:00
94ef7901e2 feat(code-gating): add code validation and enforce code usage for memorial creation
- Add /api/validate-code endpoint: validates code, marks it as used by
  the current Clerk user, prevents reuse
- Add 'Код' step to onboarding wizard (step 0): user must enter and
  validate a code before proceeding to fill memorial details
- Protect /api/publish: reject with 403 if user has not consumed a valid
  code
- Code input auto-capitalizes on the onboarding page
2026-07-29 18:58:18 +02:00
9ca66fc753 feat(admin): add admin panel with dashboard, users, and codes management
- Add admin layout with sidebar navigation and session guard
- Create AdminSidebar client component with role-based nav links
- Add dashboard page showing stats (admin count, code counts)
- Add users management page (SuperAdmin only): list, create, delete,
  and reset passwords for admin users
- Add codes management page: list all codes, generate new codes,
  delete unused codes
- Add API routes for admin user CRUD (GET, POST, DELETE, PUT)
- Add API routes for code management (GET, POST, DELETE)
- All UI in Macedonian
2026-07-29 18:56:49 +02:00
14d0b533af feat(auth): add admin authentication with HMAC session cookies
- Create admin-session lib with sign/verify helpers using HMAC-SHA256
- Add admin login API that checks hardcoded super/admin credentials
  and DB-stored admin users with bcrypt password comparison
- Add admin logout API to clear session cookie
- Add change-password API for admin self-service password changes
- Create admin login page with Macedonian UI
- Update middleware to protect /admin/* and /api/admin/* routes
  with admin session check, bypassing Clerk auth
2026-07-29 18:55:46 +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
c51ff09cdc backup 2026-07-24 04:11:40 +02:00
db88626eeb claudflare wildcard ssl migration docs 2026-06-23 00:54:08 +02:00
49b8023f37 cool fix 2026-06-22 23:44:51 +02:00
da84f7b968 img fix 2026-06-22 23:39:19 +02:00
677322db7e t v3 2026-06-22 23:28:41 +02:00
749d86d8ef http,https 2026-06-22 23:12:20 +02:00
9052224ad3 proxy fix 2026-06-22 23:01:42 +02:00
17f362f6d6 traefix conf, subdomain fix 2026-06-22 22:22:11 +02:00
aea4713aeb subdomain fix 2026-06-22 21:57:17 +02:00
afa6630a83 db network fix 2026-06-22 21:36:22 +02:00
58ad68836b env @build 2026-06-22 05:44:29 +02:00
9e0093bf7f prisma fix 2026-06-22 05:14:47 +02:00
85669b8395 fix 2026-06-22 04:43:57 +02:00
77e2e4a959 yaml 2026-06-22 04:30:02 +02:00
bf925c0ca8 composr 2026-06-22 04:27:05 +02:00
9039f00ed0 dep fix 2 2026-06-22 04:05:35 +02:00
47670f8313 deploy fix 2026-06-22 03:53:47 +02:00
ef3643a713 img fix applyed 2026-06-22 02:34:32 +02:00
5aeb5a0db2 translation done 2026-06-20 19:44:36 +02:00
ff93e8c5be template refinement 2026-06-20 19:28:05 +02:00
4fdb51f583 init 2026-06-20 18:17:30 +02:00