Skip to content

Commit 8429f24

Browse files
committed
feat: Now exploits can be seen in TIX details modal
1 parent c49aad6 commit 8429f24

File tree

1 file changed

+116
-11
lines changed

1 file changed

+116
-11
lines changed

components/feature/vexgen/TIXDetailsModal.tsx

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22

3+
import { useState } from 'react'
34
import {
45
Dialog,
56
DialogContent,
@@ -10,8 +11,18 @@ import {
1011
CardContent,
1112
CardHeader,
1213
CardTitle,
14+
Button,
1315
} from '@/components/ui'
14-
import { AlertTriangle, Info, Calendar, Shield, ExternalLink, Bug } from 'lucide-react'
16+
import {
17+
AlertTriangle,
18+
Info,
19+
Calendar,
20+
Shield,
21+
ExternalLink,
22+
Bug,
23+
ChevronDown,
24+
ChevronUp,
25+
} from 'lucide-react'
1526

1627
interface CVSSInfo {
1728
vuln_impact: number
@@ -85,6 +96,17 @@ export default function TIXDetailsModal({
8596
repositoryName,
8697
translations,
8798
}: TIXDetailsModalProps) {
99+
const [expandedPayloads, setExpandedPayloads] = useState<Set<string>>(new Set())
100+
101+
const togglePayload = (exploitId: string) => {
102+
const newExpanded = new Set(expandedPayloads)
103+
if (newExpanded.has(exploitId)) {
104+
newExpanded.delete(exploitId)
105+
} else {
106+
newExpanded.add(exploitId)
107+
}
108+
setExpandedPayloads(newExpanded)
109+
}
88110
const formatDate = (dateString: string) => {
89111
if (!dateString) return 'N/A'
90112
return new Date(dateString).toLocaleDateString('es-ES', {
@@ -478,16 +500,99 @@ export default function TIXDetailsModal({
478500
{translations.tixDetailsModal?.knownExploits ||
479501
'Known Exploits'}
480502
</p>
481-
<Badge
482-
variant={
483-
statement.exploits.length > 0 ? 'destructive' : 'secondary'
484-
}
485-
className="text-xs"
486-
>
487-
{statement.exploits.length > 0
488-
? `${statement.exploits.length} ${translations.tixDetailsModal?.available || 'available'}`
489-
: translations.tixDetailsModal?.notKnown || 'Not known'}
490-
</Badge>
503+
{statement.exploits.length > 0 ? (
504+
<div className="space-y-2">
505+
<Badge variant="destructive" className="text-xs mb-2">
506+
{statement.exploits.length}{' '}
507+
{translations.tixDetailsModal?.available || 'available'}
508+
</Badge>
509+
<div className="space-y-2 max-h-32 sm:max-h-40 overflow-y-auto">
510+
{statement.exploits.map(
511+
(exploit: any, exploitIndex: number) => {
512+
const exploitId = `${index}-${exploitIndex}`
513+
const isExpanded = expandedPayloads.has(exploitId)
514+
const shouldTruncate =
515+
exploit.payload && exploit.payload.length > 500
516+
517+
return (
518+
<div
519+
key={exploitIndex}
520+
className="bg-muted/30 rounded-lg p-2 sm:p-3"
521+
>
522+
<div className="flex flex-col sm:flex-row sm:items-center gap-2 mb-2">
523+
<a
524+
href={exploit['@id']}
525+
target="_blank"
526+
rel="noopener noreferrer"
527+
className="text-sm font-medium text-blue-600 hover:text-blue-800 hover:underline flex items-center gap-1 break-all"
528+
>
529+
{exploit.name}
530+
<ExternalLink className="h-3 w-3 flex-shrink-0" />
531+
</a>
532+
{exploit.attack_vector &&
533+
exploit.attack_vector !== 'NONE' && (
534+
<Badge variant="outline" className="text-xs">
535+
{exploit.attack_vector}
536+
</Badge>
537+
)}
538+
</div>
539+
{exploit.description &&
540+
exploit.description.trim() && (
541+
<p className="text-xs text-muted-foreground line-clamp-2 mb-2">
542+
{exploit.description}
543+
</p>
544+
)}
545+
{exploit.payload && (
546+
<div className="bg-background border rounded p-2">
547+
<div className="flex items-center justify-between mb-1">
548+
<p className="text-xs font-medium text-muted-foreground">
549+
Payload/Details:
550+
</p>
551+
{shouldTruncate && (
552+
<Button
553+
variant="ghost"
554+
size="sm"
555+
onClick={() => togglePayload(exploitId)}
556+
className="h-6 px-2 text-xs"
557+
>
558+
{isExpanded ? (
559+
<>
560+
<ChevronUp className="h-3 w-3 mr-1" />
561+
Show less
562+
</>
563+
) : (
564+
<>
565+
<ChevronDown className="h-3 w-3 mr-1" />
566+
Show more
567+
</>
568+
)}
569+
</Button>
570+
)}
571+
</div>
572+
<div
573+
className={`text-xs font-mono text-gray-700 dark:text-gray-300 overflow-y-auto ${
574+
isExpanded ? 'max-h-96' : 'max-h-20'
575+
}`}
576+
>
577+
<pre className="whitespace-pre-wrap break-words">
578+
{isExpanded || !shouldTruncate
579+
? exploit.payload
580+
: `${exploit.payload.substring(0, 500)}...`}
581+
</pre>
582+
</div>
583+
</div>
584+
)}
585+
</div>
586+
)
587+
}
588+
)}
589+
</div>
590+
</div>
591+
) : (
592+
<Badge variant="secondary" className="text-xs">
593+
{translations.tixDetailsModal?.notKnown || 'Not known'}
594+
</Badge>
595+
)}
491596
</div>
492597
</div>
493598

0 commit comments

Comments
 (0)