Enhancement: ThemeContext reads/writes localStorage without validation #5

Closed
opened 2026-06-17 14:06:32 +00:00 by abumahid · 0 comments
Owner

Description

The ThemeProvider currently reads values from localStorage and casts them directly to application types (ThemeMode and AccentTheme) without runtime validation.

Type assertions only provide compile-time guarantees and do not validate values at runtime. Since localStorage is user-modifiable, corrupted values, unexpected data, or browser-specific storage behavior may result in invalid application state.

Additionally, direct localStorage access assumes storage availability, which may not be true in privacy-restricted environments, browser extensions, embedded webviews, or storage-blocking modes.

Impact

  • Invalid theme values can cause UI inconsistencies.
  • Unexpected values may break theme initialization.
  • Potential runtime errors when storage access is unavailable.
  • Reduced resilience in privacy-focused browsers or restricted environments.
  • Hard-to-debug user-specific UI issues caused by corrupted local storage.

Location

src/contexts/ThemeContext.tsx

Approximate Lines

  • ~20–27 (localStorage reads)
  • ~41–44 (localStorage writes)

Suggested Fix

Validate Stored Values

Before applying values from localStorage, verify they belong to the allowed enum/union values.

Wrap Storage Access

Use try/catch blocks when reading and writing storage values to handle environments where access may fail.

Fallback to Defaults

When invalid values are detected:

  • Ignore the stored value.
  • Use the application's default theme settings.

Example Implementation

Theme Validation

const VALID_THEME_MODES = ["light", "dark", "system"] as const;

function isValidThemeMode(value: unknown): value is ThemeMode {
  return (
    typeof value === "string" &&
    VALID_THEME_MODES.includes(value as ThemeMode)
  );
}

Accent Validation

const VALID_ACCENT_THEMES = [
  "default",
  "blue",
  "green",
  "purple",
] as const;

function isValidAccentTheme(
  value: unknown
): value is AccentTheme {
  return (
    typeof value === "string" &&
    VALID_ACCENT_THEMES.includes(value as AccentTheme)
  );
}

Safe Read

try {
  const savedTheme = localStorage.getItem("theme");

  if (isValidThemeMode(savedTheme)) {
    setTheme(savedTheme);
  }
} catch (error) {
  console.error("Failed to read theme settings");
}

Safe Write

try {
  localStorage.setItem("theme", theme);
} catch (error) {
  console.error("Failed to persist theme settings");
}

Acceptance Criteria

  • Theme values loaded from localStorage are runtime validated.
  • Accent theme values loaded from localStorage are runtime validated.
  • Invalid values automatically fall back to defaults.
  • All localStorage reads are wrapped in error handling.
  • All localStorage writes are wrapped in error handling.
  • Theme functionality remains unchanged for valid users.
  • No new TypeScript, ESLint, or runtime warnings are introduced.

Local Verification

Run the following commands before creating the PR.

Build

npm run build

Lint Check

npm run lint

Manual Testing

  • Set a valid theme value in localStorage and verify correct behavior.
  • Set an invalid theme value and verify fallback behavior.
  • Set an invalid accent value and verify fallback behavior.
  • Clear localStorage and verify defaults are applied.
  • Verify application loads without errors.
## Description The `ThemeProvider` currently reads values from `localStorage` and casts them directly to application types (`ThemeMode` and `AccentTheme`) without runtime validation. Type assertions only provide compile-time guarantees and do not validate values at runtime. Since `localStorage` is user-modifiable, corrupted values, unexpected data, or browser-specific storage behavior may result in invalid application state. Additionally, direct `localStorage` access assumes storage availability, which may not be true in privacy-restricted environments, browser extensions, embedded webviews, or storage-blocking modes. ## Impact * Invalid theme values can cause UI inconsistencies. * Unexpected values may break theme initialization. * Potential runtime errors when storage access is unavailable. * Reduced resilience in privacy-focused browsers or restricted environments. * Hard-to-debug user-specific UI issues caused by corrupted local storage. ## Location `src/contexts/ThemeContext.tsx` ### Approximate Lines * ~20–27 (localStorage reads) * ~41–44 (localStorage writes) --- ## Suggested Fix ### Validate Stored Values Before applying values from `localStorage`, verify they belong to the allowed enum/union values. ### Wrap Storage Access Use `try/catch` blocks when reading and writing storage values to handle environments where access may fail. ### Fallback to Defaults When invalid values are detected: * Ignore the stored value. * Use the application's default theme settings. --- ## Example Implementation ### Theme Validation ```ts const VALID_THEME_MODES = ["light", "dark", "system"] as const; function isValidThemeMode(value: unknown): value is ThemeMode { return ( typeof value === "string" && VALID_THEME_MODES.includes(value as ThemeMode) ); } ``` ### Accent Validation ```ts const VALID_ACCENT_THEMES = [ "default", "blue", "green", "purple", ] as const; function isValidAccentTheme( value: unknown ): value is AccentTheme { return ( typeof value === "string" && VALID_ACCENT_THEMES.includes(value as AccentTheme) ); } ``` ### Safe Read ```ts try { const savedTheme = localStorage.getItem("theme"); if (isValidThemeMode(savedTheme)) { setTheme(savedTheme); } } catch (error) { console.error("Failed to read theme settings"); } ``` ### Safe Write ```ts try { localStorage.setItem("theme", theme); } catch (error) { console.error("Failed to persist theme settings"); } ``` --- ## Acceptance Criteria * [ ] Theme values loaded from localStorage are runtime validated. * [ ] Accent theme values loaded from localStorage are runtime validated. * [ ] Invalid values automatically fall back to defaults. * [ ] All localStorage reads are wrapped in error handling. * [ ] All localStorage writes are wrapped in error handling. * [ ] Theme functionality remains unchanged for valid users. * [ ] No new TypeScript, ESLint, or runtime warnings are introduced. --- ## Local Verification Run the following commands before creating the PR. ### Build ```bash npm run build ``` ### Lint Check ```bash npm run lint ``` ### Manual Testing * [ ] Set a valid theme value in localStorage and verify correct behavior. * [ ] Set an invalid theme value and verify fallback behavior. * [ ] Set an invalid accent value and verify fallback behavior. * [ ] Clear localStorage and verify defaults are applied. * [ ] Verify application loads without errors.
abumahid added the Kind/Enhancement label 2026-06-17 14:06:32 +00:00
abumahid added this to the techzaa-frontend project 2026-06-17 14:06:32 +00:00
rimi self-assigned this 2026-06-17 15:00:01 +00:00
abumahid moved this to Done in techzaa-frontend on 2026-06-17 16:22:40 +00:00
rimi closed this issue 2026-06-17 16:25:07 +00:00
Sign in to join this conversation.