Repository navigation
fix(widget): conversation export review follow-ups - #159
Merged
Merged
Conversation
The exception that spares a line-leading autolink from the HTML-block escape accepted any local part before the "@". So `<!--a@b>`, `<?a@b>` and `<![CDATA[a@b>` passed as addresses and were left unescaped, and each opens a CommonMark block that runs across blank lines until a terminator that never comes. In a rendered transcript, every later message vanished. The address form must now start with a letter or digit. Real autolinks such as <help@example.com> and <https://example.com> are still left alone. Checked against micromark: after each of those lines the next message now survives rendering. Shipped in 1.17.0. Only reachable by a deliberately crafted message, and only against the author's own export, in an opt-in feature. Follow-up to #55. The design doc now records the exception, which it never did. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s up legacyCopy removed its textarea and restored focus in a `finally`, but neither call was guarded. A throw there replaced the function's result, and copyText calls it outside its own try, so the promise rejected on the host page: the one thing copyText promises never to do. Each cleanup step now has its own guard. A copy that worked still reports true if tidying up fails, and a failed removal no longer costs the visitor their focus as well. Shipped in 1.17.0. Needs a document where remove() or focus() throws, so it is theoretical, but the contract is "never rejects". Follow-up to #55. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Review of the previous commit found one statement in legacyCopy still outside every guard: reading document.activeElement runs before its try, and copyText called legacyCopy outside its own. A throw there rejected the promise. It cannot realistically happen, but "never rejects" should be structural, not the result of auditing each statement, so the call is now wrapped and answers false. The temporary textarea also leaves the tab order. If removing it ever fails, it must not stay behind as a keyboard stop that holds the whole transcript while hidden from assistive technology. Follow-up to #55. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… once CommonMark allows "?" and "!" in an address, so <?q@example.com> and <!weird@example.com> are valid autolinks that also open a processing instruction and a declaration that never close. They are the strongest cases for the rule that an address must start with a letter or digit. Confirmed to fail against the 1.17.0 regex. Follow-up to #55. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The comment added with the fix gave a wrong reason. It said "!", "?" and "[" begin exactly the blocks that span blank lines. "[" begins nothing (CDATA starts with "!"), and "exactly" is false: script, pre, style and textarea blocks also span blank lines and start with a letter, which the address form allows. They stay escaped for a structural reason instead: the tag name must be followed by whitespace, ">" or the end of the line, and neither ":" nor "@" is any of those. A wrong rationale above a regex that has already shipped one bug is how the next one gets in, so the comment and the design doc now record the real invariant and what would break it. No behaviour change. Follow-up to #55. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
size-limit report 📦
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #55 (already closed) and #157. Two small bugs in conversation export that shipped in 1.17.0. They were found by the re-review of #157's final fix wave, after that wave had closed, so they went out unapplied. The feature is opt-in, so no embed is affected unless a site has switched it on.
What
1. A crafted line could hide the rest of a rendered transcript (09f45fc). Message text gets a backslash in front of a line-leading
<so an unterminated HTML block cannot swallow later messages. Autolinks such as<https://example.com>and<help@example.com>are exempt, because escaping them shows the brackets and links the wrong place. That exemption accepted any text before the@, so<!--a@b>,<?a@b>and<![CDATA[a@b>passed as addresses, stayed unescaped, and opened a block that never closes. The address must now start with a letter or digit. Real autolinks are still left alone. Only reachable by a deliberately crafted message, and only against the author's own export.2.
copyTextcould reject, which it promises never to do (03a76a1, 7a3bf81). TheexecCommandfallback removed its textarea and restored focus in afinallywithout guarding either call, andcopyTextcalled the fallback outside its owntry. Each cleanup step is now guarded, so a copy that worked still reportstrueand a failed removal does not also cost the visitor their focus. The whole call is wrapped too, so "never rejects" is structural rather than something each statement has to be audited for. The temporary textarea also leaves the tab order, so if removal ever failed it could not linger as a keyboard stop holding the transcript.3. A comment I wrote gave the wrong reason the fix is safe (e639d3b). It said
!,?and["begin exactly the blocks that span blank lines".[begins nothing, and<script/<pre/<style/<textareablocks also span blank lines and start with a letter. They stay escaped for a structural reason: the tag name must be followed by whitespace,>or the end of the line, and neither:nor@is any of those. The comment and the design doc now say that, and what would break it. The design doc had never recorded the autolink exemption at all. No behaviour change.How it was verified
Test-first throughout: each new test was seen failing against the 1.17.0 code for the stated reason before its fix.
tsc, TypeDocreact-refreshwarnings onChatWidget.tsxare on main too)chromium-desktopBeyond the unit tests:
execCommandfallback in real Chrome, for the first time. Until now it had only ever run in jsdom against a mockedexecCommand. Withnavigator.clipboardremoved to force the fallback: the copy command ran once on the focused textarea, the "Copied to clipboard" status appeared, the textarea was removed, focus returned to the menu trigger, and the transcript was on the system clipboard.Notes
cdn/claudius.iife.js. Until then, sites on the@1tag keep the 1.17.0 build. Since the feature is off by default, nothing is exposed unless a site has enabled it.🤖 Generated with Claude Code