fix(settings): expose plugin ep_* config blocks to CJS require (#8110) - #8155
Conversation
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
PR Summary by QodoFix CJS Settings exports for plugin ep_* config blocks
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the day💡 Did you know, you can switch off images and animations for a plain-text comment |
Plugins read their own configuration from a top-level `ep_*` block in
settings.json via `require('ep_etherpad-lite/node/utils/Settings')`. The
CJS-compatibility shim added in #7421 installs accessor properties on
`module.exports` for `Object.keys(settings)` — but it ran exactly once, at
module-evaluation time, and `ep_*` blocks are only merged onto the settings
object later, by the `reloadSettings()` call at the bottom of that same
module. No accessor was ever defined for them, so every plugin config block
was invisible to the require() path; the value was reachable only under
`.default`.
Consequence: every plugin that reads `settings.ep_<name>` silently ran on its
built-in defaults. The reported symptom is ep_hash_auth, whose `hash_dir`
reverted to `/var/etherpad/users`, so every hash lookup failed, the
`authenticate` hook returned false, core's basic-auth fallback found no
`password` on the settings.json user, and admin login answered 401.
Note the `authenticate` hook itself was never the problem — /admin-auth/ is
handled by webaccess.checkAccess like any other path and does call the hook.
Extract the shim into `syncCjsExports()` and re-run it at the end of
`reloadSettings()`, so keys that only exist because the operator put them in
settings.json get accessors as soon as they are loaded.
Reported by @tris-ots.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013WTrZxkTJhiH1p7RuAx3NJ
The entry had landed under the already-released 3.3.4 section after rebase. Also reference #8109 (the canonical issue for this root cause), credit @mathewcsims and @AkprasadoP (#8113), and assert the ep_* key is enumerable on the CJS export and returns the live settings object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012kA75NPq8nGRidAwhPXeCi
4495a46 to
d94ab9e
Compare
Fixes #8109.
Fixes #8110.
Supersedes #8113 (@AkprasadoP), which proposed the same resync-after-
reloadSettings()fix for #8109; credited in the changelog.What's actually broken
Not the
authenticatehook./admin-auth/is handled bywebaccess.checkAccess(src/node/hooks/express/webaccess.ts:76), which isapp.use'd globally, and it callsaCallFirst0('authenticate', ctx)at line 195 exactly like every other path.openapi-admin.tsis only the hand-authored OpenAPI document, not a handler. Verified by reproduction:ep_hash_authdoes log on admin login attempts.The real bug is that plugins can't see their own
settings.jsonconfig block at all.Plugins read configuration from a top-level
ep_*block viarequire('ep_etherpad-lite/node/utils/Settings'). The CJS-compatibility shim added in #7421 installs accessor properties onmodule.exportsforObject.keys(settings)— but it ran once, at module-evaluation time, andep_*blocks are only merged onto the settings object later, by thereloadSettings()call at the bottom of that same module (storeSettingsexplicitly admitsi.indexOf('ep_') === 0). No accessor was ever defined for them.Measured in a running server with
ep_hash_auth@11.0.24installed andep_hash_auth.hash_dirset in settings.json:Why it surfaced as a 401 on the admin panel
hash_dirsilently reverted to ep_hash_auth's built-in/var/etherpad/users→ every hash file read failed → the hook returned[false]→ core's basic-auth fallback found nopasswordon the settings.json user → 401. The reporter's diagnostic was further obscured becauseSettings.ts:72rebindsconsole.logto thesettingslog4js category, so ep_hash_auth's own log lines print as[INFO] settings - …with nothing identifying the plugin.Blast radius
Every plugin that reads
settings.ep_<name>has been silently running on defaults since the shim shipped in 2.7.0 — ~20 in the ether org alone:ep_oauth,ep_helmet,ep_email_notifications,ep_themes,ep_search,ep_comments_page,ep_spellcheck,ep_stable_authorid,ep_pad_title,ep_author_hover,ep_author_follow,ep_headerauth,ep_mammoth,ep_print,ep_real_time_chat,ep_what_have_i_missed, …The fix
Extract the shim into
syncCjsExports()and call it again at the end ofreloadSettings(), so keys that exist only because the operator put them in settings.json get accessors as soon as they are loaded.Verification
Real server on :9014, fresh
develop,ep_hash_auth@11.0.24installed from npm, sha512 hash file underhash_dir:POST /admin-auth/Basic, hash_dir user,.adm=trueusers.<name>.hashin settings.json (never touchesep_hash_auth)tsc --noEmitclean.Note for #8110 specifically
There is a second, independent gotcha on the plugin side (not core): ep_hash_auth's hash_dir branch replaces
settings.users[username]with{username, is_admin: adm, displayname}, whereadmcomes from<hash_dir>/<user>/.admorep_hash_auth.hash_adm. Sois_admin: truein settings.json is discarded and you get a 403 instead of a 200 unless.admcontainstrue. Measured and confirmed.Reported by @tris-ots.
Follow-up (rebase)
develop; the changelog entry had ended up under the already-released 3.3.4 heading, so it now lives under a new 3.3.6 section and references Settings CJS mirror is built before reloadSettings(), so plugin settings hashes are never visible to CJS plugins #8109 too..default.Settings.ts(plugin ep_* settings must be reachable via CJS require), passes with the fix; settings spec 33 passing; vitest 840/840;tsc --noEmitclean.🤖 Generated with Claude Code
https://claude.ai/code/session_012kA75NPq8nGRidAwhPXeCi