mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-17 16:47:05 +00:00
fix(pad): don't issue a deletion token (or show its modal) when allowPadDeletionByAllUsers is on (#7929)
When `allowPadDeletionByAllUsers` is true, anyone can delete a pad with no token at all (handlePadDelete's flagOk branch), so the one-time deletion token is pointless and the "Save your pad deletion token" modal only overwhelms users who will never need it. Gate token issuance on `!settings.allowPadDeletionByAllUsers` so no token reaches clientVars; the client's showDeletionTokenModalIfPresent() then returns early and the modal never appears. No new setting — it derives automatically from the existing one. Closes #7926. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1e7c4b8c21
commit
f47626049c
2 changed files with 53 additions and 4 deletions
|
|
@ -1287,9 +1287,15 @@ const handleClientReady = async (socket:any, message: ClientReadyMessage) => {
|
|||
// once. Readonly sessions never see it.
|
||||
const isCreator =
|
||||
!sessionInfo.readonly && sessionInfo.author === await pad.getRevisionAuthor(0);
|
||||
// Skip token issuance when requireAuthentication is on: every creator has a
|
||||
// stable identity so the cookie/identity path is sufficient.
|
||||
const padDeletionToken = isCreator && !settings.requireAuthentication
|
||||
// Skip token issuance — and so the client never shows the "Save your pad
|
||||
// deletion token" modal (issue #7926) — when the token cannot help:
|
||||
// - requireAuthentication: every creator already has a stable identity, so
|
||||
// the cookie/identity path is sufficient.
|
||||
// - allowPadDeletionByAllUsers: anyone can delete the pad with no token at
|
||||
// all (see handlePadDelete's flagOk branch), so a recovery token is noise
|
||||
// and the modal only overwhelms users who will never need it.
|
||||
const padDeletionToken =
|
||||
isCreator && !settings.requireAuthentication && !settings.allowPadDeletionByAllUsers
|
||||
? await padDeletionManager.createDeletionTokenIfAbsent(sessionInfo.padId)
|
||||
: null;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe(__filename, function () {
|
|||
plugins.hooks[hookName] = [];
|
||||
}
|
||||
backups.settings = {};
|
||||
for (const setting of ['editOnly', 'requireAuthentication', 'requireAuthorization', 'users', 'enablePadWideSettings']) {
|
||||
for (const setting of ['editOnly', 'requireAuthentication', 'requireAuthorization', 'users', 'enablePadWideSettings', 'allowPadDeletionByAllUsers']) {
|
||||
// @ts-ignore
|
||||
backups.settings[setting] = settings[setting];
|
||||
}
|
||||
|
|
@ -492,6 +492,49 @@ describe(__filename, function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Pad deletion token issuance (#7926)', function () {
|
||||
const removeIfExists = async (padId: string) => {
|
||||
if (await padManager.doesPadExist(padId)) {
|
||||
const p = await padManager.getPad(padId);
|
||||
await p.remove();
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(async function () {
|
||||
// @ts-ignore - public setting toggled per test
|
||||
settings.allowPadDeletionByAllUsers = false;
|
||||
await removeIfExists('pad');
|
||||
});
|
||||
afterEach(async function () {
|
||||
if (socket) socket.close();
|
||||
socket = null;
|
||||
await removeIfExists('pad');
|
||||
});
|
||||
|
||||
it('anonymous creator receives a deletion token by default', async function () {
|
||||
const res = await agent.get('/p/pad').expect(200);
|
||||
socket = await common.connect(res);
|
||||
const cv: any = await common.handshake(socket, 'pad');
|
||||
assert.equal(cv.type, 'CLIENT_VARS');
|
||||
assert.equal(typeof cv.data.padDeletionToken, 'string',
|
||||
'creator should get a token so the client can show the save-token modal');
|
||||
assert.ok(cv.data.padDeletionToken.length >= 32);
|
||||
});
|
||||
|
||||
it('no token (and so no modal) when allowPadDeletionByAllUsers is true', async function () {
|
||||
// @ts-ignore - public setting
|
||||
settings.allowPadDeletionByAllUsers = true;
|
||||
const res = await agent.get('/p/pad').expect(200);
|
||||
socket = await common.connect(res);
|
||||
const cv: any = await common.handshake(socket, 'pad');
|
||||
assert.equal(cv.type, 'CLIENT_VARS');
|
||||
// A null token means showDeletionTokenModalIfPresent() returns early on the
|
||||
// client, so the "Save your pad deletion token" modal never appears. Anyone
|
||||
// can already delete the pad without a token in this configuration.
|
||||
assert.equal(cv.data.padDeletionToken, null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SocketIORouter.js', function () {
|
||||
const Module = class {
|
||||
setSocketIO(io:any) {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue