Commit graph

2 commits

Author SHA1 Message Date
Johannes Millan
0286cd3b5d feat(electron): restore bmp/avif background image support 2026-06-10 17:04:26 +02:00
johannesjo
601a26c1f7 feat(electron): image picker copy-to-cache (Phase 3 of #8228)
The background-image picker previously gave the renderer an absolute
path to an arbitrary image-extension file and stored it as a file://
URL in user config. The render path then asked main to inline that
file:// on every theme apply. Main only refused paths inside userData,
so a compromised renderer could swap the stored value to any png/jpg/
gif/webp/svg path outside userData and re-read it for as long as it
stayed in config.

Switch the picker to copy-to-cache, serve by opaque id:

- electron/image-cache.ts (new): main-owned directory at
  `userData/bg-images/<id>.<ext>`. importImage(absolutePath) validates
  the source (outside userData, allowed extension, 5 MB cap, non-empty,
  is-file), copies it in, and returns a `randomBytes(16)` hex id. The
  id is unguessable so a renderer cannot iterate the cache directory
  for files it didn't import. getImageDataUrl(id) reads the cached
  file and returns a `data:<mime>;base64,…` URL, or null.

- electron/local-file-sync.ts: two new IPCs, IMAGE_CACHE_IMPORT and
  IMAGE_CACHE_GET_DATA_URL, registered next to the existing image
  handlers.

- electronAPI.d.ts + preload.ts: imageCacheImport / imageCacheGetDataUrl
  bindings.

- formly-image-input.component: after showOpenDialog returns a path,
  call imageCacheImport(path) and store `image:<id>` in the form
  control. Surface the existing "couldn't read image" snack on
  rejection. Removes the toFileUrl round-trip and removes the
  absolute-path leak into user config.

- resolve-bg-image-to-data-url.util: handle the `image:<id>` prefix by
  calling imageCacheGetDataUrl. Legacy `file://` values are still
  accepted for back-compat (the existing userData-guarded
  READ_LOCAL_IMAGE_AS_DATA_URL handles them); since the picker no
  longer produces new file:// values, the long-tail drains as users
  re-pick. A future commit can remove the legacy code path.

Tests:
- electron/image-cache.test.cjs: 12 cases — happy path, in-userData
  rejection, bad extension, too-large / empty / missing source,
  non-string input, unknown / malformed id, cross-restart persistence,
  removeCachedImage.
- electron/local-file-sync.test.cjs: 3 new IPC-level cases for
  IMAGE_CACHE_IMPORT (round-trip, userData refusal) and
  IMAGE_CACHE_GET_DATA_URL (unknown id).
- formly-image-input.component.spec: rewritten to assert
  imageCacheImport is called and `image:<id>` is what lands in the
  form, plus a failure-path snack assertion.

67 of 67 electron security tests pass; 6 of 6 formly-image-input
karma tests pass; lint and tsc clean.
2026-06-09 23:28:14 +02:00