Claude: changes for issue #93 #94
No reviewers
Labels
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente!94
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "claude/issue-93"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #93.
Anything on the board can now be handed to somebody. ShareLink is the one place that says what a shareable thing's link is and the one place that reads one back; a card's link is its board's plus ?card={id}, which the board strips again the moment it has opened the dialog. The share itself is a ladder — the platform's sheet, then the clipboard, then an off-screen selection — resolved against location.origin in the browser rather than built absolutely on the server, since the browser is the only party that knows for certain which origin a page is read from. calendar-interop now re-exports that clipboard fallback instead of keeping its own. A shared link survives the sign-in screen: ReturnUrl is the single rule for whether a value may be a redirect target, applied by the login page and by /login/start (including on every one of its error redirects) and honoured by /dev/login so the suite can walk it without OAuth. A link pasted back into a description or a comment, alone on its line, renders as the card or board it points at. LinkPreviewService is the one card-reading path that access-checks, because it is the only one whose id comes from text a member typed; a card that is missing or not theirs falls back to the plain link, and the two are deliberately the same answer. Open Graph tags describe the app and never the page — an unfurler is an anonymous fetch by somebody else's server, and this board is private. Adds ShareLinkTests, RichTextTests, ReturnUrlTests and share.spec.js, and a 2.5.0 changelog entry.🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
✅ Verdict: approve — no blocking issues found.
This is a large, well-scoped feature (link sharing, deep-linked cards, link-card unfurling, safe return-URL handling for sign-in, and app-level Open Graph metadata) and it holds up well under review.
Things specifically checked and found correct:
ShareLink.TryParse/SameOrigin: absolute URLs are only accepted when scheme+host+port match the caller-supplied origin, sohttps://evil.example/board/3?card=9and lookalike hosts (ponente.app.evil.example, wrong port) are correctly refused — verified againstShareLinkTests. The rooted-path check runs beforeUri.TryCreate(..., UriKind.Absolute, ...), which is required on Unix where a bare/board/3would otherwise parse as afile://URI (the code comment calls this out explicitly and gets the ordering right).ReturnUrl.Sanitize: blocks//host,/host, non-local paths, and now also strips any candidate containing control characters (defense against header/redirect injection), applied consistently at/login/start,/login(render),/dev/login/{did}, andRoutes.razor'sNotAuthorizedbranch — a single source of truth as the PR claims.LinkPreviewService: correctly re-checks board visibility per request viaBoardService.CanViewAsync/ResolveAsync(sameBoardAccess.VisibleTopredicate used everywhere else), and treats missing/denied identically without leaking which case occurred — this is the one new path that reads aCardoutside of an already-access-checked circuit, and it's handled the way the architecture notes prescribe.LinkCard.razorrenderspreview.Title/tag names as plain text (notMarkupString), so Blazor auto-encodes them; the onlyMarkupStringuse is the existing sanitizedMarkdown.ToHtmlpipeline insideRichTextView, unchanged in that regard.comment-body/composer-previewlosing themarkdownclass on the outer div in favor of a nested one fromRichTextView) doesn't break existing styling — verified no CSS rule targets.comment-body/.composer-previewcombined with.markdown; the outer divs are pure layout containers and.markdownrules apply the same as before.og:imagepoints at/icon-512.png, which exists and matches the manifest exactly, consistent with the "full mark, not favicon.svg" rule.share.*,meta.description) are present and identical in bothen/de, satisfying the locale parity test; the changelog entry avoids the jargon guard's banned terms.LinkPreviewService/BoardServiceare both scoped, matching DI conventions in this codebase.Nothing here looks like a blocking bug. A couple of very minor, non-blocking notes:
RichTextView'sReferenceEqualsmemoization guard will rarely hit given fresh decrypted strings on every reload (so it's effectively a no-op optimization in the common case), andshare.cards/pluralization isn't handled for the1 cardcase — neither is worth blocking on.⏱ 3m 53s · 22 turns · tokens: 120.0k in / 20.1k out (+2768.2k cache-read)
📜 Full session transcript