From 9e37ed833f7ef10900dc0a95225574ec9ca13134 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 17 May 2026 13:07:25 +0100 Subject: [PATCH 1/2] fix(API): exclude SYSTEM_AUTHOR_ID from listAuthorsOfPad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pad.SYSTEM_AUTHOR_ID ('a.etherpad-system') is the synthetic author Etherpad attributes inserts to when the HTTP API receives a call without authorId (setText, setHTML, appendText, the server-side import flows, and plugins like ep_post_data). It exists so the changeset's text and attribs stay in sync — without ANY author attribute, pad.atext drifts and clients fail setDocAText reconciliation when loading the pad. See Pad.ts:96-105 for the full rationale. That bookkeeping detail was leaking through listAuthorsOfPad: a pad whose only "contributor" is the system author still reported one authorID, which the existing tests in pad.ts and appendTextAuthor.ts (and presumably any caller that uses listAuthorsOfPad to count real users) treat as a real participant. Filter SYSTEM_AUTHOR_ID at the API surface so internal attribution stays internal. getAllAuthors() and downstream callers (copy, anonymize, atext verification) keep seeing the synthetic id — this only narrows the public listAuthorsOfPad response. Fixes #7785 Fixes #7790 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/node/db/API.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/node/db/API.ts b/src/node/db/API.ts index 38d06297386..a1bf4e6bb63 100644 --- a/src/node/db/API.ts +++ b/src/node/db/API.ts @@ -831,7 +831,13 @@ Example returns: exports.listAuthorsOfPad = async (padID: string) => { // get the pad const pad = await getPadSafe(padID, true); - const authorIDs = pad.getAllAuthors(); + // Pad.SYSTEM_AUTHOR_ID is the synthetic author Etherpad attributes inserts to + // when no authorId is supplied (HTTP API setText/appendText/setHTML without + // authorId, server-side import flows, plugins like ep_post_data). It is an + // implementation detail of changeset bookkeeping, not a real contributor, so + // it should not surface through this public API. + const {Pad} = require('./Pad'); + const authorIDs = pad.getAllAuthors().filter((id: string) => id !== Pad.SYSTEM_AUTHOR_ID); return {authorIDs}; }; From aed441e1c7f6a2b26b4896677459fbb36ee72e64 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 17 May 2026 13:17:31 +0100 Subject: [PATCH 2/2] docs(api): note that listAuthorsOfPad omits the system author MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match the runtime behaviour from the previous commit — the synthetic 'a.etherpad-system' author used for unattributed inserts is filtered out of the listAuthorsOfPad response. Co-Authored-By: Claude Opus 4.7 (1M context) --- doc/api/http_api.adoc | 2 ++ doc/api/http_api.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/api/http_api.adoc b/doc/api/http_api.adoc index 82313c54aa8..19c2839b44d 100644 --- a/doc/api/http_api.adoc +++ b/doc/api/http_api.adoc @@ -654,6 +654,8 @@ _Example returns:_ returns an array of authors who contributed to this pad +The synthetic `a.etherpad-system` author (used internally when content is inserted without an explicit `authorId` — HTTP API `setText`/`appendText`/`setHTML` calls without `authorId`, server-side imports, plugins like `ep_post_data`) is omitted from the returned list. + _Example returns:_ * `{code: 0, message:"ok", data: {authorIDs : ["a.s8oes9dhwrvt0zif", "a.akf8finncvomlqva"]}` diff --git a/doc/api/http_api.md b/doc/api/http_api.md index 35437f23eb1..c9c57bfeb32 100644 --- a/doc/api/http_api.md +++ b/doc/api/http_api.md @@ -698,6 +698,8 @@ return true of false returns an array of authors who contributed to this pad +The synthetic `a.etherpad-system` author (used internally when content is inserted without an explicit `authorId` — HTTP API `setText`/`appendText`/`setHTML` calls without `authorId`, server-side imports, plugins like `ep_post_data`) is omitted from the returned list. + *Example returns:* * `{code: 0, message:"ok", data: {authorIDs : ["a.s8oes9dhwrvt0zif", "a.akf8finncvomlqva"]}` * `{code: 1, message:"padID does not exist", data: null}`