Skip to content

fix(pad): suppress deletion-token modal when allowPadDeletionByAllUsers is on (#7926)#7929

Open
JohnMcLear wants to merge 1 commit into
developfrom
fix/7926-no-deletion-token-when-deletion-open
Open

fix(pad): suppress deletion-token modal when allowPadDeletionByAllUsers is on (#7926)#7929
JohnMcLear wants to merge 1 commit into
developfrom
fix/7926-no-deletion-token-when-deletion-open

Conversation

@JohnMcLear

Copy link
Copy Markdown
Member

Problem

Closes #7926.

The one-time pad deletion token is minted for the creator on their first visit, and the client pops a "Save your pad deletion token" modal. As the reporter notes, for many users (children/students, less technical teachers) this modal is confusing and overwhelming.

When an instance sets allowPadDeletionByAllUsers: true, the token is pointless: anyone can already delete the pad with no token at all (handlePadDelete's flagOk branch). So in that configuration the modal is pure noise.

Change

Gate token issuance on !settings.allowPadDeletionByAllUsers in handleClientReady:

const padDeletionToken =
    isCreator && !settings.requireAuthentication && !settings.allowPadDeletionByAllUsers
    ? await padDeletionManager.createDeletionTokenIfAbsent(sessionInfo.padId)
    : null;

With no token in clientVars, the client's showDeletionTokenModalIfPresent() returns early and the modal never appears. This implements the reporter's first (preferred) option — it derives automatically from the existing setting, no new setting required.

This PR is intentionally minimal and unconditionally safe (a token is never needed when everyone can delete). A follow-up PR will handle the related ideas discussed on the issue — suppressing the token for authenticated/OIDC sessions that carry a durable cross-device identity, and the deletion-button naming.

Test

src/tests/backend/specs/socketio.ts — new "Pad deletion token issuance (#7926)" block:

  • anonymous creator still receives a token by default (≥32 chars);
  • no token in clientVars when allowPadDeletionByAllUsers is true.

Full socketio.ts suite: 41 passing.

🤖 Generated with Claude Code

…PadDeletionByAllUsers is on

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>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (1)

Context used

Grey Divider


Action required

1. delete-pad-with-token still rendered 📎 Requirement gap ≡ Correctness
Description
When allowPadDeletionByAllUsers is true, the UI still includes deletion-token-related
controls/text (the "Delete with token" section) even though the token is unnecessary. This violates
the requirement to fully suppress deletion token UI in this configuration, not just the one-time
modal.
Code

src/node/handler/PadMessageHandler.ts[R1297-1300]

+    const padDeletionToken =
+        isCreator && !settings.requireAuthentication && !settings.allowPadDeletionByAllUsers
        ? await padDeletionManager.createDeletionTokenIfAbsent(sessionInfo.padId)
        : null;
Evidence
Rule 1 requires suppression of deletion-token UI when allowPadDeletionByAllUsers is true.
Although the PR gates token issuance in handleClientReady, the token-related UI section ("Delete
with token" and token input) is still rendered whenever !settings.requireAuthentication, with no
check for allowPadDeletionByAllUsers.

Disable pad deletion token UI when allowPadDeletionByAllUsers is true
src/node/handler/PadMessageHandler.ts[1297-1300]
src/templates/pad.html[390-398]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR suppresses issuance of `clientVars.padDeletionToken` when `settings.allowPadDeletionByAllUsers` is enabled, which prevents the one-time modal. However, the settings UI still renders the token-related delete controls ("Delete with token" section), which violates the requirement that deletion-token UI should not appear at all when `allowPadDeletionByAllUsers` is `true`.

## Issue Context
The token-related controls are rendered in `pad.html` under a condition that only checks `!settings.requireAuthentication`, so they remain present even when `allowPadDeletionByAllUsers` is enabled.

## Fix Focus Areas
- src/templates/pad.html[390-398]
- src/node/handler/PadMessageHandler.ts[1297-1300]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Token missing after toggle 🐞 Bug ☼ Reliability
Description
handleClientReady now skips createDeletionTokenIfAbsent() when
settings.allowPadDeletionByAllUsers is true, so pads created/first-visited under that
configuration will never get a deletion token. If the flag is later disabled, an anonymous creator
who no longer has the original author cookie cannot delete the pad via the recovery-token path
because handlePadDelete requires a creator cookie or a valid token when the flag is off.
Code

src/node/handler/PadMessageHandler.ts[R1297-1300]

+    const padDeletionToken =
+        isCreator && !settings.requireAuthentication && !settings.allowPadDeletionByAllUsers
        ? await padDeletionManager.createDeletionTokenIfAbsent(sessionInfo.padId)
        : null;
Evidence
The diff gates token issuance on !settings.allowPadDeletionByAllUsers. Deletion authorization
requires either creator-cookie, valid token, or the flag; and the token is only persisted if
createDeletionTokenIfAbsent() is called. The client provides a deletion-by-token path that depends
on the token having been created and shared previously.

src/node/handler/PadMessageHandler.ts[1284-1300]
src/node/handler/PadMessageHandler.ts[290-314]
src/node/db/PadDeletionManager.ts[20-36]
src/static/js/pad_editor.ts[152-176]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `allowPadDeletionByAllUsers` is true at pad creation/first-visit time, the server never mints a deletion token for the pad. If an operator later disables `allowPadDeletionByAllUsers`, anonymous creators who have lost their author cookie have no recovery-token path to delete those pads.

## Issue Context
This is an edge case triggered by a later configuration change, but it results in user-visible inability to delete pads without admin intervention.

## Fix Focus Areas
- src/node/handler/PadMessageHandler.ts[1284-1300]

## Suggested fix direction
Implement one of the following:
1) Add an explicit operator-facing warning (startup log and/or admin docs surfaced in logs) when `allowPadDeletionByAllUsers` is enabled that deletion tokens are not issued and disabling the flag later can strand anonymous creators.
2) Alternatively (more robust), decouple "modal suppression" from "token availability" by adding a non-modal, creator-only way to retrieve/copy the token later (while they still have the creator cookie), so enabling `allowPadDeletionByAllUsers` doesn’t permanently prevent creators from ever obtaining a token.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Suppress pad deletion-token modal when open deletion is enabled
🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

Walkthroughs

User Description

Problem

Closes #7926.

The one-time pad deletion token is minted for the creator on their first visit, and the client pops a "Save your pad deletion token" modal. As the reporter notes, for many users (children/students, less technical teachers) this modal is confusing and overwhelming.

When an instance sets allowPadDeletionByAllUsers: true, the token is pointless: anyone can already delete the pad with no token at all (handlePadDelete's flagOk branch). So in that configuration the modal is pure noise.

Change

Gate token issuance on !settings.allowPadDeletionByAllUsers in handleClientReady:

const padDeletionToken =
    isCreator && !settings.requireAuthentication && !settings.allowPadDeletionByAllUsers
    ? await padDeletionManager.createDeletionTokenIfAbsent(sessionInfo.padId)
    : null;

With no token in clientVars, the client's showDeletionTokenModalIfPresent() returns early and the modal never appears. This implements the reporter's first (preferred) option — it derives automatically from the existing setting, no new setting required.

This PR is intentionally minimal and unconditionally safe (a token is never needed when everyone can delete). A follow-up PR will handle the related ideas discussed on the issue — suppressing the token for authenticated/OIDC sessions that carry a durable cross-device identity, and the deletion-button naming.

Test

src/tests/backend/specs/socketio.ts — new "Pad deletion token issuance (#7926)" block:

  • anonymous creator still receives a token by default (≥32 chars);
  • no token in clientVars when allowPadDeletionByAllUsers is true.

Full socketio.ts suite: 41 passing.

🤖 Generated with Claude Code

AI Description
• Stop minting pad deletion tokens when any user can delete pads via configuration.
• Prevent the client from showing the save-token modal by omitting the token from clientVars.
• Add socket.io backend tests covering token issuance vs. allowPadDeletionByAllUsers behavior.
Diagram
graph TD
  A["Browser client"] --> B["Socket.IO handshake"] --> C["PadMessageHandler.handleClientReady"] --> D["Token gating (settings)"] --> E["padDeletionManager.createDeletionTokenIfAbsent"]
  D --> F["clientVars.padDeletionToken"] --> A
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Client-side suppression only
  • ➕ No server behavior change; purely UI/UX adjustment
  • ➕ Easy to conditionally hide modal based on settings already in clientVars
  • ➖ Still mints and transmits a pointless token when open deletion is enabled
  • ➖ Leaves unused security artifacts around and adds conceptual clutter
2. Introduce a dedicated setting to disable the modal/token
  • ➕ Explicit control for admins independent of deletion policy
  • ➕ Could support nuanced cases beyond allowPadDeletionByAllUsers
  • ➖ Adds configuration surface area and documentation burden
  • ➖ Higher chance of misconfiguration; unnecessary for the reported issue
3. Always mint token but omit from clientVars for specific sessions
  • ➕ Could preserve token availability for later recovery workflows
  • ➕ Allows decoupling of issuance from presentation
  • ➖ Adds complexity and unclear lifecycle/ownership for an unneeded token when open deletion is enabled
  • ➖ Does not align with the claim that token is never needed in this configuration

Recommendation: Keep the current approach: gate token issuance on !allowPadDeletionByAllUsers (and existing !requireAuthentication). It’s the simplest, least surprising behavior—when anyone can delete, a recovery token provides no value—while also preventing the modal without adding new configuration knobs. The added backend tests appropriately lock in the intended behavior.

Grey Divider

File Changes

Bug fix (1)
PadMessageHandler.ts Gate deletion-token issuance when open pad deletion is enabled +9/-3

Gate deletion-token issuance when open pad deletion is enabled

• Extends the creator token issuance condition in handleClientReady to also require allowPadDeletionByAllUsers to be false. Adds explanatory comments tying the behavior to the modal suppression and the fact that tokens are unnecessary when any user can delete pads.

src/node/handler/PadMessageHandler.ts


Tests (1)
socketio.ts Add socket.io tests for pad deletion token issuance rules +44/-1

Add socket.io tests for pad deletion token issuance rules

• Adds a new test block asserting that anonymous creators receive a token by default, and that padDeletionToken is null when allowPadDeletionByAllUsers is true. Updates settings backup/restore coverage to include allowPadDeletionByAllUsers for test isolation.

src/tests/backend/specs/socketio.ts


Grey Divider

Qodo Logo

Comment on lines +1297 to 1300
const padDeletionToken =
isCreator && !settings.requireAuthentication && !settings.allowPadDeletionByAllUsers
? await padDeletionManager.createDeletionTokenIfAbsent(sessionInfo.padId)
: null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. delete-pad-with-token still rendered 📎 Requirement gap ≡ Correctness

When allowPadDeletionByAllUsers is true, the UI still includes deletion-token-related
controls/text (the "Delete with token" section) even though the token is unnecessary. This violates
the requirement to fully suppress deletion token UI in this configuration, not just the one-time
modal.
Agent Prompt
## Issue description
The PR suppresses issuance of `clientVars.padDeletionToken` when `settings.allowPadDeletionByAllUsers` is enabled, which prevents the one-time modal. However, the settings UI still renders the token-related delete controls ("Delete with token" section), which violates the requirement that deletion-token UI should not appear at all when `allowPadDeletionByAllUsers` is `true`.

## Issue Context
The token-related controls are rendered in `pad.html` under a condition that only checks `!settings.requireAuthentication`, so they remain present even when `allowPadDeletionByAllUsers` is enabled.

## Fix Focus Areas
- src/templates/pad.html[390-398]
- src/node/handler/PadMessageHandler.ts[1297-1300]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — this is a deliberate scoping decision, not an oversight. This PR is intentionally minimal: it fixes the issue's primary complaint (the overwhelming "Save your pad deletion token" modal) with an unconditionally-safe server change.

The remaining deletion-token controls (relabeling the "Delete with token" disclosure to "Delete Pad" when no token is needed) are handled in the stacked follow-up #7930, which adds a canDeleteWithoutToken clientVar and switches the disclosure label accordingly. The maintainer (@JohnMcLear) explicitly asked to split this into two PRs — modal suppression first, the UI/label bits second.

Note we keep the disclosure present rather than removing it: with enablePadWideSettings: false it can be the only delete affordance, so hiding it outright would be unsafe. #7930 relabels instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disable pad deletion token UI when allowPadDeletionByAllUsers is true

1 participant