wulf-pulse/components/phishing/url-list.tsx
lorentz 87008a5da6 feat(22-03): add tooltip primitive + inert UrlList component (D-09)
- npx shadcn add tooltip generates components/ui/tooltip.tsx (official
  registry, no npm dependency added)
- components/phishing/url-list.tsx renders extracted URLs as inert
  <code> text with copy-to-clipboard only — no <a>/href, no <Link>,
  no navigating onClick per D-09
2026-07-16 14:27:11 -04:00

50 lines
1.5 KiB
TypeScript

'use client';
/* UrlList — inert, copy-only rendering of URLs extracted from a reported
* phishing/spam email (REVIEW-03, D-09).
*
* D-09 is a deliberately STRICTER-than-sanitization posture: extracted URLs
* are attacker-controlled content and must never be rendered as anything
* clickable. There is no anchor tag with a navigation attribute, no
* `<Link>`, and no navigating `onClick` anywhere in this file — the only
* affordance is copy-to-clipboard via an icon-only button. Do not "improve"
* this by adding a real link. */
import { Copy } from 'lucide-react';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
interface UrlListProps {
urls: string[];
}
export function UrlList({ urls }: UrlListProps) {
if (urls.length === 0) {
return (
<p className="text-sm text-muted-foreground">No URLs found in this message.</p>
);
}
async function handleCopy(url: string) {
await navigator.clipboard.writeText(url);
toast.success('Copied');
}
return (
<ul className="flex flex-col gap-2">
{urls.map((url, index) => (
<li key={`${url}-${index}`} className="flex items-center gap-2">
<code className="font-mono text-xs truncate flex-1">{url}</code>
<Button
size="icon"
variant="ghost"
aria-label="Copy URL"
onClick={() => handleCopy(url)}
>
<Copy className="h-3.5 w-3.5" />
</Button>
</li>
))}
</ul>
);
}