Skip to content

Word highlighter: store settings in the user configuration (works with a read-only extensions folder) - #542

Open
stdAri wants to merge 1 commit into
FreshRSS:mainfrom
stdAri:word-highlighter-user-config
Open

stdAri wants to merge 1 commit into
FreshRSS:mainfrom
stdAri:word-highlighter-user-config

Conversation

@stdAri

@stdAri stdAri commented Oct 7, 2026

Copy link
Copy Markdown

Problem

Word highlighter writes its settings into its own directory (static/config.<user>.json, plus a generated static/config.<user>.js that is loaded as a script). When the extensions/ folder is not writable by the web server — a common hardening setup, e.g. a read-only bind mount in Docker — the configure page shows "Your config file is not writable, please change the file permissions for …" and settings cannot be saved. Making that folder writable means letting the web process create executable JavaScript.

Separately, highlighting sometimes did not start at all: the script is added with appendScript() (async), so it can run before #stream has been parsed; document.querySelector('#stream') then returns null and Mark / MutationObserver throw. Reloading the same page alternated between highlighted and not highlighted (more often in Chromium than in Safari).

Changes (0.0.5)

  • Settings (word list + the four options) are stored with setUserConfiguration(); nothing is written to disk anymore.
  • Existing installations keep their words: if the user configuration has no word list yet, the legacy static/config.<user>.json is read (read-only) until the settings are saved once.
  • Settings reach the script through the js_vars hook (context.extensions['Word highlighter'].configuration) instead of a generated script file. window.WordHighlighterConf is still accepted as a fallback.
  • The script waits for the FreshRSS global context (freshrss:globalContextLoaded) and for DOMContentLoaded before looking up #stream.
  • The word list in the configure textarea is HTML-escaped.
  • static/.gitignore ignores the legacy per-user files; README changelog and version updated.

Testing

On FreshRSS 1.30.0 / PHP 8.4 (Docker), with a read-only extensions folder:

  • the configure page loads without the permission error and saves; an existing 16-word legacy config was migrated automatically and the legacy file left untouched;
  • reloading a feed page 10 times in Safari and 10 times in Edge gave the same number of highlights every time (before: intermittently none);
  • eslint, markdownlint-cli2 and phpcs pass on the extension. I could not run phpstan locally.

🤖 Generated with Claude Code

The extension wrote its settings into its own directory
(static/config.<user>.json and an executable static/config.<user>.js),
so it failed with "Your config file is not writable" whenever the
extensions folder is read-only for the web server, and generated a
JavaScript file at runtime.

- Store the word list and options with setUserConfiguration(); no file
  writes anywhere. Settings from an existing static/config.<user>.json
  are picked up automatically until they are saved once.
- Pass the settings to the script through the js_vars hook
  (context.extensions['Word highlighter'].configuration) instead of a
  generated script file; keep window.WordHighlighterConf as a fallback.
- Fix highlighting that intermittently did not start: the script is
  loaded async and could run before #stream was parsed; wait for
  DOMContentLoaded (and for the FreshRSS global context).
- Escape the word list in the configure textarea.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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