From 270e3c657607be6dfd04fa0c45256328f4023f2f Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 6 Apr 2026 13:31:57 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20very=20old=20.etherpad=20imports=20could?= =?UTF-8?q?=20break=20import=20due=20to=20lack=20of=20aut=E2=80=A6=20(#747?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: very old .etherpad imports could break import due to lack of author metadata, allow this now * test: add regression tests for old .etherpad import without author Tests that importing an old .etherpad export (circa 2014) where revision records lack meta.author succeeds without error, and that getRevisionAuthor returns '' for such revisions. Covers the fix for #6785. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- src/node/db/Pad.ts | 2 +- src/tests/backend/specs/ImportEtherpad.ts | 43 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/node/db/Pad.ts b/src/node/db/Pad.ts index 2789f1867..821487cda 100644 --- a/src/node/db/Pad.ts +++ b/src/node/db/Pad.ts @@ -173,7 +173,7 @@ class Pad { async getRevisionAuthor(revNum: number) { // @ts-ignore - return await this.db.getSub(`pad:${this.id}:revs:${revNum}`, ['meta', 'author']); + return await this.db.getSub(`pad:${this.id}:revs:${revNum}`, ['meta', 'author']) ?? ''; } async getRevisionDate(revNum: number) { diff --git a/src/tests/backend/specs/ImportEtherpad.ts b/src/tests/backend/specs/ImportEtherpad.ts index b9ac9baaf..9da4511d1 100644 --- a/src/tests/backend/specs/ImportEtherpad.ts +++ b/src/tests/backend/specs/ImportEtherpad.ts @@ -171,6 +171,49 @@ describe(__filename, function () { } }); + // Regression test for https://github.com/ether/etherpad-lite/issues/6785 + describe('old .etherpad imports without author metadata', function () { + // Old exports (circa 2014) have revisions where meta.author is missing entirely + const makeOldExportNoAuthor = () => ({ + 'pad:testing': { + atext: { + text: 'foo\n', + attribs: '|1+4', + }, + pool: { + numToAttrib: {}, + nextNum: 0, + }, + head: 0, + savedRevisions: [], + }, + // Revision 0 has no meta.author — this is how very old etherpads exported + 'pad:testing:revs:0': { + changeset: 'Z:1>3+3$foo', + meta: { + timestamp: 1273769875976, + atext: { + text: 'foo\n', + attribs: '|1+4', + }, + }, + }, + }); + + it('imports without error when revision lacks meta.author', async function () { + await importEtherpad.setPadRaw(padId, JSON.stringify(makeOldExportNoAuthor())); + const pad = await padManager.getPad(padId); + assert.equal(pad.text(), 'foo\n'); + assert.equal(pad.head, 0); + }); + + it('getRevisionAuthor returns empty string for missing author', async function () { + await importEtherpad.setPadRaw(padId, JSON.stringify(makeOldExportNoAuthor())); + const pad = await padManager.getPad(padId); + assert.equal(await pad.getRevisionAuthor(0), ''); + }); + }); + describe('exportEtherpadAdditionalContent', function () { let hookBackup: Function;