etherpad-lite/CHANGELOG.md
John McLear 29dac6bfcc
fix(pad): redesign outdated-version notice (#7799) (#7804)
* docs: design spec for #7799 outdated-notice redesign

Per-pad first-author gating, dismissable gritter, minor-or-more rule, drop vulnerable UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: implementation plan for #7799 outdated-notice redesign

12 bite-sized tasks, TDD-first where applicable; closes the spec end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(updater): add isMinorOrMoreBehind, drop major/vulnerable helpers

Adds isMinorOrMoreBehind(current, latest) which returns true only when
the latest release is at least one minor version ahead (patch-only deltas
return false). Removes isMajorBehind, parseVulnerableBelow, and
isVulnerable from versionCompare.ts — callers in updateStatus.ts,
VersionChecker.ts, and index.ts will be updated in subsequent tasks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(updater): drop vulnerable-below directive and state field

Remove VulnerableBelowDirective type, UpdateState.vulnerableBelow field, and
all related scraping/checking logic (parseVulnerableBelow, isVulnerable imports).
Clean up Notifier, OpenAPI schema, and all test fixtures to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(updater): drop residual EmailSendLog vulnerable fields

Remove `vulnerableAt` and `vulnerableNewReleaseTag` from the
`EmailSendLog` interface, `EMPTY_STATE`, and the `isValidEmail`
validator — these backed the removed `vulnerable`/`vulnerable-new-release`
email kinds and are now dead code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): add firstAuthorOf helper

Export firstAuthorOf() from updateStatus.ts — finds the lowest-numbered
author attrib in a pad's pool, skipping empty-string placeholders.
Covered by 6 vitest cases in tests/backend-new/specs/hooks/express/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): add resolveRequestAuthor helper for HTTP GET

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(updater): pad-aware /api/version-status with first-author gating

Replace global badge cache with a per-(padId, authorId) LRU cache. The
new response shape is {outdated: 'minor' | null, isFirstAuthor: boolean};
the old 'severe'/'vulnerable' enum is dropped entirely. computeOutdated
now resolves the pad's first author and compares it against the session
author before returning outdated:'minor', so the notice is only shown to
the person who created the pad.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(updater): switch isSevere signal from major-only to minor-or-more behind

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(updater): end-to-end coverage for /api/version-status

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(openapi): /api/version-status pad-aware shape and gating

Add the /api/version-status GET operation to the admin OpenAPI spec with
the new pad-aware response shape: outdated enum reduced to [minor]|null,
isFirstAuthor boolean, and an optional padId query param.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(pad): remove unused #version-badge template and CSS

* feat(pad): replace persistent badge with first-author outdated gritter

Renames pad_version_badge.ts → pad_outdated_notice.ts and rewrites it
as a fire-and-forget gritter notice that only shows when the API reports
outdated=minor AND the current user is the pad's first author.  Wires
the new maybeShowOutdatedNotice() call into pad.ts immediately after
showPrivacyBannerIfEnabled().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(pad): playwright coverage for outdated notice gritter

Six Playwright specs exercise maybeShowOutdatedNotice: null response,
isFirstAuthor:false guard, positive appearance + text, X-dismiss,
500 server error tolerance, and 8 s auto-fade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(pad): outdated-notice redesign + drop vulnerable-below docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(test): remove stale specs for deleted #version-badge surface

Delete the GET /api/version-status describe block from the legacy mocha
spec (asserted outdated:null and outdated:'severe' — both no longer match
the new response shape). The new vitest spec at
tests/backend-new/specs/hooks/express/updateStatus.test.ts covers this
surface comprehensively.

Delete src/tests/frontend-new/specs/pad-version-badge.spec.ts entirely:
all three tests reference the #version-badge DOM element removed in Task 8
and stub 'severe'/'vulnerable' enum values that no longer exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: clean stale references to vulnerable/severe in types, emails, docs

- Remove OutdatedLevel type (null|'severe') from types.ts — no consumers
  remain after the badge redesign removed the severe tier.
- Fix Notifier severe-email body: was "more than one major release behind"
  but isSevere now fires on minor-or-more, so update to "at least one
  minor release behind the latest published version".
- Drop "vulnerability directives" from the /admin/update/status OpenAPI
  description; replace with the actual response fields.
- Remove stale vulnerableBelow field from UpdateStatusPayload in
  admin/src/store/store.ts — server no longer sends it.
- Fix docs/admin/updates.md: "pad-side badge" → "pad-side notice".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 12:23:40 +01:00

107 KiB
Raw Blame History

3.1.0

3.1 ships the self-update programme's Tier 4 — autonomous in a maintenance window for real (the v3.0.0 notes documented the design; this is the release the code actually lands in), adds first-class SMTP delivery so update failures email the admin, and bundles a defence-in-depth pass across the HTTP/API entry points. Two new admin-facing escape hatches arrive: a preflight check that aborts an update before it mutates the working tree when the target tag's engines.node doesn't match the running runtime, and email notifications for every auto-rollback / preflight outcome (not just the terminal rollback-failed state).

Notable enhancements

  • pad: Outdated-version notice redesigned (#7799). The persistent "severely outdated" banner is replaced by a dismissable gritter notification (auto-fades after 8 seconds), shown only to a pad's first author and only when the server is at least one minor version behind the latest released version. Patch-only deltas no longer fire the notice. The vulnerable-below directive scraping, the severe and vulnerable enum values, and the vulnerableBelow state field have been removed.

  • API: GET /api/version-status updated (#7799). Now accepts an optional ?padId=<id> query parameter and returns {outdated: "minor" | null, isFirstAuthor: boolean}. The severe and vulnerable enum values are gone. Results are cached per (padId, authorId) for 60 seconds.

  • Self-update — Tier 4 (autonomous in a maintenance window). Set updates.tier: "autonomous" together with updates.maintenanceWindow: {"start":"HH:MM","end":"HH:MM","tz":"local"|"utc"} to constrain autonomous updates to a nightly window. The scheduler snaps scheduledFor forward to the next window opening when grace would otherwise land outside the window, and defers the fire when the window has closed by the timer callback. Cross-midnight windows (end < start) are supported; DST transitions are absorbed by host wall-clock arithmetic. A missing or malformed window degrades the policy to Tier 3 with an explicit policy.reason of maintenance-window-missing / maintenance-window-invalid; an admin banner surfaces the misconfiguration so autonomous behaviour is not silently disabled. The admin update page shows a "Maintenance window" section with the parsed window summary, the next opening, and a "deferred until " subtitle on the scheduled panel when the timer has been snapped forward. Closes #7607 (#7753).

  • Updater — real SMTP via nodemailer (new top-level mail.* block). Replaces the "(would send email)" stub. New settings: mail.host, mail.port, mail.secure, mail.from, mail.auth.{user,pass}. mail.host=null keeps the legacy log-only behaviour. The nodemailer dependency is lazy-imported on first send so installs that don't configure mail pay no runtime cost; the transport is cached on the full SMTP options tuple so a reloadSettings() change to host/port/credentials invalidates the cache. settings.json.docker reads MAIL_HOST / MAIL_FROM / MAIL_PORT / MAIL_SECURE from env. Send errors are logged warn and swallowed so a transient SMTP failure can never poison the updater state machine.

  • Updater — preflight against the target tag's engines.node. Before mutating the working tree, runPreflight now runs git show <tag>:package.json and verifies process.versions.node satisfies the target's engines.node. A mismatch fails cleanly at preflight-failed with the detail target requires Node >=X, running Y — no drain, no restart, no rollback. The check runs after signature verification so we only trust signed package.json. New PreflightReason: 'node-engine-mismatch'.

  • Updater — email admin on rollback / preflight-failed (not just rollback-failed). Before this release only the terminal rollback-failed state emailed. Auto-recovered failures (rolled-back-install-failed, rolled-back-build-failed, rolled-back-health-check, rolled-back-crash-loop) and preflight-failed now also fire one email per <outcome>:<targetTag> (dedupe key in EmailSendLog.lastFailureKey). A 3am autonomous update that rolls back because of, say, a Node engine bump now lands in the admin inbox at 3am instead of staying invisible until the next admin login. Boot-path catch-up covers cases where the failure preceded a clean process exit (timer-fired health-check rollback, crash-loop forced rollback, preflight-failed that didn't get to email before exit).

  • API — listAuthorsOfPad filters the synthetic system author. Pad.SYSTEM_AUTHOR_ID (a.etherpad-system) is the placeholder Etherpad attributes to when the HTTP API receives a call without an authorId (setText, setHTML, appendText, server-side import). It was leaking through listAuthorsOfPad, making pads with only API-driven content appear to have one "real" author. The synthetic id is now filtered at that API surface only — getAllAuthors() and downstream callers (copy, anonymize, atext verification) still see it. Fixes #7785 / #7790 (#7793).

Notable fixes

  • Export HTML — ordered-list counter no longer poisoned by a sibling unordered list. When an ordered-list level was the only consumer of olItemCounts, closing any list at that depth (including a <ul> that happened to share the level) reset the counter to 0. A subsequent unrelated <ol> at the same depth then took the "counter exists but is 0" branch and emitted <ol class="..."> without the start= attribute. The reset is now gated on line.listTypeName === 'number' so closing an unordered list never touches the ol bookkeeping. Fixes #7786 / #7787 (#7791).
  • Export — bad :rev returns a meaningful 500 body, not Express's HTML error page. A non-numeric :rev (e.g. /p/foo/test1/export/txt) reached checkValidRev which throws CustomError('rev is not a number', 'apierror'); the message fell through .catch(next) and Express's default renderer returned an HTML 500 page. The route handler now catches the apierror and emits err.message as a deterministic text/plain 500. As a follow-up, checkValidRev runs before res.attachment() so an invalid rev no longer leaves a Content-Disposition header in place (browsers were offering to save the error message as a file), and unrelated export failures (conversion, fs, soffice) are surfaced as text/plain rather than the HTML stack page. Fixes #7788 (#7792).

Security hardening

A bundle of defence-in-depth tightening picked up during an internal audit pass (#7784):

  • HTTP API — OAuth JWT path. Verify the signature before reading any claim off the payload; require admin: true strictly (presence is no longer sufficient). The apikey comparison switches to crypto.timingSafeEqual.
  • Import/Export temp-file path tokens. Derived from crypto.randomBytes(16) instead of Math.random().
  • Token transfer. Records now have a 5-minute TTL and are single-use (removed from the store before responding). The author token is no longer in the redemption response body — the HttpOnly cookie is the only delivery channel.
  • x-proxy-path header sanitiser (new src/node/utils/sanitizeProxyPath.ts). Shared by admin.ts and specialpages.ts. Strips characters outside [A-Za-z0-9_./-], collapses leading //+ to a single /, rejects .. traversal. admin.ts also emits Vary: x-proxy-path and Cache-Control: private, no-store so a poisoned response can never be reused for another origin.
  • Pad.appendRevision insert-op author invariant. Centralises the "every insert op carries an author attribute" rule the socket handler already enforced, so non-wire callers (setText, setHTML, restoreRevision, plugin paths) get the same check. Pad.init and setPadHTML substitute SYSTEM_AUTHOR_ID when no author is supplied — same pattern setText / spliceText already used.
  • setPadRaw legacy-import rewrite. Bulk-import bypasses appendRevision, so a hand-crafted .etherpad file could persist non-conforming records that any subsequent setText / setHTML would refuse to extend. A pre-pass now walks revs in order, sanitises each changeset's + ops against the cumulative pad pool (substituting SYSTEM_AUTHOR_ID where needed), and re-applies each changeset to a running atext so the head atext and key-rev meta.atext / meta.pool snapshots stay in lock-step. Conforming payloads round-trip unchanged.

Internal / contributor-facing

  • Backend tests — tests/backend/specs/{api,admin}/* un-skipped. The pnpm test script's glob (tests/backend/specs/**.ts) only matched depth-1 files. Every spec under api/ (14 files) and admin/ (2 files) has been silently skipped by CI. Switched to --extension ts --recursive so mocha walks the tree as documented. A new vitest regression check reads the pnpm script, hands mocha the same arguments under --dry-run --list-files, and asserts representative specs from both subdirectories appear in the discovered list (#7789).
  • CI — Windows npx ENOENT in the glob-discovery regression check. execFileSync('npx', ...) doesn't pick up npx.cmd on Windows runners. Resolved by running mocha's JS entry directly via require.resolve under the current node process. Path normalisation now goes through path.relative + replace([\\/]) so mixed-separator / drive-letter casing on Windows mocha output still matches the POSIX-relative assertions (#7794).
  • CI — anonymizeAuthorSocket suite gated on admin-socket health when ep_hash_auth is installed. Un-hiding the suite in #7789 surfaced a 14-minute stall on every with-plugins matrix run because ep_hash_auth's handleMessage hook fires for every socket message regardless of namespace and reads from the deprecated client context (undefined for non-pad namespaces). Until the root cause lands (tracked in #7795), the suite skips itself when an application-level probe shows the admin /settings namespace isn't responding — keeps the no-plugin matrix covered and stops burning ~14 minutes per with-plugins run (#7796).

Localisation

  • Multiple updates from translatewiki.net.

3.0.0

3.0 is a feature-heavy release that closes out the self-update programme (Tiers 2 and 3 land alongside Tier 1 from 2.7.3), removes the last identified upstream telemetry vector, and ships a parsed JSONC settings editor, native DOCX export, in-place pad history scrubbing, and an admin UI for GDPR author erasure. It also marks the start of the broader Etherpad app ecosystem (see Companion apps below).

Breaking changes

  • Minimum required Node.js version is now 24. Node.js 22 is no longer supported. Node 25 was briefly the floor mid-cycle but was rolled back to 24 LTS (Krypton, supported through ~May 2028) because Node 25 reached end-of-life on 2026-04-10 (see #7779 / #7781). The CI matrix targets Node 24 and 26. Node 24 still ships Corepack, so existing bin/installer.sh / bin/installer.ps1 flows continue to work unchanged; the global pnpm install fallback added for the Node 25 detour is kept for forward-compatibility.
  • pnpm floor raised to pnpm@11.1.2. packageManager is now pinned to pnpm@11.1.2 and engines.pnpm requires >=11.1.2. The Dockerfile, snap, .deb and all GitHub workflows are aligned.
  • swagger-ui-express removed. /api-docs now serves a vendored, telemetry-free copy of Scalar (see the privacy item below). The route, the OpenAPI document, and the rendered output are unchanged for downstream consumers, but anything that introspected swagger-ui-express internals will need updating.
  • Debian package depends on nodejs (>= 24). The signed apt repository at etherpad.org/apt is rebuilt against this floor; older Node packages are no longer acceptable as a dependency (#7754).

Companion apps

This release coincides with the launch of two ecosystem projects, both maintained under the ether org and able to talk to any 3.x Etherpad server over its existing HTTP / WebSocket API:

  • ether/etherpad-desktop — a native desktop wrapper around Etherpad for macOS, Windows and Linux. Single-window editor experience, system-tray indicator, and an optional embedded server for fully offline pads.
  • ether/pad — a portable cross-target client: an Android and iOS app for editing pads on the go, and a nano-style terminal client for headless / SSH workflows. Shares the same realtime client transport as the browser editor so changes propagate live across desktop, mobile, terminal and the web UI.

Both clients hit the stable 3.x API surface, so server operators don't need to enable anything extra to support them — the OpenAPI clean-up landed in this release (see Notable enhancements) is what makes the shared client code generators viable.

Notable enhancements

  • Self-update subsystem — Tier 2 (manual click).
    • Admins on a git install can click "Apply update" at /admin/update. Etherpad runs a 60s session drain (with T-60 / T-30 / T-10 broadcasts to every pad), git fetch / checkout / pnpm install --frozen-lockfile / pnpm run build:ui, and exits with code 75 so a process supervisor restarts it on the new version. The next boot runs a 60s health check; if /health doesn't come up the previous SHA + lockfile are restored automatically.
    • Crash-loop guard: if the new version reboots more than twice without the health check completing, RollbackHandler forces a rollback regardless of the timer.
    • Terminal rollback-failed state surfaces a strong banner; the admin clicks Acknowledge once they've manually recovered to clear the lock and re-allow Tier 2 attempts.
    • New settings under updates.*: preApplyGraceMinutes, drainSeconds, rollbackHealthCheckSeconds, diskSpaceMinMB, requireSignature, trustedKeysPath. Tag signature verification is opt-in (default false) — see doc/admin/updates.md for the keyring setup.
    • A process supervisor (systemd / pm2 / docker --restart=unless-stopped) is required to apply updates. Without one, exit 75 leaves the instance down.
  • Self-update subsystem — Tier 3 (auto with grace window).
    • On a git install, set updates.tier: "auto" to have new releases applied automatically after preApplyGraceMinutes. During the grace window, /admin/update shows a live countdown plus Cancel and Apply now buttons. Schedules are persisted to var/update-state.json, so an Etherpad restart during the grace window rehydrates the timer instead of losing the schedule. A new release tag detected mid-grace re-arms the timer; if adminEmail is set, a one-shot grace-start notification fires per scheduled tag (issue #7607).
    • The terminal rollback-failed state continues to disable auto/autonomous attempts globally until acknowledged; manual click stays available because an admin click is the intervention the terminal state requires.
  • Self-update subsystem — Tier 4 (autonomous in a maintenance window).
    • Set updates.tier: "autonomous" together with updates.maintenanceWindow: {"start":"HH:MM","end":"HH:MM","tz":"local"|"utc"} to constrain autonomous updates to a nightly window. The scheduler snaps scheduledFor forward to the next window opening when grace would otherwise land outside the window, and defers the fire when the window has closed by the timer callback. Cross-midnight windows (end < start) are supported; DST transitions are absorbed by the host's wall-clock arithmetic.
    • A missing or malformed window degrades the policy to Tier 3 with an explicit policy.reason of maintenance-window-missing / maintenance-window-invalid; an admin banner surfaces the misconfiguration so autonomous behavior is not silently disabled. Closes #7607.
  • Privacy — drop swagger-ui telemetry, document phone-homes, add opt-outs.
    • Dropped swagger-ui-express because upstream injects a Scarf analytics pixel that cannot be disabled at install or runtime (see swagger-api/swagger-ui#10573). /api-docs now serves a vendored copy of Scalar (MIT) configured with withDefaultFonts: false and telemetry: false so no outbound calls are made.
    • New privacy.updateCheck (default true) — set to false to disable the hourly UpdateCheck.ts request to ${updateServer}/info.json.
    • New privacy.pluginCatalog (default true) — set to false to disable the admin plugins page fetch of ${updateServer}/plugins.json. CLI install-by-name still works.
    • New PRIVACY.md at repo root documenting both outbound calls, what they send, and how to turn each off.
    • bin/plugins/stalePlugins.ts now reads settings.updateServer (was hardcoded to static.etherpad.org) and honours the new flag.
    • Closes #7524.
  • Parsed JSONC settings editor in /admin. The settings page now parses settings.json as JSONC (with comments and trailing commas preserved), validates edits in-browser, and writes the file back without clobbering comment blocks (#7709, closes #7603, takes over #7666).
  • GDPR — admin UI for author erasure. Builds on the 2.7.3 author-erasure API: admins can now find an author by id or name in /admin and run a confirmed erasure flow from the UI (#7667, follow-up to #7550).
  • Pad-wide settings on by default. padOptions-style settings can now be edited from the in-pad cog without flipping a flag, and the modal title no longer misleads about scope (#7679). Plugin-namespaced ep_* keys also flow through applyPadSettings so plugins can register their own pad-wide options (#7698).
  • Scrub history in-place on the pad URL. A long-edited pad can now have its history rewritten in place (e.g. for compliance or to drop accidentally-pasted secrets), without changing the pad URL or breaking deep-links (#7710, closes #7659).
  • bin/compactStalePads — staleness-gated bulk compaction. Companion to the 2.7.3 compactAllPads CLI: targets only pads not edited in the last --older-than N days, so hot pads in active timeslider use are left alone. Same --keep / --dry-run shape as compactAllPads (#7708, issue #7642).
  • Native DOCX export (opt-in). A html-to-docx-based exporter lands as an alternative to the LibreOffice path, so installs that don't want soffice on the host can still produce .docx. soffice is now documented as optional for .docx and .pdf (#7568 / #7707, issue #7538).
  • Editor / UI.
    • Settings popup is now scrollable on short viewports so the lower controls stay reachable on small laptops (#7703, issue #7696).
    • Admin design pass cleans up the rework introduced in 2.7.3 (#7716).
    • theme-color meta now follows the client-side dark-mode switch instead of locking to the boot-time value (#7690, issue #7606).
    • menu_right stays visible on readonly pads by default; operators that prefer the slimmer chrome can still opt in via showMenuRight (#7783).
    • Social meta: new settings.socialMeta.description override (#7691) plus a fix for numeric / boolean override values that were silently being dropped during coercion (#7692).
  • Admin / API surface.
    • The published OpenAPI spec is cleaned up for downstream codegens — duplicate operationIds removed, response schemas filled in, nullableoneOf null migrated for OpenAPI 3.1 (#7714). The companion apps above consume this directly.
    • Admin endpoints (/admin/* JSON APIs) are now documented in the OpenAPI spec (#7693 / #7705) and called from a typesafe TanStack Query client in the admin SPA (#7638 / #7695).
    • "Requires newer Etherpad" message in the plugin browser when an ep.json declares an engines.etherpad higher than the running version, instead of failing with a generic install error (#7763 / #7771).
  • Security hardening.
    • Reject USER_CHANGES inserts that arrive without an author attribute, closing a server-side trust gap where unattributed changes could be applied to a pad (#7773).
    • Integrator-issued sessionID cookies can now be marked HttpOnly via the new option, matching the 2.7.3 author-token hardening (#7045 / #7755).
  • Observability — Prometheus counters. Three new counters surface scaling-relevant events (pad_load_total, socket_connect_total, changeset_apply_total) so operators can drive horizontal-scaling decisions off the existing /metrics endpoint without a custom exporter (#7756 / #7762).
  • Accessibility (continuation of the 2.7.2 / 2.7.3 pass).
    • Skip-to-content link plus hiding line-number gutters from screen readers (#7255 / #7758).
    • Named role="toolbar" regions and linemetricsdiv hidden from assistive tech (#7255 / #7777).
    • Localized aria-label on form controls (<select>, <input>, <textarea>) and on export-as links (#7697 / #7713).
    • Removed role="textbox" / aria-multiline from innerdocbody where they no longer matched the editor's real semantics (#7778 / #7782).

Notable fixes

  • Docker — pnpm at runtime. Bypass pnpm at container start so the entrypoint no longer triggers a spurious deps-status reinstall on every restart (#7718 / #7727). The Corepack cache is now shared so the unprivileged etherpad user can resolve pnpm (#7689).
  • Debian — plugin_packages stays in-tree. The .deb now keeps plugin_packages/ under the install root so plugins installed at runtime can still resolve ep_etherpad-lite (#7750).
  • Admin — restore search and sort. SearchField and the column-sort helpers used by the authors page were lost during the admin rework; they're restored (#7746).
  • Admin — German strings hardcoded in error paths. A handful of leftover German strings from the rework are replaced with i18n keys (#7735 / #7736).
  • Settings — username: false / malformed color: false regression. Legacy settings.json files that used false to disable a feature no longer surface as 'false' username or 'malformed color: false' errors (#7688, issue #7686).

Internal / contributor-facing

  • Database driver — ueberdb2 5 → 6. Major-version bump to ueberdb2@^6.0.3 (#7734). Drivers are pinned through the lockfile; the schema-level changes are documented in the ueberdb2 6.0 release notes.
  • CI / tests.
    • Windows + Node 24 backend-test flake fixed; native crashes are now captured for diagnosis (#7748).
    • updater-integration rmdir-retry to clear the long-standing Windows EBUSY flake (#7728).
    • lowerCasePadIds spec closes its socket.io clients on teardown (#7722).
    • Admin tests realigned to the typesafe API client + plugin row count fixes (#7712).
    • Rate-limit test waits for Etherpad readiness before running, instead of racing the boot sequence (#7726).
  • README link fixes and tidy-up (#7723 / #7724 / #7725).
  • Several dependency-group bumps across the dev and runtime trees: undici 7.25 → 8.3, semver 7.7.4 → 7.8, tsx 4.21 → 4.22, mssql 12.5.2 → 12.5.3, js-cookie 3.0.5 → 3.0.6, @tanstack/react-query 5.100.9 → 5.100.10, actions/dependency-review-action 4 → 5, plus the usual Dependabot dev-group rollups.

Localisation

  • Multiple updates from translatewiki.net.

2.7.3

Breaking changes

  • Minimum required Node.js version is now 22.13. Node.js 20 is reaching end-of-life (see https://nodejs.org/en/about/previous-releases) and pnpm 11 hard-rejects Node releases older than 22.13. The CI matrix targets Node 22, 24, and 25. Upgrading should be straightforward — install a current Node.js release before updating Etherpad.
  • The official Docker image no longer ships curl, npm, or npx. These were dropped to remove transitive CVEs (curl/libcurl SMB advisories, npm's bundled picomatch 4.0.3 and brace-expansion 2.0.2). The container's healthcheck now uses wget (busybox built-in, always present), and Etherpad provisions pnpm via corepack for all runtime package operations. If you exec into the container and rely on curl or npm for ad-hoc tasks, install them on demand with apk add curl or use the busybox wget / pnpm already present.

Notable enhancements

  • GDPR / privacy controls. A multi-PR series adds the building blocks operators need to satisfy data-subject requests:
    • Pad deletion controls (admin-driven and self-service).
    • IP / privacy audit pass across the codebase.
    • Author-token cookies are now HttpOnly, removing them from JavaScript reach.
    • Configurable privacy banner shown on first visit.
    • Author erasure: an authenticated path for purging an individual author's identity and contributions.
  • Self-update subsystem (Tier 1: notify).
    • Periodic check against the GitHub Releases API for the configured repo (default ether/etherpad). Configurable via the new updates.* settings block, default tier "notify". Set updates.tier to "off" to disable entirely.
    • The admin UI shows a banner and a dedicated "Etherpad updates" page with the current version, latest version, install method, and changelog.
    • Pad users see a discreet footer badge only when the running version is severely outdated (one or more major versions behind) or flagged as vulnerable in a recent release manifest. The public endpoint that drives this never leaks the version string itself.
    • New top-level adminEmail setting. When set, the updater emails the admin on first detection of severe / vulnerable status, with escalating cadence (weekly while vulnerable, monthly while severely outdated). PR 1 ships the dedupe + cadence logic; real SMTP wiring lands in a follow-up PR.
    • Tier 1 ships in this release. Tiers 2 (manual click), 3 (auto with grace window) and 4 (autonomous in maintenance window) are designed and will land in subsequent releases.
    • See doc/admin/updates.md for full configuration.
  • Pad compaction. New compactPad HTTP API plus bin/compactPad and bin/compactAllPads CLIs to reclaim database space on long-lived pads with heavy edit history (issue #6194). --keep N retains the last N revisions; --dry-run previews per-pad rev counts before writing. Per-pad failures don't stop the bulk run.
    • bin/compactStalePads (issue #7642) targets only pads not edited in the last --older-than N days, so hot pads in active timeslider use are left alone. Same --keep / --dry-run shape as bin/compactAllPads. Targeting is deliberately a CLI concern — the compactPad API surface stays unchanged.
  • New packaging targets.
    • Etherpad is now published as a Snap package.
    • Debian (.deb) packages are built via nfpm with a systemd unit, and a signed apt repository is published to etherpad.org/apt.
  • Editor enhancements.
    • IDE-style line operations: keyboard shortcuts to duplicate or delete the current line.
    • New showMenuRight URL parameter to hide the right-side toolbar — useful for embeds that need slimmer chrome.
    • Click a user in the userlist to open chat with @<name> prefilled, making mentions discoverable.
    • New padOptions.fadeInactiveAuthorColors setting plus a toolbar UI to fade the background colors of authors who have left the pad.
  • Color contrast. Author colors now pick the WCAG-higher-contrast text color for readability.
  • Social / mobile metadata. Pad, timeslider, and home views now emit Open Graph and Twitter Card tags (closes #7599) and a theme-color meta that matches the toolbar on mobile.
  • Plugin admin UX. The /admin plugin browser surfaces each plugin's ep.json disables declarations, so operators can see what a plugin will turn off before installing.

Notable fixes

  • Socket.io: don't kick authenticated duplicate-author sessions. A regression where two tabs from the same authenticated author could evict each other has been fixed (#7656 / #7678).
  • Anchor scrolling. Anchor-link navigation now waits for layout to settle, so jumping to a deep link no longer overshoots.
  • Plugin updater. bin/updatePlugins.sh actually updates installed plugins again (closes #6670).
  • Settings: stable per-release version string. randomVersionString is now derived from the release identity rather than regenerated on each boot, so caches behave correctly across restarts of the same version.

Internal / contributor-facing

  • The HTTP client in the backend has been migrated from axios to the built-in fetch API, dropping a dependency now that Node 22 ships a stable fetch.
  • admin/ and ui/ workspaces moved from rolldown-vite to upstream Vite 8.
  • Build and CI moved to pnpm 11 (packageManager: "pnpm@11.1.2"); the Dockerfile, snap, and all GitHub workflows are aligned. pnpm overrides have been migrated from package.json to pnpm-workspace.yaml to match pnpm 11's expectations.
  • All client modules have been converted to ESM.
  • The CI matrix tests Node 22, 24, and 25; on PRs the matrix is reduced to a single Node version to keep feedback fast.
  • Frontend Playwright tests now run against the /ether plugin set, with feature-tag based skips so plugin-incompatible specs are excluded automatically.
  • Build hardening: signed apt repo publishing, frozen lockfile installs across CI, Node setup pinned in every workflow, and a Docker-image CVE sweep that bumps npm, pnpm, and uuid.

Localisation

  • Multiple updates from translatewiki.net.

2.7.2

Notable enhancements and fixes

  • Accessibility pass: corrected dialog semantics, improved focus management, added missing icon labels, and set the html lang attribute correctly.
  • Chat: clicking the chat icon works again, disabled toggles render properly, and the username layout no longer overflows.
  • /export/etherpad now honors the :rev URL segment, so revision-specific exports return the requested revision instead of the latest.
  • Undo / redo now scrolls the viewport to follow the caret, so reverted edits stay in view.
  • Page Down / Page Up now scrolls by viewport height instead of a fixed line count, matching standard editor behavior on tall and short windows alike.
  • Editbar: caret is restored to the pad after changing a toolbar select, so typing continues in the document instead of falling through to the toolbar.
  • Admin: i18n is restored on /admin so the admin UI is translated again.

2.7.1

Notable enhancements and fixes

  • fixed stop harcoding lang=en, letting the client auto detect locale
  • Stop mutating the shared plugin registry during sanitization
  • Preserve non-breaking space

2.7.0

Breaking changes

  • Abiword has been replaced with LibreOffice for document import/export. If you were using Abiword for DOCX/ODT/PDF conversion, update your settings.json to point soffice at your LibreOffice binary. DOCX export is now supported out of the box.

Notable enhancements

  • Added line numbers to the timeslider so you can follow along with specific lines while replaying a pad's history.
  • Added a playback speed setting to the timeslider — you can now scrub through history faster (or slower) than real time.
  • Creator-owned pad settings defaults: the user who creates a pad now seeds its default settings, giving pad creators more control over initial configuration.
  • Cookie names are now configurable via a prefix setting. Useful when running multiple Etherpads on the same domain and you need to keep their session cookies from colliding.
  • Added a new aceRegisterLineAttributes hook so plugins can preserve custom line attributes across Enter / line-split operations. Documentation for the hook is included.
  • Added a one-line installer script for getting Etherpad running quickly on a fresh machine.
  • Docker images are now published to GitHub Container Registry (GHCR) in addition to Docker Hub.
  • npm publishing of core and plugins has been migrated to OIDC trusted publishing for stronger supply-chain security.

Notable fixes

  • Database drivers are now bundled with Etherpad again, so fresh installs no longer fail to connect to Postgres, MySQL, and friends out of the box. A regression test has been added to prevent this from breaking again.
  • Pending changesets are now flushed immediately after a reconnect instead of being silently dropped, and users are warned when a pending edit is not accepted by the server.
  • Head revision and atext are now captured atomically, preventing the occasional "mismatched apply" errors on busy pads.
  • Clearing authorship colors can now be undone without forcing a client disconnect.
  • Added periodic cleanup of expired/stale sessions from the database, and fixed a race condition in the session cleanup timeout.
  • Error messages returned to clients are now sanitized by default with deduplication, so internal details no longer leak through error responses.
  • Raised the maximum socket.io message size to 10 MB so large pastes no longer get rejected.
  • Dev mode entrypoint paths now respect the x-proxy-path header, fixing reverse-proxy setups in development.
  • Numerous list-related fixes: numbered list wrapped lines now indent correctly, ordered list numbering is preserved across bullet interruptions during export, consecutive numbering survives indented sub-bullets, switching from unordered to ordered resets numbering, and line attributes are preserved across drag-and-drop.
  • Bold (and other) formatting is now retained after copy-paste.
  • Dead-key / compose-key input no longer eats the preceding space.
  • POST API requests with a JSON body no longer time out.
  • appendText now correctly attributes the new text to the specified author.
  • createDiffHTML no longer fails with Not a changeset: undefined.
  • Added padId to the padUpdate / padCreate hook context.
  • Fixed numConnectedUsers to include the joining user in its count.
  • Accessibility improvements: keyboard trap fix, better screen reader support, and aria-live announcements.
  • RTL URL parameter rtl=false now correctly disables RTL mode.
  • Language dropdown is now sorted alphabetically by native name.
  • PageDown now advances the caret by a full page of lines.
  • ESM/CJS interop issues in the Settings module that had been breaking plugin compatibility have been resolved, with setters added to the CJS compatibility layer and regression tests in place.
  • Several Docker build fixes: git submodule handling, hardlink package-import-method for ZFS, and production-only workspace config.

Other

  • Many occurrences of "etherpad-lite" have been renamed to "etherpad" across the codebase and documentation.
  • Pinned 33 transitive dependencies to patched versions to clear out Dependabot security alerts.
  • Restricted GITHUB_TOKEN permissions in the update-plugins workflow.

2.6.1

For those wondering where the new updates are and why it was very quite throughout the last 1 1/2 years I've been working on a new implementation of Etherpad from scratch in Go. It's called Etherpad-Go and you can find it here: https://github.com/ether/etherpad-go and a short FAQ about it here: https://github.com/ether/etherpad-go/wiki/FAQ . I'd love to hear your feedback about it either on Discord or issue tracker. There is a README.md that explains how to get started and try it out and also the FAQ can be quite fruitful. Latest release can be found here: https://github.com/ether/etherpad-go/releases/tag/v0.0.4

Notable enhancements and fixes of this release

  • Minor fixes and improvements to the session transfer feature introduced in 2.6.0
  • Dependencies upgrades

2.6.0

Notable enhancements and fixes

  • Added native option to transfer your Etherpad session between browsers. If you use multiple browsers or different PC for Etherpad they are different sessions. Meaning typing on one PC and then switching to another one in the same pad will result in different authorship colors. With this new feature you can now transfer your session to another browser or PC. To do so, open the home page and click on the wheel icon in the top right corner. After that click through the first dialog prompting you to copy a code to your clipboard. On your second browser open the same dialog and switch to "Receive Session" tab. There you can paste the code you copied before and click on "Receive Session". After that your session is transferred, and you can continue editing with the same authorship color as before. Just be aware that you can't have two active sessions at once in a pad.
  • Updated to oidc provider v2.6.0 after resolving compatibility issues.

🎉 For all the people celebrating: Have a happy and awesome new year! 🎉 There is something big on the horizon for Etherpad in 2026. Stay tuned!

2.5.3

Notable enhancements and fixes

  • Fixed an issue with the release script that caused the release to not be created correctly.

2.5.2

Notable enhancements and fixes

  • Fixes the no skin theme having an overlapping
  • Adds a new setting to disable recent pads to be shown. By setting showRecentPads to false in the settings.json file you can disable the recent pads feature on the home screen.
  • Sets the oidc-provider version to 9.5.1 as 9.5.2 crashes Etherpad on startup.

2.5.1

Notable enhancements and fixes

  • Added endpoint for prometheus scraping. You can now scrape the metrics endpoint with prometheus. It is available at /stats/prometheus if you have enableMetrics set to true in your settings.json

  • fixed exposeVersion causing the pad panel to not load correctly

  • fixed admin manage pad url to also take the base path into account

2.5.0

Notable enhancements and fixes

  • Updated to express 5.0.0. This is a major update to express that brings a lot of improvements and fixes. Please update all your plugins to the latest version to ensure compatibility. A lot changed in the route matching, and thus old plugins will throw errors and crash Etherpad.
  • Fixed an issue with the no-skin theme with cookie recentPadList feature
  • Fixed layout issues with the no-skin theme

2.4.2

Notable enhancements and fixes

  • Fixed a german translation in the english translation file.

2.4.1

Notable enhancements and fixes

  • Added generating release through ci cd pipeline.
  • Readded temporarily disabled workflows after release generation works again

2.4.0

Notable enhancements and fixes

  • Added home button to the pad panel. To show it in your current instance, please copy the updated "toolbar" settings from the settings.json.template file to your settings.json file.
  • Added more current design for the default collibri theme.
  • Added handling of recent visited pads in the collibri theme. You can now access the most recent three pads you visited in the pad panel.
  • Disable stats endpoints if enableMetrics is set to false. This allows you to disable the metrics endpoints if you don't want to use them.
  • Use Node LTS instead of always latest Node version.

2.3.2

Notable enhancements and fixes

  • Fixed admin ui displaying incorrect text

2.3.1

Notable enhancements and fixes

  • Dependency updates

2.3.0

Notable enhancements and fixes

  • Added possibility to cluster Etherpads behind reverse proxy. There is now a new reverse proxy designed for Etherpads that handles multiple Etherpads and the created pads in them. It will assign the pad assignement to an Etherpad at random but once the choice was made it will always reverse proxy the same backend. This allows to host multiple concurrent Etherpads and benefit from multi core systems even though one Etherpad is singlethreaded.
  • Added reverse proxy configuration for replacing Nginx. In the past there were some issues with nginx and its configuration. This reverse proxy allows you to handle your configuration with ease.

If you want to find out more about the reverse proxy method check out the repository https://github.com/ether/etherpad-proxy . It also contains a sample docker-compose file with three Etherpads and one etherpad-proxy. Of course you need to adapt the settings.json.template to your liking and map it into the reverse proxy image before you are ready :).

  • Added client authorization to work with Etherpad. Before it would get blocked because it doesn't have the required claim. As this is now fixed etherpad-proxy can also work with your new OAuth2 configuration and retrieve a token via client credentials flow.

2.2.7

Notable enhancements and fixes

  • We migrated all important pages to React 19 and React Router v7

Besides that only dependency updates.

-> Have a merry Christmas and a happy new year. 🎄 🎁

2.2.6

Notable enhancements and fixes

  • Added option to delete a pad by the creator. This option can be found in the settings menu. When you click on it you get a confirm dialog and after that you have the chance to completely erase the pad.

2.2.5

Notable enhancements and fixes

  • Fixed timeslider not scrolling when the revision count is a multiple of 100
  • Added new Restful API for version 2 of Etherpad. It is available at /api-docs

2.2.4

Notable enhancements and fixes

  • Switched to new SQLite backend
  • Fixed rusty-store-kv module not found

2.2.3

Notable enhancements and fixes

  • Introduced a new in process database rustydb that represents a fast key value store written in Rust.
  • Readded window._ as a shortcut for getting text
  • Added support for migrating any ueberdb database to another. You can now switch as you please. See here: https://docs.etherpad.org/cli.html
  • Further Typescript movements
  • A lot of security issues fixed and reviewed in this release. Please update.

2.2.2

Notable enhancements and fixes

  • Removal of Etherpad require kernel: We finally managed to include esbuild to bundle our frontend code together. So no matter how many plugins your server has it is always one JavaScript file. This boosts performance dramatically.
  • Added log layoutType: This lets you print the log in either colored or basic (black and white text)
  • Introduced esbuild for bundling CSS files
  • Cache all files to be bundled in memory for faster load speed

2.1.1

Notable enhancements and fixes

  • Fixed failing Docker build when checked out as git submodule. Thanks to @neurolabs
  • Fixed: Fallback to websocket and polling when unknown(old) config is present for socket io
  • Fixed: Next page disabled if zero page by @samyakj023
  • On CTRL+CLICK bring the window back to focus by Helder Sepulveda

2.1.0

Notable enhancements and fixes

  • Added PWA support. You can now add your Etherpad instance to your home screen on your mobile device or desktop.
  • Fixed live plugin manager versions clashing. Thanks to @yacchin1205
  • Fixed a bug in the pad panel where pagination was not working correctly when sorting by pad name

Compatibility changes

  • Reintroduced APIKey.txt support. You can now switch between APIKey and OAuth2.0 authentication. This can be toggled with the setting authenticationMethod. The default is OAuth2. If you want to use the APIKey method you can set that to apikey.

2.0.3

Notable enhancements and fixes

  • Added documentation for replacing apikeys with oauth2
  • Bumped live plugin manager to 0.20.0. Thanks to @fgreinacher
  • Added better documentation for using docker-compose with Etherpad

2.0.2

Notable enhancements and fixes

  • Fixed the locale loading in the admin panel
  • Added OAuth2.0 support for the Etherpad API. You can now log in into the Etherpad API with your admin user using OAuth2

Compatibility changes

  • The tests now require generating a token from the OAuth secret. You can find the generateJWTToken in the common.ts script for plugin endpoint updates.

2.0.1

Notable enhancements and fixes

  • Fixed a bug where a plugin depending on a scoped dependency would not install successfully.

2.0.0

Compatibility changes

  • Socket io has been updated to 4.7.5. This means that the json.send function won't work anymore and needs to be changed to .emit('message', myObj)
  • Deprecating npm version 6 in favor of pnpm: We have made the decision to switch to the well established pnpm (https://pnpm.io/). It works by symlinking dependencies into a global directory allowing you to have a cleaner and more reliable environment.
  • Introducing Typescript to the Etherpad core: Etherpad core logic has been rewritten in Typescript allowing for compiler checking of errors.
  • Rewritten Admin Panel: The Admin panel has been rewritten in React and now features a more pleasant user experience. It now also features an integrated pad searching with sorting functionality.

Notable enhancements and fixes

  • Bugfixes

    • Live Plugin Manager: The live plugin manager caused problems when a plugin had depdendencies defined. This issue is now resolved.
  • Enhancements

    • pnpm Workspaces: In addition to pnpm we introduced workspaces. A clean way to manage multiple bounded contexts like the admin panel or the bin folder.
    • Bin folder: The bin folder has been moved from the src folder to the root folder. This change was necessary as the contained scripts do not represent core functionality of the user.
    • Starting Etherpad: Etherpad can now be started with a single command: pnpm run prod in the root directory.
    • Installing Etherpad: Etherpad no longer symlinks itself in the root directory. This is now also taken care by pnpm, and it just creates a node_modules folder with the src directory`s ep_etherpad-lite folder
    • Plugins can now be installed simply via the command: pnpm run plugins i first-plugin second-plugin or if you want to install from path you can do: pnpm run plugins i --path ../path-to-plugin

1.9.7

Notable enhancements and fixes

  • Added Live Plugin Manager: Plugins are now installed into a separate folder on the host system. This folder is called plugin_packages. That way the plugins are separated from the normal etherpad installation.
  • Make repairPad.js more verbose
  • Fixed favicon not being loaded correctly

1.9.6

Notable enhancements and fixes

  • Prevent etherpad crash when update server is not reachable
  • Use npm@6 in Docker build
  • Fix setting the log level in settings.json

1.9.5

Compatibility changes

  • This version deprecates NodeJS16 as it reached its end of life and won't receive any updates. So to get started with Etherpad v1.9.5 you need NodeJS 18 and above.
  • The bundled windows NodeJS version has been bumped to the current LTS version 20.

Notable enhancements and fixes

  • The support for the tidy program to tidy up HTML files has been removed. This decision was made because it hasn't been updated for years and also caused an incompability when exporting a pad with Abiword.

1.9.4

Compatibility changes

  • Log4js has been updated to the latest version. As it involved a bump of 6 major version. A lot has changed since then. Most notably the console appender has been deprecated. You can find out more about it here

Notable enhancements and fixes

  • Fix for MySQL: The logger calls were incorrectly configured leading to a crash when e.g. somebody uses a different encoding than standard MySQL encoding.

1.9.3

Compability changes

  • express-rate-limit has been bumped to 7.0.0: This involves the breaking change that "max: 0" in the importExportRateLimiting is set to always trigger. So set it to your desired value. If you haven't changed that value in the settings.json you are all set.

Notable enhancements and fixes

  • Bugfixes

    • Fix etherpad crashing with mongodb database
  • Enhancements

    • Add surrealdb database support. You can find out more about this database here.
    • Make sqlite faster: The sqlite library has been switched to better-sqlite3. This should lead to better performance.

1.9.2

Notable enhancements and fixes

  • Security

    • Enable session key rotation: This setting can be enabled in the settings.json. It changes the signing key for the cookie authentication in a fixed interval.
  • Bugfixes

    • Fix appendRevision when creating a new pad via the API without a text.
  • Enhancements

    • Bump JQuery to version 3.7
    • Update elasticsearch connector to version 8

Compatibility changes

  • No compability changes as JQuery maintains excellent backwards compatibility.

For plugin authors

  • Please update to JQuery 3.7. There is an excellent deprecation guide over here. Version 3.1 to 3.7 are relevant for the upgrade.

1.9.1

Notable enhancements and fixes

  • Security

    • Limit requested revisions in timeslider and export to head revision. (affects v1.9.0)
  • Bugfixes

    • revisions in CHANGESET_REQ (timeslider) and export (txt, html, custom) are now checked to be numbers.
    • bump sql for audit fix
  • Enhancements

    • Add keybinding meta-backspace to delete to beginning of line
    • Fix automatic Windows build via GitHub Actions
    • Enable docs to be build cross platform thanks to asciidoctor

Compatibility changes

  • tests: drop windows 7 test coverage & use chrome latest for admin tests
  • Require Node 16 for Etherpad and target Node 20 for testing

1.9.0

Notable enhancements and fixes

  • Windows build:
    • The bundled node.exe was upgraded from v12 to v16.
    • The bundled node.exe is now a 64-bit executable. If you need the 32-bit version you must download and install Node.js yourself.
  • Improvements to login session management:
    • express_sid cookies and sessionstorage:* database records are no longer created unless requireAuthentication is true (or a plugin causes them to be created).
    • Login sessions now have a finite lifetime by default (10 days after leaving).
    • sessionstorage:* database records are automatically deleted when the login session expires (with some exceptions that will be fixed in the future).
    • Requests for static content (e.g., /robots.txt) and special pages (e.g., the HTTP API, /stats) no longer create login session state.
    • The secret used to sign the express_sid cookie is now automatically regenerated every day (called key rotation) by default. If key rotation is enabled, the now-deprecated SESSIONKEY.txt file can be safely deleted after Etherpad starts up (its content is read and saved to the database and used to validate signatures from old cookies until they expire).
  • The following settings from settings.json are now applied as expected (they were unintentionally ignored before):
    • padOptions.lang
    • padOptions.showChat
    • padOptions.userColor
    • padOptions.userName
  • HTTP API:
    • Fixed the return value of getText when called with a specific revision.
    • Fixed a potential attribute pool corruption bug with copyPadWithoutHistory.
    • Mappings created by createGroupIfNotExistsFor are now removed from the database when the group is deleted.
    • Fixed race conditions in the setText, appendText, and restoreRevision functions.
    • Added an optional authorId parameter to appendText, copyPadWithoutHistory, createGroupPad, createPad, restoreRevision, setHTML, and setText, and bumped the latest API version to 1.3.0.
  • Fixed a crash if the database is busy enough to cause a query timeout.
  • New /health endpoint for getting information about Etherpad's health (see draft-inadarei-api-health-check-06).
  • Docker now uses the new /health endpoint for health checks, which avoids issues when authentication is enabled. It also avoids the unnecessary creation of database records for managing browser sessions.
  • When copying a pad, the pad's records are copied in batches to avoid database timeouts with large pads.
  • Exporting a large pad to .etherpad format should be faster thanks to bulk database record fetches.
  • When importing an .etherpad file, records are now saved to the database in batches to avoid database timeouts with large pads.

For plugin authors

  • New expressPreSession server-side hook.
  • Pad server-side hook changes:
    • padCheck: New hook.
    • padCopy: New srcPad and dstPad context properties.
    • padDefaultContent: New hook.
    • padRemove: New pad context property.
  • The db property on Pad objects is now public.
  • New getAuthorId server-side hook.
  • New APIs for processing attributes: ep_etherpad-lite/static/js/attributes (low-level API) and ep_etherpad-lite/static/js/AttributeMap (high-level API).
  • The import server-side hook has a new ImportError context property.
  • New exportEtherpad and importEtherpad server-side hooks.
  • The handleMessageSecurity and handleMessage server-side hooks have a new sessionInfo context property that includes the user's author ID, the pad ID, and whether the user only has read-only access.
  • The handleMessageSecurity server-side hook can now be used to grant write access for the current message only.
  • The init_<pluginName> server-side hooks have a new logger context property that plugins can use to log messages.
  • Prevent infinite loop when exiting the server
  • Bump dependencies

Compatibility changes

  • Node.js v14.15.0 or later is now required.
  • The default login session expiration (applicable if requireAuthentication is true) changed from never to 10 days after the user leaves.

For plugin authors

  • The client context property for the handleMessageSecurity and handleMessage server-side hooks is deprecated; use the socket context property instead.
  • Pad server-side hook changes:
    • padCopy:
      • The originalPad context property is deprecated; use srcPad instead.
      • The destinationID context property is deprecated; use dstPad.id instead.
    • padCreate: The author context property is deprecated; use the new authorId context property instead. Also, the hook now runs asynchronously.
    • padLoad: Now runs when a temporary Pad object is created during import. Also, it now runs asynchronously.
    • padRemove: The padID context property is deprecated; use pad.id instead.
    • padUpdate: The author context property is deprecated; use the new authorId context property instead. Also, the hook now runs asynchronously.
  • Returning true from a handleMessageSecurity hook function is deprecated; return 'permitOnce' instead.
  • Changes to the src/static/js/Changeset.js library:
    • The following attribute processing functions are deprecated (use the new attribute APIs instead):
      • attribsAttributeValue()
      • eachAttribNumber()
      • makeAttribsString()
      • opAttributeValue()
    • opIterator(): Deprecated in favor of the new deserializeOps() generator function.
    • appendATextToAssembler(): Deprecated in favor of the new opsFromAText() generator function.
    • newOp(): Deprecated in favor of the new Op class.
  • The AuthorManager.getAuthor4Token() function is deprecated; use the new AuthorManager.getAuthorId() function instead.
  • The exported database records covered by the exportEtherpadAdditionalContent server-side hook now include keys like ${customPrefix}:${padId}:*, not just ${customPrefix}:${padId}.
  • Plugin locales should overwrite core's locales Stale
  • Plugin locales overwrite core locales

1.8.18

Released: 2022-05-05

Notable enhancements and fixes

  • Upgraded ueberDB to fix a regression with CouchDB.

1.8.17

Released: 2022-02-23

Security fixes

  • Fixed a vunlerability in the CHANGESET_REQ message handler that allowed a user with any access to read any pad if the pad ID is known.

Notable enhancements and fixes

  • Fixed a bug that caused all pad edit messages received at the server to go through a single queue. Now there is a separate queue per pad as intended, which should reduce message processing latency when many pads are active at the same time.

1.8.16

Security fixes

If you cannot upgrade to v1.8.16 for some reason, you are encouraged to try cherry-picking the fixes to the version you are running:

git cherry-pick b7065eb9a0ec..77bcb507b30e
  • Maliciously crafted .etherpad files can no longer overwrite arbitrary non-pad database records when imported.
  • Imported .etherpad files are now subject to numerous consistency checks before any records are written to the database. This should help avoid denial-of-service attacks via imports of malformed .etherpad files.

Notable enhancements and fixes

  • Fixed several .etherpad import bugs.
  • Improved support for large .etherpad imports.

1.8.15

Security fixes

  • Fixed leak of the writable pad ID when exporting from the pad's read-only ID. This only matters if you treat the writeable pad IDs as secret (e.g., you are not using ep_padlist2) and you share the pad's read-only ID with untrusted users. Instead of treating writeable pad IDs as secret, you are encouraged to take advantage of Etherpad's authentication and authorization mechanisms (e.g., use ep_openid_connect with ep_readonly_guest, or write your own authentication and authorization plugins).
  • Updated dependencies.

Compatibility changes

  • The logconfig setting is deprecated.

For plugin authors

  • Etherpad now uses jsdom instead of cheerio for processing HTML imports. There are two consequences of this change:
    • require('ep_etherpad-lite/node_modules/cheerio') no longer works. To fix, your plugin should directly depend on cheerio and do require('cheerio').
    • The collectContentImage hook's node context property is now an HTMLImageElement object rather than a Cheerio Node-like object, so the API is slightly different. See citizenos/ep_image_upload#49 for an example fix.
  • The clientReady server-side hook is deprecated; use the new userJoin hook instead.
  • The init_<pluginName> server-side hooks are now run every time Etherpad starts up, not just the first time after the named plugin is installed.
  • The userLeave server-side hook's context properties have changed:
    • auth: Deprecated.
    • author: Deprecated; use the new authorId property instead.
    • readonly: Deprecated; use the new readOnly property instead.
    • rev: Deprecated.
  • Changes to the src/static/js/Changeset.js library:
    • opIterator(): The unused start index parameter has been removed, as has the unused lastIndex() method on the returned object.
    • smartOpAssembler(): The returned object's appendOpWithText() method is deprecated without a replacement available to plugins (if you need one, let us know and we can make the private opsFromText() function public).
    • Several functions that should have never been public are no longer exported: applyZip(), assert(), clearOp(), cloneOp(), copyOp(), error(), followAttributes(), opString(), stringOp(), textLinesMutator(), toBaseTen(), toSplices().

Notable enhancements and fixes

  • Accessibility fix for JAWS screen readers.
  • Fixed "clear authorship" error (see issue #5128).
  • Etherpad now considers square brackets to be valid URL characters.
  • The server no longer crashes if an exception is thrown while processing a message from a client.
  • The useMonospaceFontGlobal setting now works (thanks @Lastpixl!).
  • Chat improvements:
    • The message input field is now a text area, allowing multi-line messages (use shift-enter to insert a newline).
    • Whitespace in chat messages is now preserved.
  • Docker improvements:
    • New HEALTHCHECK instruction (thanks @Gared!).
    • New settings.json variables: DB_COLLECTION, DB_URL, SOCKETIO_MAX_HTTP_BUFFER_SIZE, DUMP_ON_UNCLEAN_EXIT (thanks @JustAnotherArchivist!).
    • .ep_initialized files are no longer created.
  • Worked around a Firefox Content Security Policy bug that caused CSP failures when 'self' was in the CSP header. See issue #4975 for details.
  • UeberDB upgraded from v1.4.10 to v1.4.18. For details, see the ueberDB changelog. Highlights:
    • The postgrespool driver was renamed to postgres, replacing the old driver of that name. If you used the old postgres driver, you may see an increase in the number of database connections.
    • For postgres, you can now set the dbSettings value in settings.json to a connection string (e.g., "postgres://user:password@host/dbname") instead of an object.
    • For mongodb, the dbName setting was renamed to database (but dbName still works for backwards compatibility) and is now optional (if unset, the database name in url is used).
  • /admin/settings now honors the --settings command-line argument.
  • Fixed "Author X tried to submit changes as author Y" detection.
  • Error message display improvements.
  • Simplified pad reload after importing an .etherpad file.

For plugin authors

  • clientVars was added to the context for the postAceInit client-side hook. Plugins should use this instead of the clientVars global variable.
  • New userJoin server-side hook.
  • The userLeave server-side hook has a new socket context property.
  • The helper.aNewPad() function (accessible to client-side tests) now accepts hook functions to inject when opening a pad. This can be used to test any new client-side hooks your plugin provides.
  • Chat improvements:
    • The chatNewMessage client-side hook context has new properties:
      • message: Provides access to the raw message object so that plugins can see the original unprocessed message text and any added metadata.
      • rendered: Allows plugins to completely override how the message is rendered in the UI.
    • New chatSendMessage client-side hook that enables plugins to process the text before sending it to the server or augment the message object with custom metadata.
    • New chatNewMessage server-side hook to process new chat messages before they are saved to the database and relayed to users.
  • Readability improvements to browser-side error stack traces.
  • Added support for socket.io message acknowledgments.

1.8.14

Security fixes

  • Fixed a persistent XSS vulnerability in the Chat component. In case you can't update to 1.8.14 directly, we strongly recommend to cherry-pick a796811558. Thanks to sonarsource for the professional disclosure.

Compatibility changes

  • Node.js v12.13.0 or later is now required.
  • The favicon setting is now interpreted as a pathname to a favicon file, not a URL. Please see the documentation comment in settings.json.template.
  • The undocumented faviconPad and faviconTimeslider settings have been removed.
  • MySQL/MariaDB now uses connection pooling, which means you will see up to 10 connections to the MySQL/MariaDB server (by default) instead of 1. This might cause Etherpad to crash with a "ER_CON_COUNT_ERROR: Too many connections" error if your server is configured with a low connection limit.
  • Changes to environment variable substitution in settings.json (see the documentation comments in settings.json.template for details):
    • An environment variable set to the string "null" now becomes null instead of the string "null". Similarly, if the environment variable is unset and the default value is "null" (e.g., "${UNSET_VAR:null}"), the value now becomes null instead of the string "null". It is no longer possible to produce the string "null" via environment variable substitution.
    • An environment variable set to the string "undefined" now causes the setting to be removed instead of set to the string "undefined". Similarly, if the environment variable is unset and the default value is "undefined" (e.g., "${UNSET_VAR:undefined}"), the setting is now removed instead of set to the string "undefined". It is no longer possible to produce the string "undefined" via environment variable substitution.
    • Support for unset variables without a default value is now deprecated. Please change all instances of "${FOO}" in your settings.json to ${FOO:null} to keep the current behavior.
    • The DB_* variable substitutions in settings.json.docker that previously defaulted to null now default to "undefined".
  • Calling next without argument when using Changeset.opIterator does always return a new Op. See b9753dcc71 for details.

Notable enhancements and fixes

  • MySQL/MariaDB now uses connection pooling, which should improve stability and reduce latency.
  • Bulk database writes are now retried individually on write failure.
  • Minify: Avoid crash due to unhandled Promise rejection if stat fails.
  • padIds are now included in /socket.io query string, e.g. https://video.etherpad.com/socket.io/?padId=AWESOME&EIO=3&transport=websocket&t=...&sid=.... This is useful for directing pads to separate socket.io nodes.