gendesign/tradein-mvp/frontend
lekss361 5bd9c2f66d fix(tradein-frontend): safeUrl validator, apiFetch dedup, ListingsCard a11y, error boundary
Four security/UX fixes from 2026-05-24 audit:

* lib/safeUrl.ts (new): validate external URLs, reject non-http(s) schemes
  (closes finding #3 — backend supplies lot.source_url verbatim from scraped
  sites; javascript:/data:/file: would have executed on click).
* lib/api.ts: refactor apiFetch to delegate to apiFetchWithStatus — single
  read-body-once implementation, drops the body-stream-twice anti-pattern
  (finding #8).
* components/trade-in/ListingsCard.tsx: drop tr.onClick (not keyboard
  accessible), keep the inline <a> as the only interactive element, gate it
  through safeUrl() (findings #7 + #3).
* app/error.tsx (new): Next 15 App Router route-segment error boundary —
  prevents white-screen on component crash (finding #16).

Scope-cut from original audit:
* #17 (sessionId crypto.randomUUID) — already implemented in sessionId.ts;
  no change needed.
* safeUrl wiring in DealsCard / IMVBenchmark — neither renders user-supplied
  URLs (DealsCard has no links, IMVBenchmark links a hardcoded domain).
2026-05-24 14:38:56 +03:00
..
public fix(tradein): commit empty frontend/public via .gitkeep 2026-05-21 00:59:13 +03:00
src fix(tradein-frontend): safeUrl validator, apiFetch dedup, ListingsCard a11y, error boundary 2026-05-24 14:38:56 +03:00
.dockerignore feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
Dockerfile fix(tradein): HOSTNAME=0.0.0.0 + NEXT_PUBLIC_API_BASE_URL build-arg 2026-05-21 10:21:32 +03:00
next.config.ts fix(tradein): убрать basePath redirect-loop 2026-05-21 01:05:49 +03:00
package.json feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
tsconfig.json feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00