mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-17 16:47:05 +00:00
* docs: design spec for #7524 drop swagger-ui + privacy opt-outs Three-deliverable plan: vendor RapiDoc to replace swagger-ui-express (Scarf-injecting), add privacy.updateCheck and privacy.pluginCatalog opt-outs for our two outbound calls, and ship PRIVACY.md as a public stance doc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: implementation plan for #7524 swagger-ui + privacy opt-outs Twelve TDD-flavoured tasks: privacy settings shape, UpdateCheck + installer opt-outs (each with a failing-test-first cycle), admin backend/UI plumbing, dependency drop, vendored RapiDoc, PRIVACY.md, final verification matrix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(privacy): add privacy block to settings shape Adds privacy.updateCheck and privacy.pluginCatalog, both defaulting to true so behavior is unchanged until operators opt out. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(privacy): honour privacy.updateCheck=false in UpdateCheck check() and getLatestVersion() now early-return when the setting is off. Logs once on first skip. The admin "update available" panel already tolerates an undefined latestVersion. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(privacy): honour privacy.pluginCatalog=false in installer Extracts the gate into pluginCatalogGuard.ts so it can be unit-tested under vitest without dragging in the CJS require() chain from installer.ts. getAvailablePlugins() now throws the tagged disabled error before any fetch. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(privacy): emit results:catalogDisabled when pluginCatalog off Short-circuits the four catalog-driven socket events. The install/ uninstall events are untouched so operators can still install by plugin name even when the catalog is disabled. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(bin): stalePlugins reads updateServer and honours privacy flag Was hardcoding static.etherpad.org and ignoring opt-out. Now exits 0 cleanly when privacy.pluginCatalog=false. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(settings): document privacy block in settings template Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api-docs): replace swagger-ui-express with RapiDoc shell Drops the swagger-ui-express dep (third-party Scarf telemetry pixel, see swagger-api/swagger-ui#10573) and serves /api-docs with a static HTML shell that mounts <rapi-doc>. /api-docs.json is unchanged. The vendored RapiDoc asset is added in the next commit so the tree is broken for one diff hunk — pair this with the rapidoc-min.js commit during review. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api-docs): vendor RapiDoc 9.3.4 (MIT) as static asset Pinned bundle with checksum in VERSION. Replaces swagger-ui-dist which shipped a Scarf telemetry pixel. Disables RapiDoc's bundled Google Fonts request via load-fonts="false" plus explicit regular-font/mono-font system stacks — RapiDoc's CSS @font-face rules would otherwise fetch Open Sans from fonts.gstatic.com at render time. Also fixes the /api-docs route's res.sendFile to use an absolute path resolved via settings.root (the previous {root: 'src/static'} was resolved from CWD which is already src/, producing src/src/static). Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): banner when plugin catalog is disabled Subscribes to results:catalogDisabled and renders a localized info banner on the plugins page. install/uninstall still function via CLI. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: PRIVACY.md and README/CHANGELOG pointers Publishes Etherpad's stance on telemetry: two documented, opt-out outbound calls; no third-party analytics; no install-time phone-homes in our deps. Refs #7524 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(admin): await checkPluginForUpdates and emit array on error Qodo flagged that checkUpdates emitted the unresolved Promise (missing await) and emitted {} for updatable on the error path, both breaking the admin UI's expected string[] shape. Pre-existing bug surfaced when the surrounding block was edited for the privacy.pluginCatalog gate. Refs #7524 * feat(api-docs): swap RapiDoc for Scalar (actively maintained) Per @SamTV12345's review on #7757: RapiDoc has been effectively unmaintained for a while. Scalar (https://github.com/scalar/scalar) is MIT-licensed, actively developed, and ships a self-contained standalone bundle that works the same way for our purposes. Privacy posture is preserved by configuring the embed: - withDefaultFonts: false (no fonts.scalar.com woff2 fetch) - telemetry: false (defensive) - agent.disabled: true (no api.scalar.com/vector/* calls) - mcp.disabled: true (no MCP integration) - showDeveloperTools: 'never' - hideClientButton: true Verified with headless Chromium: page loads /api-docs, mounts Scalar, renders the Etherpad OpenAPI document, and makes zero requests to any host other than localhost. Vendor: - src/static/vendor/scalar/standalone.js (@scalar/api-reference 1.57.2) - src/static/vendor/scalar/VERSION (sha256 pinned) - src/static/vendor/scalar/LICENSE (MIT) Removed: - src/static/vendor/rapidoc/* Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8c4f974122
commit
278acb10cb
25 changed files with 4050 additions and 85 deletions
|
|
@ -1044,6 +1044,16 @@ input, button, select, optgroup, textarea {
|
|||
padding: 8px 8px 40px;
|
||||
}
|
||||
|
||||
.pm-banner {
|
||||
margin: 8px 0 16px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--ink-3, #cbd5e1);
|
||||
background: var(--surface-2, #f8fafc);
|
||||
font-size: .9rem;
|
||||
}
|
||||
.pm-banner-info { border-left: 4px solid var(--accent, #0ea5e9); }
|
||||
|
||||
/* Header */
|
||||
.pm-header {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {IconButton} from "../components/IconButton.tsx";
|
|||
export const HomePage = () => {
|
||||
const pluginsSocket = useStore(state => state.pluginsSocket)
|
||||
const [plugins, setPlugins] = useState<PluginDef[]>([])
|
||||
const [catalogDisabled, setCatalogDisabled] = useState(false)
|
||||
const installedPlugins = useStore(state => state.installedPlugins)
|
||||
const setInstalledPlugins = useStore(state => state.setInstalledPlugins)
|
||||
// Default sort: name ascending. PR #7716 set this to "downloads desc" but
|
||||
|
|
@ -89,11 +90,14 @@ export const HomePage = () => {
|
|||
pluginsSocket.emit('search', searchParams)
|
||||
}
|
||||
|
||||
const onCatalogDisabled = () => setCatalogDisabled(true)
|
||||
|
||||
pluginsSocket.on('results:installed', onInstalled)
|
||||
pluginsSocket.on('results:updatable', onUpdatable)
|
||||
pluginsSocket.on('finished:install', onFinishedInstall)
|
||||
pluginsSocket.on('finished:uninstall', onFinishedUninstall)
|
||||
pluginsSocket.on('connect', onConnect)
|
||||
pluginsSocket.on('results:catalogDisabled', onCatalogDisabled)
|
||||
|
||||
pluginsSocket.emit('getInstalled')
|
||||
|
||||
|
|
@ -105,6 +109,7 @@ export const HomePage = () => {
|
|||
pluginsSocket.off('finished:install', onFinishedInstall)
|
||||
pluginsSocket.off('finished:uninstall', onFinishedUninstall)
|
||||
pluginsSocket.off('connect', onConnect)
|
||||
pluginsSocket.off('results:catalogDisabled', onCatalogDisabled)
|
||||
}
|
||||
}, [pluginsSocket])
|
||||
|
||||
|
|
@ -145,6 +150,12 @@ export const HomePage = () => {
|
|||
return (
|
||||
<div className="pm-page">
|
||||
|
||||
{catalogDisabled && (
|
||||
<div className="pm-banner pm-banner-info" role="status">
|
||||
<Trans i18nKey="admin_plugins.catalog_disabled"/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Page header ────────────────────────────────────────────────── */}
|
||||
<div className="pm-header">
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue