super-productivity/electron/shared-with-frontend/plugin-node-execution.model.ts
Johannes Millan eb80bfc707 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).
2026-06-25 15:50:41 +02:00

24 lines
860 B
TypeScript

import {
PluginNodeScriptRequest,
PluginNodeScriptResult,
} from '../../packages/plugin-api/src/types';
/**
* Shape of the Electron main-process bridge the renderer uses to grant, run, and
* revoke Node script execution for a plugin. This is a host-internal IPC contract
* (not part of the public plugin API), shared between the renderer
* (`plugin-bridge.service.ts`) and the Electron API typing
* (`electron/electronAPI.d.ts`) so the two cannot drift.
*/
export interface PluginNodeExecutionElectronApi {
requestGrant(
pluginId: string,
displayInfo?: { name?: string; version?: string },
): Promise<{ token: string } | null>;
executeScript(
pluginId: string,
grantToken: string,
request: PluginNodeScriptRequest,
): Promise<PluginNodeScriptResult>;
revokeGrant(pluginId: string, grantToken: string): Promise<void>;
}