Skip to content

Phase 2: abuse resistance and information leakage (frontend) - #3

Merged
subhanlone merged 4 commits into
masterfrom
fix/phase-2-abuse-resistance
Aug 30, 2026
Merged

Phase 2: abuse resistance and information leakage (frontend)#3
subhanlone merged 4 commits into
masterfrom
fix/phase-2-abuse-resistance

Conversation

@subhanlone

Copy link
Copy Markdown
Owner

Summary

Frontend companion to bidvault-backend's Phase 2 PR.

  • Stores the replacement session change-password now issues, so the user is not signed out of the device they just used to change their own password.
  • Gives seller and admin the password-change surface buyer already had.
  • Shows the validation message the backend actually sends instead of a generic error.
  • Upload signature request posts only the parameters the backend signed (BV-024's tightened Cloudinary signature).

Test plan

  • npm run build
  • npm run lint
  • CI green on this PR

Generated with Claude Code

https://claude.ai/code/session_0151oceeiAyJdi6T273spk4P

subhanlone and others added 4 commits August 27, 2026 19:03
Cloudinary rebuilds the signature from the parameters it recognises and ignores
the rest, so an extra field makes the upload fail with 401 Invalid Signature
rather than being harmlessly dropped. max_file_size is not an Upload API
parameter, and sending it broke every upload -- verified against the live API,
which reported the string it had signed with the field absent.

Now posts the server-issued public_id, which pins the asset to this seller and
is checked again when the listing is submitted, and allowed_formats, which
Cloudinary does enforce.

The file-type check narrows from any image/* to the three formats the backend
allows, so the browser refuses what Cloudinary would refuse anyway rather than
uploading it first. The 5 MB check stays a courtesy: it saves a doomed upload
and a token from the signature route's hourly budget, but Cloudinary's Upload
API has no per-request size cap, so nothing server-side enforces it and the
backend no longer publishes it as policy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcxUSuo3zd4z4TRHh58iop
Two defects found by driving the real UI, not by tests.

A validation failure answers with a constant top-level `error` -- "Validation
error" -- and puts the actionable part in `details`, a field -> messages map.
services/api.ts did not carry `details` in its response type at all and threw
away everything but `error`, so every field-level rejection in the app rendered
as the same unactionable sentence. Rejecting "password123" showed "Validation
error" while the server had said "Choose a less common password". Phase 2 widened
this vocabulary considerably -- password strength, length caps, the emoji limit,
money bounds -- so what was already wrong became a lot more visible.

Fixed where the error is constructed rather than at each call site, so every
screen benefits and no screen has to remember to.

Separately, the create-listing dropzone advertised "Max 10 MB" in two places
while the check beneath it rejected anything over MAX_IMAGE_BYTES, 5 MB. A 7 MB
photo was refused by a rule the screen never stated. The label is now derived
from the constant so the two cannot drift again.

Verified live: the change-password form now reads "Choose a less common
password" against the field that caused it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AW5Zp1KXWzEvG1KNviCfTh
Backend now revokes every session on a password change, including the
caller's, and hands back a fresh pair with the confirmation (contract
2.1.0). Without storing it, the stale refresh token in localStorage signs
the user out on the next silent refresh -- their own successful password
change logging them out minutes later, mid-task.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114vatC9EkHGSUN9zGfAT3G
…y had

Only BuyerProfile could change its own password -- no admin or seller
screen offered it, and no route existed for a seller one at all. Admin
gets a Security card inline in the existing Settings page, next to the
read-only Admin Profile card. Seller gets a new Profile screen (mirroring
BuyerProfile's layout: stats, account info, recent listings, quick links)
reachable the same way Buyer's is -- clicking the avatar/name in the
navbar, which SellerNavbar's did not link anywhere before this.

Both Security cards are the same inline form buyer's already has, copied
rather than extracted into a shared component: each lives in a screen with
its own loading/error handling and its own header, and the three copies
are three fields and two handlers, not enough to justify the indirection.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114vatC9EkHGSUN9zGfAT3G
Copilot AI lite review requested due to automatic review settings August 30, 2026 21:54
@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
bidvault Ready Ready Preview Aug 30, 2026 9:54pm

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@subhanlone
subhanlone merged commit c86373a into master Aug 30, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants