Skip to content

fix(themes): guard installed-themes storage against non-array JSON#268

Open
dormouse-bot wants to merge 1 commit into
mainfrom
fix/themes-store-array-guard
Open

fix(themes): guard installed-themes storage against non-array JSON#268
dormouse-bot wants to merge 1 commit into
mainfrom
fix/themes-store-array-guard

Conversation

@dormouse-bot

Copy link
Copy Markdown
Collaborator

Problem

getInstalledThemes() in lib/src/lib/themes/store.ts wraps JSON.parse in a try/catch, so malformed (non-JSON) storage falls back to []. But valid JSON that isn't an array — e.g. localStorage['dormouse:installed-themes'] holding {"id":"oops"} from corruption or external tampering — parses successfully and is returned cast as DormouseTheme[] without any shape check. The non-array value then flows into the spread in getAllThemes() and the .filter(...) in addInstalledTheme() / removeInstalledTheme(), throwing an uncaught TypeError that breaks theme listing and installation entirely.

Found during the nightly rolling survey of lib/src/lib/themes/store.ts.

Solution

Add an Array.isArray guard after the parse: a parsed value that isn't an array now falls back to [], matching the existing fail-soft intent of the surrounding try/catch. No behavior change for well-formed storage.

Testing

This module previously had no test file, though every sibling under themes/ does. Added store.test.ts (@vitest-environment jsdom, reusing the sibling installStorageStub pattern) covering:

  • the regression — a valid-but-non-array value now yields [] and doesn't throw through getAllThemes() / addInstalledTheme();
  • non-JSON garbage still yields [];
  • the install/dedupe-by-id path.

The regression test fails on the pre-fix code (getInstalledThemes() returns {id:'oops'} instead of []) and passes with the guard. tsc --noEmit is clean and all 8 themes/ test files pass locally.


Automated nightly survey finding.

A valid-but-non-array value in localStorage (corruption or external
tampering) was returned cast as DormouseTheme[], causing an uncaught
TypeError in getAllThemes()'s spread and addInstalledTheme()'s filter.
Add an Array.isArray guard and a regression test (the module had none).
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 562e206
Status: ✅  Deploy successful!
Preview URL: https://e0a7f3f1.mouseterm.pages.dev
Branch Preview URL: https://fix-themes-store-array-guard.mouseterm.pages.dev

View logs

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.

1 participant