mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 00:46:45 +00:00
* feat(plugins): allow uploaded nodeExecution behind consent gate Re-open the nodeExecution permission for uploaded/community plugins (previously built-in only, #8205) behind the existing main-process consent dialog. Phase 1 of #8512; unblocks the Super Productivity MCP plugin (discussion #8385). - Main process sanitizes the attacker-controlled plugin id and the self-declared name/version before they reach the consent dialog or the grant map (control/bidi/whitespace rejected, length-capped). - Bundled vs uploaded is decided by the on-disk manifest, never a renderer-supplied flag, so uploaded code can't borrow a built-in plugin's verified name. - Uploaded-plugin dialog anchors on the validated id, flags the plugin as unverified third-party with full machine access / no sandbox, and defaults to Deny. - Revoke is main-authoritative by (pluginId, webContents) so a re-upload reusing an id can't inherit a live session grant. - Consent stays session-scoped: an in-memory, never-synced denied set prevents re-prompt storms; deny keeps the plugin enabled but fails node calls closed until re-enable or restart. Refs #8512 #8385 * fix(plugins): reject path-segment ids in nodeExecution consent gate Multi-agent review of the Phase 1 gate found the uploaded plugin id — used as a path component in the bundled-manifest existsSync probe — was not rejecting path separators or dot-segments. Impact was bounded (the verified-builtin branch re-validates with the strict kebab regex before any read, so no code exec / file read / dialog spoof), but `..` / `/` left a filesystem-existence oracle and rendered misleadingly as the dialog "Plugin ID". assertSafePluginId now rejects `/`, `\`, `.`, `..`. Also from review: factor the shared Allow/Deny dialog shell, and correct the denied-cache comment (the existing token short-circuit handles the multi-call-site case; the cache only makes a denial sticky across a later non-interactive grant re-entry). Documents the uploaded-id constraints. Refs #8512 * fix(plugins): harden uploaded nodeExecution consent gate (review follow-ups) Addresses multi-agent review findings on the uploaded-plugin nodeExecution consent gate: - id validation: use an allowlist (/^[A-Za-z0-9][A-Za-z0-9._-]*$/) instead of a Unicode denylist, closing bidi/zero-width/homoglyph dialog-anchor spoofing the range list missed (U+061C, U+2060, U+3164, fullwidth chars); strip all Unicode control+format chars from the self-declared display name/version. - never upgrade trust: describeVerifiedBuiltInDialog returns null on any imperfect on-disk verification (id mismatch, missing permission, unreadable manifest) and the grant handler falls back to the unverified dialog, so a colliding uploaded id can never borrow a built-in's verified dialog. - reserve the gitea/linear/trello/azure-devops issue-provider bundled ids (they had drifted out of BUNDLED_PLUGIN_IDS, leaving an impersonation gap) and guard the BUNDLED_PLUGIN_PATHS subset-of BUNDLED_PLUGIN_IDS invariant with a node test. - key the revoke and exec IPC handlers through the same assertSafePluginId as the grant handler so the "revoke by id on teardown/re-upload" guarantee can't drift. - clear the session nodeExecution denial when a plugin is uninstalled, so a fresh re-upload of the same id is prompted again rather than silently failing closed. - de-duplicate the PluginNodeExecutionElectronApi interface into a single electron/shared-with-frontend model (was copied byte-identically in two files). |
||
|---|---|---|
| .. | ||
| assets/icons | ||
| ipc-handlers | ||
| scripts | ||
| shared-with-frontend | ||
| task-widget | ||
| wayland-idle-helper | ||
| app-control.test.cjs | ||
| backup.ts | ||
| bundled-plugin-ids.test.cjs | ||
| clear-stale-idb-locks.ts | ||
| clipboard-image-handler.test.cjs | ||
| clipboard-image-handler.ts | ||
| common-const.test.cjs | ||
| common.const.ts | ||
| CONFIG.ts | ||
| debug.ts | ||
| electronAPI.d.ts | ||
| error-handler-with-frontend-inform.ts | ||
| file-path-guard.test.cjs | ||
| file-path-guard.ts | ||
| full-screen-blocker.ts | ||
| gpu-startup-guard.ts | ||
| idle-time-handler.ts | ||
| image-cache.test.cjs | ||
| image-cache.ts | ||
| indicator.test.cjs | ||
| indicator.ts | ||
| ipc-handler-wrapper.test.cjs | ||
| ipc-handler-wrapper.ts | ||
| ipc-handler.ts | ||
| jira.ts | ||
| local-file-sync.test.cjs | ||
| local-file-sync.ts | ||
| local-rest-api.ts | ||
| lockscreen.ts | ||
| main-window.ts | ||
| main.ts | ||
| navigation-guard.test.cjs | ||
| navigation-guard.ts | ||
| plugin-node-executor.test.cjs | ||
| plugin-node-executor.ts | ||
| plugin-oauth.ts | ||
| preload.ts | ||
| protocol-handler.ts | ||
| proxy-agent.test.cjs | ||
| proxy-agent.ts | ||
| shared-state.ts | ||
| simple-store.test.cjs | ||
| simple-store.ts | ||
| start-app.ts | ||
| sync-path-resolver.test.cjs | ||
| sync-path-resolver.ts | ||
| task-widget.test.cjs | ||
| tsconfig.electron.json | ||
| various-shared.ts | ||