etherpad-lite/src/node/handler
John McLear ce038b0b0f
fix(pad): keep token-less Delete pad reachable without pad-wide settings (#7959) (#7960)
* fix(pad): keep token-less Delete pad reachable without pad-wide settings (#7959)

The token-less "Delete pad" button (#delete-pad) was nested inside the
enablePadWideSettings-gated pad-settings section, so disabling pad-wide
settings removed the only way to delete a pad without a recovery token.
Combined with #7926 hiding the token disclosure when deletion needs no
token (e.g. allowPadDeletionByAllUsers), a user who was allowed to delete
could be left with no deletion UI at all.

Pad deletion is unrelated to pad-wide settings, so:

- Move #delete-pad out of the enablePadWideSettings block in pad.html; it
  is now always rendered and hidden by default.
- Add a canDeletePad clientVar (isCreator || allowPadDeletionByAllUsers)
  and drive the button's visibility from it in pad_editor.ts, mirroring the
  existing canDeleteWithoutToken handling for the token disclosure.

The two controls are now mutually coherent and neither depends on
enablePadWideSettings: the plain button shows when this session can delete
without a token, the recovery-token disclosure shows otherwise.

Tests:
- backend padDeletionUiPlacement.ts: #delete-pad is rendered with
  enablePadWideSettings both on and off (fails without the template move).
- backend socketio.ts: canDeletePad reflects the creator/allow-all matrix,
  including a non-creator who only gains it under allowPadDeletionByAllUsers.
- frontend pad_settings.spec.ts: asserts #delete-pad is no longer a
  descendant of #pad-settings-section.

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

* fix(pad): never let readonly sessions delete via token-less paths (#7959)

Qodo review of #7960: `canDeletePad` was `isCreator || allowPadDeletionByAllUsers`,
so under allowPadDeletionByAllUsers a readonly viewer received
canDeletePad=true and the relocated #delete-pad button unhid for them.
Worse, the server-side handlePadDelete `flagOk`/`creatorOk` branches never
checked session.readonly either, so a readonly-link holder could actually
delete the pad without a token — a data-loss hole that the new always-rendered
button would expose.

Exclude readonly sessions from both the clientVar and the server's token-less
authorization paths. A valid recovery token (tokenOk) stays a sufficient
credential regardless of session mode.

Test: socketio.ts asserts a readonly viewer gets canDeletePad=false and that a
token-less PAD_DELETE from a readonly session leaves the pad intact (red before
this change on the clientVar assertion).

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 15:18:23 +01:00
..
APIHandler.ts harden: assorted server-side tightening for 3.0.2 (#7784) 2026-05-17 13:19:41 +01:00
APIKeyHandler.ts chore: migrated settings to esm6 (#7062) 2025-08-04 22:42:50 +02:00
ExportHandler.ts fix(export): surface checkValidRev error message on bad :rev (#7792) 2026-05-17 13:20:05 +01:00
ImportHandler.ts harden: assorted server-side tightening for 3.0.2 (#7784) 2026-05-17 13:19:41 +01:00
PadMessageHandler.ts fix(pad): keep token-less Delete pad reachable without pad-wide settings (#7959) (#7960) 2026-06-17 15:18:23 +01:00
RestAPI.ts Hardening: API request handling, random IDs, and plugin loading (#7906) 2026-06-07 19:17:39 +02:00
SocketIORouter.ts feat(gdpr): IP/privacy audit (PR2 of #6701) (#7547) 2026-05-01 13:47:40 +01:00