fix(community): CR fixes — 嵌套按钮 + OG 封面 URL sanitize#317
Conversation
Copilot CR 指出的两条: PR #315 Hero.tsx:119 —— <a> 包 <button> 是嵌套交互元素(HTML 无效 + a11y 问题) 修法:把 <Link> 直接渲染成按钮样式,不再嵌套 <button> PR #316 LinkCard.tsx:52 / admin/community/page.tsx:143 —— OG 封面 URL 直接进 <img src> 没过白名单。 修法:用 lib/url-safety.ts 的 sanitizeMediaUrl 兜底,拦 javascript:/data: 协议 (后端 UrlNormalizer 是第一道防线,前端 sanitize 是 defense-in-depth)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR addresses outstanding code review feedback in the community/feed UI by fixing invalid nested interactive elements in the homepage Hero CTAs and adding defense-in-depth URL sanitization for OG cover images before rendering them into <img src>.
Changes:
- Refactors Hero CTAs to avoid invalid
<a><button/></a>nesting by styling<Link>elements directly as button-like CTAs. - Sanitizes OG cover image URLs with
sanitizeMediaUrlbefore using them in<img src>in both feed cards and the admin moderation page. - Keeps
referrerPolicy="no-referrer"behavior for hotlink-protected image hosts (WeChat/Zhihu/etc.).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| app/feed/components/LinkCard.tsx | Sanitizes ogCover before rendering into <img src> for feed cards. |
| app/components/Hero.tsx | Removes nested <button> inside <Link> and applies button styles to the link itself. |
| app/admin/community/page.tsx | Sanitizes ogCover before rendering into <img src> in the admin review list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export function LinkCard({ link, categoryLabel, isLoggedIn }: LinkCardProps) { | ||
| const t = useTranslations("feed.card"); | ||
| // defense-in-depth:过白名单协议拦 javascript:/data:,后端 UrlNormalizer 是第一道,这里是第二道 | ||
| const safeOgCover = sanitizeMediaUrl(link.ogCover); | ||
|
|
There was a problem hiding this comment.
LinkCard now sanitizes link.ogCover, but the card’s main <a href={link.url}> still uses a backend-provided URL without going through sanitizeExternalUrl. Since url-safety.ts documents that any backend/user-provided URLs must be sanitized before rendering, this remains an XSS vector (e.g., javascript:). Consider sanitizing link.url and rendering the card as non-clickable (or fallback to text) when the URL is unsafe.
收尾 Copilot 在 #315 / #316 上留的两条 CR:
typecheck 0 errors。