fix(web): avatar preview uses a data: URL, not a CSP-blocked blob: URL (BUNYIP-408) #401
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/BUNYIP-408-avatar-preview-csp"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptoms
"Change photo doesn't work", plus in the console:
Loading the image 'blob:https://a8n.systems/...' violates the following Content Security Policy directive: "img-src 'self' data: https:"/settings/avatar:1 Failed to load resource: the server responded with a status of 400Two separate issues
1. CSP-blocked preview - real code bug, fixed here
The instant local preview used
URL.createObjectURL(file), which yields ablob:URL. The page CSP isimg-src 'self' data: https:(noblob:), so the preview image was refused. Fixed by previewing with adata:URL (FileReader.readAsDataURL), which the existing CSP already allows - no CSP change required.2. The 400 on /settings/avatar - a stale bunyip-api deployment, not a code bug
settings_avatar(BFF) returns400 BAD_REQUESTwhenever its upstream call toPOST /v1/users/me/avatarerrors. A bunyip-api image that predates the BUNYIP-408 endpoints returns 404 there - which is the "404" originally reported, surfaced to the browser as a 400.I verified the code is correct, so this is a deploy issue:
GET/POST/DELETEon/users/me/avatarall dispatch to their handlers (401 unauthenticated), never 404/405.infer0.16 magic-byte sniff +imagesize0.13 dimension parse). So neither the routes nor the image format is at fault.Recent PRs (#398-#400) were bunyip-web only. If the deploy pipeline only rebuilt bunyip-web, bunyip-api is still on a pre-BUNYIP-408 image. Redeploying bunyip-api restores the upload endpoint.
Also (refinement, not the fix)
Switched the client re-encode from WebP to JPEG with a white backing. Both formats are accepted by the API; JPEG keeps the stored avatar small and flattens transparency to white instead of black.
Verification
just check-containergreen: fmt + clippy-D warnings+ all test binaries (116 web tests).🤖 Generated with Claude Code
Reported: "change photo doesn't work", a CSP violation, and a 400 on /settings/avatar. Two separate things, one of them a real code bug: 1. CSP-blocked preview (fixed here). The instant local preview used `URL.createObjectURL(file)`, which is a `blob:` URL. The page CSP is `img-src 'self' data: https:` - no `blob:` - so the browser refused to render the preview ("Loading the image 'blob:...' violates ... img-src"). Fixed by previewing with a `data:` URL via `FileReader.readAsDataURL` (allowed by the existing CSP), so no CSP change is needed. 2. The 400 on /settings/avatar is NOT a code bug - it is a stale bunyip-api deployment. `settings_avatar` returns BAD_REQUEST whenever the upstream `POST /v1/users/me/avatar` call errors, and a bunyip-api image that predates the BUNYIP-408 endpoints returns 404 there (the "404" originally reported). Confirmed the code is correct: a routing test showed GET/POST/DELETE on `/users/me/avatar` all dispatch (401 unauth, never 404/405), and running a real Chrome-canvas WebP AND JPEG through the API's exact validators (infer 0.16 + imagesize 0.13) both pass - so neither the routes nor the image format is at fault. The recent PRs (#398-#400) were bunyip-web only; redeploying bunyip-api restores the endpoint. Also switched the client re-encode from WebP to JPEG with a white backing: both are accepted by the API, but JPEG keeps the stored avatar small and flattens transparency to white instead of black. This is a refinement, not the fix - the WebP validated fine. Verified: `just check-container` green (fmt + clippy -D warnings + all test binaries, 116 web tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5dcYueNHByRnWJDYoDX1W