fix: allow undo of clear authorship colors without disconnect#7430
fix: allow undo of clear authorship colors without disconnect#7430JohnMcLear wants to merge 6 commits intoether:developfrom
Conversation
891d1b8 to
6e83dd7
Compare
|
bump @SamTV12345 and @webzwo0i |
…2802) When a user clears authorship colors and then undoes, the undo changeset re-applies author attributes for all authors who contributed text. The server was rejecting this because it treated any changeset containing another author's ID as impersonation, disconnecting the user. The fix distinguishes between: - '+' ops (new text): still reject if attributed to another author - '=' ops (attribute changes on existing text): allow restoring other authors' attributes, which is needed for undo of clear authorship Also removes the client-side workaround in undomodule.ts that prevented clear authorship from being undone at all, and adds backend + frontend tests covering the multi-author undo scenario. Fixes: ether#2802 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use toHaveAttribute with regex instead of raw getAttribute + toContain - Check div/span attributes within pad body instead of broad selectors - Use Playwright auto-retry (expect with timeout) instead of toHaveCount(0) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add page.on('dialog') handler to accept the confirm dialog triggered
by clearAuthorship when no text is selected (clears whole pad)
- Use auto-retrying toHaveAttribute assertions instead of raw getAttribute
- Increase cross-user sync timeouts to 15s for CI reliability
- Add retries: 2 to multi-user test for CI flakiness
- Scope assertions to pad body spans instead of broad selectors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace sequential waitForSocketEvent loops with single persistent listeners that filter messages inline. This prevents race conditions where messages arrive between off/on listener cycles, causing timeouts on slower CI runners. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The '-' op attribs are discarded from the document but still get added to the pad's attribute pool by moveOpsToNewPool. Without this check, an attacker could inject a fabricated author ID into the pool via a '-' op, then use a '=' op to attribute text to that fabricated author (bypassing the pool existence check). Now all non-'=' ops (+, -) with foreign author IDs are rejected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
eba9b12 to
1aefafa
Compare
|
Is this MR ready for review? I could check it. Normally draft is not yet ready :) But I could also be mistaken. |
|
@SamTV12345 yes please, |
Review Summary by QodoAllow undo of clear authorship colors without disconnect
WalkthroughsDescription• Allow undo of clear authorship colors without server disconnect - Distinguish between = ops (restore existing author attributes) and +/- ops (reject foreign authors) - Validate = ops against pad pool to prevent fabricated author attribution • Remove client-side workaround blocking clear authorship from undo stack • Add comprehensive backend and frontend tests for multi-author undo scenarios Diagramflowchart LR
A["User clears authorship<br/>removes all author attribs"] -->|undo changeset| B["Re-applies author attribs<br/>for all contributors"]
B -->|server validation| C{"Op type?"}
C -->|"+ or -"| D["Reject if foreign author<br/>prevent impersonation"]
C -->|"="| E["Check pad pool<br/>allow if author exists"]
E -->|valid| F["Accept changeset<br/>undo succeeds"]
D -->|invalid| G["Disconnect badChangeset"]
E -->|fabricated| G
File Changes1. src/node/handler/PadMessageHandler.ts
|
Code Review by Qodo
1.
|
| * https://github.com/ether/etherpad-lite/issues/2802 | ||
| */ | ||
| if (event && (event.eventType !== 'clearauthorship')) { | ||
| if (event) { |
There was a problem hiding this comment.
So we now basically push all the events? Even if it is clearAuthorship?
There was a problem hiding this comment.
Yes, take your time to read the Known limitations part... We're basically just moving the problem away from it being a broken UX to a potential untruth of authorship. It's highly unlikely anyone would ever exploit it AND there would be revision history to show who/how/when it was exploited so it's a bit like spitting on your fingerprints to hide your criminality.. All it takes is a curious eye to swab test for DNA and you are still busted....
There was a problem hiding this comment.
Yes, intentionally. The old eventType !== 'clearauthorship' filter was a client-side workaround added in #2802 because the server was disconnecting users whose undo changeset reapplied another author's colors (it treated any foreign author ID as impersonation).
The real fix is server-side: Pad.ts now distinguishes + ops (new text — still reject foreign author) from = ops (attribute-only changes — allow restoring other authors' colors for undo). With that in place, the client filter is no longer needed and clear-authorship becomes undoable, which is the point of this PR.
Merge-same-type deduplication and identity-backset skipping still apply, so we're not "push all events unconditionally" — we just stopped singling out clearauthorship.
There was a problem hiding this comment.
True so I guess the impact is low. Yeah I am in favor of not creating some client side special exceptions for events. Good work. Feel free to merge when you have all the qodo warnings removed.
Addresses Qodo review: linestylefilter skips attribs with empty values, so a span with author='' has no class attribute at all. The previous negative-lookahead regex on the class attribute failed against a null attribute and was flaky in CI. Switch to not.toHaveClass(/author-/), which also passes when the attribute is missing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
PadMessageHandler.ts): The author validation now distinguishes between=ops (attribute changes on existing text — allows restoring other authors' attributes if they exist in the pad pool) and+/-ops (both reject foreign author IDs). The-op rejection prevents a pool injection attack where fabricated author IDs could be smuggled into the pad pool via delete attribs.undomodule.ts): The stopgap that preventedclearauthorshipevents from being pushed onto the undo stack is removed — users can now undo/redo clear authorship normally.-op pool injection prevention. 2 frontend Playwright tests for multi-user and single-user undo flows. Updated existingclear_authorship_color.spec.ts.Context
Clicking "clear authorship colors" without any text selected clears the entire pad's authorship colors. When a user then presses Ctrl+Z to undo, the undo changeset re-applies the original author attributes for all authors who contributed text. The server's author validation rejected this because it treated any changeset containing another author's ID as impersonation, disconnecting the user with
badChangeset.The fix distinguishes between:
=operations (applying attributes to existing text) — allows restoring previously-existing author attributes, gated by verifying the author ID exists in the pad's attribute pool+operations (inserting new text) — still rejects if attributed to another author-operations (deleting text) — still rejects if carrying another author's attribs (prevents pool injection:-attribs are discarded from the doc but added topad.poolbymoveOpsToNewPool, which could be exploited to bypass the=op pool check)Known limitations
=ops. Full mitigation requires diffing againstpad.atextat each character position (tracked separately). Timeslider would show correct author at previous revisions so if someone attempted to attribute text to an author this would be discoverable through the timeslider. Not ideal and something we need to patch moving forward. Because of that I will ask @SamTV12345 and @webzwo0i to review this and confirm if they are happy with this "fix" with the knowledge that in the future we should bake in more safety to ensure truthfulness in authorship attribution.Test plan
undo_clear_authorship.ts— 6 tests all passing locallymessages.tstests still pass (10/10)clear_authorship_color.spec.tsupdated — handles confirm dialog, expects undo to restore colorsundo_clear_authorship.spec.ts— multi-user and single-user undo scenariosFixes #2802
🤖 Generated with Claude Code