mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
* feat(plugin): add generic request capability to PluginAPI * feat(plugin): gate PluginAPI.request behind manifest allowedHosts PluginAPI.request is otherwise reachable to any host the shared SSRF filter does not block. Add a manifest-declared, host-enforced allowlist so a plugin's outbound reach is explicit and reviewable at install. - PluginManifest.allowedHosts: exact hostnames the plugin may reach. - PluginBridgeService enforces it before the shared HTTP/SSRF layer: exact host, case-insensitive, trailing-dot tolerant, port-agnostic; userinfo tricks resolved via URL parsing; fail-closed (empty/omitted allowedHosts disables request entirely). - validatePluginManifest rejects malformed allowedHosts at install. Companion tests: bridge enforcement (reject non-declared host, fail-closed on undefined/empty, case-insensitive + trailing-dot, userinfo-trick blocked) and manifest validation. * style(plugin): fix prettier formatting flagged by CI in request API The generic-request commit slipped past checkFile on three files; CI prettier flagged the multi-line request() signature and a long spec assertion string. Formatting only, no behavior change. * feat(plugin): require "http" permission for PluginAPI.request Network egress becomes an explicit, opt-in capability (like nodeExecution): request now requires "http" in the manifest permissions in addition to a matching allowedHosts entry. Missing either is fail-closed. Enforced host-side (before the shared SSRF layer) on both the iframe and Function-sandbox paths; the "http" permission gets a human-readable line in the plugin security info. Tests: fail-closed without the "http" permission. * feat(plugin): surface plugin network reach in the plugin-management UI Render the manifest allowedHosts as a chip-set beside permissions/hooks (with a count in the collapsible title), so a plugin's outbound network reach is reviewable in-app instead of only in the raw manifest. Tests: allowedHosts shown in the collapsible title, omitted when none. * feat(plugin): block redirects on PluginAPI.request (SSRF-via-redirect) Only the initial request URL is allowlist/SSRF-checked, but HttpClient/XHR auto-follows 3xx — so a declared host could 302 to a private/metadata IP and return internal content to the plugin. Execute the request path via fetch with redirect:"error" so any redirect is refused instead of chased. - New PluginHttpHelperOpts.blockRedirects (default false); PluginBridge sets it for request. Issue-provider HTTP is untouched (still HttpClient). - fetch executor preserves the HttpClient contract callers depend on: query params, timeout via AbortController (covering the body read, not just headers), text/json parsing, and non-2xx rejecting with .status + .error. - Only plain objects/arrays are JSON-serialized; FormData/Blob/URLSearchParams/ ArrayBuffer(View) pass through, and Content-Type: application/json is added only for the JSON case (HttpClient parity). - Web/desktop only: on native, Capacitor patches fetch and ignores redirect/signal, so native falls back to HttpClient (documented limitation). - Blocks all redirects incl. benign same-host ones; manual per-hop re-validation is not possible on the web (cross-origin Location is opaque). Documented. Tests: redirect refused, .status/.error parity, SSRF still pre-checked, body pass-through, params + responseType:text, real-timer timeout, and native falls back to HttpClient. * fix(plugin): gate allowedHosts UI on the "http" capability The plugin-management panel showed a "Network access" section (and title count) whenever allowedHosts was non-empty, regardless of permissions — advertising reach for a capability the bridge rejects without the "http" permission. Gate the section, the chip loop, and the title count on a getNetworkReachHosts() helper (hosts only when permissions includes "http"). Addresses review on #8721. * docs(plugin): note _requestNoRedirect bypasses NetworkRetryInterceptorService The fetch path skips Angular HTTP_INTERCEPTORS, so PluginAPI.request GETs lose the single status-0 retry the HttpClient paths keep. Inherent to redirect:"error" (XHR/HttpClient cannot block redirects). Flagged in review on #8721. |
||
|---|---|---|
| .. | ||
| plugin-api | ||
| plugin-dev | ||
| shared-schema | ||
| super-sync-server | ||
| sync-core | ||
| sync-providers | ||
| vite-plugin | ||
| build-packages.js | ||
| README.md | ||
Super Productivity Packages
This directory contains plugin packages and the plugin API for Super Productivity.
Structure
plugin-api/- TypeScript definitions for the plugin APIplugin-dev/- Plugin development examples and toolsapi-test-plugin/- Basic API test pluginprocrastination-buster/- Example SolidJS-based pluginyesterday-tasks-plugin/- Simple plugin showing yesterday's tasksboilerplate-solid-js/- Template for creating new SolidJS plugins (not built)sync-md/- Markdown sync plugin (not built)
Building Packages
All packages are built automatically when running the main build process:
npm run build:packages
This command:
- Builds the plugin-api TypeScript definitions
- Builds plugins that require compilation (e.g., procrastination-buster)
- Copies plugin files to
src/assets/for inclusion in the app
Development
To work on a specific plugin:
cd plugin-dev/[plugin-name]
npm install
npm run dev
Adding a New Plugin
- Create a new directory in
plugin-dev/ - Add the plugin configuration to
/packages/build-packages.js - Run
npm run build:packagesto test the build
Notes
- The
boilerplate-solid-jsandsync-mdplugins are development templates and are not included in production builds - Plugin files are automatically copied to
src/assets/during the build process - The build script handles dependency installation automatically