fix(images): make "Save image as" work for local images and refuse honestly for remote ones - #408
Merged
Conversation
PathGao
force-pushed
the
fix/save-image-as-asset-urls
branch
2 times, most recently
from
August 2, 2026 23:11
b3c457d to
29a7417
Compare
…nestly for remote ones
The remote branch fetched the image bytes with `fetch(src)`, which
`connect-src 'self'` refuses - so it was unreachable on every platform,
not merely failing. Windows fell into that same unreachable branch for
*local* images too, because the local test was `src.startsWith('asset:')`
while Windows asset URLs are `http://asset.localhost/...`.
Reuses `normalizeAssetPath` from #363 rather than another hand-rolled
prefix test. It handles both URL shapes and rejects
`http://asset.localhost.evil.test/...`, which a `startsWith` check accepts
and would have handed to `copy_file`.
The dead fetch path is deleted. The remote case now bails before opening a
save dialog it cannot honour, and says why, instead of leaving code that
reads like a feature. Supporting it needs a download command in Rust.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PathGao
force-pushed
the
fix/save-image-as-asset-urls
branch
from
August 2, 2026 23:13
29a7417 to
03d3c24
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The defect
The remote branch fetched the bytes with
fetch(src)— andconnect-src 'self'refuses every cross-origin fetch, so that branch was unreachable on every platform, not merely failing. (img-srcallowinghttps:only affects<img>loading, notfetch.)Windows fell into that same unreachable branch for local images too: the local test was
src.startsWith('asset:'), while Windows asset URLs arehttp://asset.localhost/….The fix reuses #363
normalizeAssetPathhandles both URL shapes and — the part a hand-rolled prefix test gets wrong — rejectshttp://asset.localhost.evil.test/C:/secret.png, whichstartsWith('http://asset.localhost')accepts and would have handed tocopy_file. That hole is real in the original implementation; the test asserts it.The dead fetch path is deleted. The remote case now bails before opening a save dialog it cannot honour, and says why, rather than leaving code that reads like a feature. Supporting it needs a download command in Rust — out of scope here.
save_file_binaryis now unreferenced from the frontend; left registered in Rust.Tests
scripts/saveImageAsAssetUrl.test.ts, including a pin on"connect-src": "'self'"so the explanation in the source cannot go stale silently.Not covered
data:image sources — decodable in pure JS, but scope creep.🤖 Generated with Claude Code