@cyvest/cyvest-vis 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -10
- package/dist/index.d.mts +156 -6
- package/dist/index.d.ts +156 -6
- package/dist/index.js +1445 -650
- package/dist/index.mjs +1457 -665
- package/package.json +2 -2
- package/src/components/CyvestGraph.tsx +115 -46
- package/src/components/FloatingEdge.tsx +41 -11
- package/src/components/Icons.tsx +730 -0
- package/src/components/InvestigationGraph.tsx +107 -36
- package/src/components/InvestigationNode.tsx +129 -112
- package/src/components/ObservableNode.tsx +116 -135
- package/src/components/ObservablesGraph.tsx +241 -111
- package/src/hooks/useForceLayout.ts +136 -62
- package/src/index.ts +25 -2
- package/src/types.ts +9 -11
- package/src/utils/observables.ts +9 -97
- package/tests/observables.test.ts +10 -17
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Professional SVG icons for the visualization components.
|
|
3
|
+
* Hand-crafted icons optimized for small sizes and clear recognition.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
|
|
8
|
+
export interface IconProps {
|
|
9
|
+
size?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const defaultSize = 16;
|
|
15
|
+
const defaultColor = "currentColor";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Network/Globe icon for IP addresses
|
|
19
|
+
*/
|
|
20
|
+
export const GlobeIcon: React.FC<IconProps> = ({
|
|
21
|
+
size = defaultSize,
|
|
22
|
+
color = defaultColor,
|
|
23
|
+
className,
|
|
24
|
+
}) => (
|
|
25
|
+
<svg
|
|
26
|
+
width={size}
|
|
27
|
+
height={size}
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
fill="none"
|
|
30
|
+
stroke={color}
|
|
31
|
+
strokeWidth="2"
|
|
32
|
+
strokeLinecap="round"
|
|
33
|
+
strokeLinejoin="round"
|
|
34
|
+
className={className}
|
|
35
|
+
>
|
|
36
|
+
<circle cx="12" cy="12" r="10" />
|
|
37
|
+
<path d="M2 12h20" />
|
|
38
|
+
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Home/Domain icon for domain names
|
|
44
|
+
*/
|
|
45
|
+
export const DomainIcon: React.FC<IconProps> = ({
|
|
46
|
+
size = defaultSize,
|
|
47
|
+
color = defaultColor,
|
|
48
|
+
className,
|
|
49
|
+
}) => (
|
|
50
|
+
<svg
|
|
51
|
+
width={size}
|
|
52
|
+
height={size}
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke={color}
|
|
56
|
+
strokeWidth="2"
|
|
57
|
+
strokeLinecap="round"
|
|
58
|
+
strokeLinejoin="round"
|
|
59
|
+
className={className}
|
|
60
|
+
>
|
|
61
|
+
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
|
62
|
+
<polyline points="9,22 9,12 15,12 15,22" />
|
|
63
|
+
</svg>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Link icon for URLs
|
|
68
|
+
*/
|
|
69
|
+
export const LinkIcon: React.FC<IconProps> = ({
|
|
70
|
+
size = defaultSize,
|
|
71
|
+
color = defaultColor,
|
|
72
|
+
className,
|
|
73
|
+
}) => (
|
|
74
|
+
<svg
|
|
75
|
+
width={size}
|
|
76
|
+
height={size}
|
|
77
|
+
viewBox="0 0 24 24"
|
|
78
|
+
fill="none"
|
|
79
|
+
stroke={color}
|
|
80
|
+
strokeWidth="2"
|
|
81
|
+
strokeLinecap="round"
|
|
82
|
+
strokeLinejoin="round"
|
|
83
|
+
className={className}
|
|
84
|
+
>
|
|
85
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
86
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
87
|
+
</svg>
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Mail icon for email addresses
|
|
92
|
+
*/
|
|
93
|
+
export const MailIcon: React.FC<IconProps> = ({
|
|
94
|
+
size = defaultSize,
|
|
95
|
+
color = defaultColor,
|
|
96
|
+
className,
|
|
97
|
+
}) => (
|
|
98
|
+
<svg
|
|
99
|
+
width={size}
|
|
100
|
+
height={size}
|
|
101
|
+
viewBox="0 0 24 24"
|
|
102
|
+
fill="none"
|
|
103
|
+
stroke={color}
|
|
104
|
+
strokeWidth="2"
|
|
105
|
+
strokeLinecap="round"
|
|
106
|
+
strokeLinejoin="round"
|
|
107
|
+
className={className}
|
|
108
|
+
>
|
|
109
|
+
<rect x="2" y="4" width="20" height="16" rx="2" />
|
|
110
|
+
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
|
111
|
+
</svg>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Envelope icon for email messages
|
|
116
|
+
*/
|
|
117
|
+
export const EnvelopeIcon: React.FC<IconProps> = ({
|
|
118
|
+
size = defaultSize,
|
|
119
|
+
color = defaultColor,
|
|
120
|
+
className,
|
|
121
|
+
}) => (
|
|
122
|
+
<svg
|
|
123
|
+
width={size}
|
|
124
|
+
height={size}
|
|
125
|
+
viewBox="0 0 24 24"
|
|
126
|
+
fill="none"
|
|
127
|
+
stroke={color}
|
|
128
|
+
strokeWidth="2"
|
|
129
|
+
strokeLinecap="round"
|
|
130
|
+
strokeLinejoin="round"
|
|
131
|
+
className={className}
|
|
132
|
+
>
|
|
133
|
+
<path d="M22 12h-6l-2 3h-4l-2-3H2" />
|
|
134
|
+
<path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
|
|
135
|
+
</svg>
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* File icon
|
|
140
|
+
*/
|
|
141
|
+
export const FileIcon: React.FC<IconProps> = ({
|
|
142
|
+
size = defaultSize,
|
|
143
|
+
color = defaultColor,
|
|
144
|
+
className,
|
|
145
|
+
}) => (
|
|
146
|
+
<svg
|
|
147
|
+
width={size}
|
|
148
|
+
height={size}
|
|
149
|
+
viewBox="0 0 24 24"
|
|
150
|
+
fill="none"
|
|
151
|
+
stroke={color}
|
|
152
|
+
strokeWidth="2"
|
|
153
|
+
strokeLinecap="round"
|
|
154
|
+
strokeLinejoin="round"
|
|
155
|
+
className={className}
|
|
156
|
+
>
|
|
157
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
158
|
+
<polyline points="14,2 14,8 20,8" />
|
|
159
|
+
</svg>
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Hash/Fingerprint icon for file hashes
|
|
164
|
+
*/
|
|
165
|
+
export const HashIcon: React.FC<IconProps> = ({
|
|
166
|
+
size = defaultSize,
|
|
167
|
+
color = defaultColor,
|
|
168
|
+
className,
|
|
169
|
+
}) => (
|
|
170
|
+
<svg
|
|
171
|
+
width={size}
|
|
172
|
+
height={size}
|
|
173
|
+
viewBox="0 0 24 24"
|
|
174
|
+
fill="none"
|
|
175
|
+
stroke={color}
|
|
176
|
+
strokeWidth="2"
|
|
177
|
+
strokeLinecap="round"
|
|
178
|
+
strokeLinejoin="round"
|
|
179
|
+
className={className}
|
|
180
|
+
>
|
|
181
|
+
<line x1="4" y1="9" x2="20" y2="9" />
|
|
182
|
+
<line x1="4" y1="15" x2="20" y2="15" />
|
|
183
|
+
<line x1="10" y1="3" x2="8" y2="21" />
|
|
184
|
+
<line x1="16" y1="3" x2="14" y2="21" />
|
|
185
|
+
</svg>
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* User icon
|
|
190
|
+
*/
|
|
191
|
+
export const UserIcon: React.FC<IconProps> = ({
|
|
192
|
+
size = defaultSize,
|
|
193
|
+
color = defaultColor,
|
|
194
|
+
className,
|
|
195
|
+
}) => (
|
|
196
|
+
<svg
|
|
197
|
+
width={size}
|
|
198
|
+
height={size}
|
|
199
|
+
viewBox="0 0 24 24"
|
|
200
|
+
fill="none"
|
|
201
|
+
stroke={color}
|
|
202
|
+
strokeWidth="2"
|
|
203
|
+
strokeLinecap="round"
|
|
204
|
+
strokeLinejoin="round"
|
|
205
|
+
className={className}
|
|
206
|
+
>
|
|
207
|
+
<circle cx="12" cy="8" r="5" />
|
|
208
|
+
<path d="M20 21a8 8 0 1 0-16 0" />
|
|
209
|
+
</svg>
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* ID Card icon for identity
|
|
214
|
+
*/
|
|
215
|
+
export const IdCardIcon: React.FC<IconProps> = ({
|
|
216
|
+
size = defaultSize,
|
|
217
|
+
color = defaultColor,
|
|
218
|
+
className,
|
|
219
|
+
}) => (
|
|
220
|
+
<svg
|
|
221
|
+
width={size}
|
|
222
|
+
height={size}
|
|
223
|
+
viewBox="0 0 24 24"
|
|
224
|
+
fill="none"
|
|
225
|
+
stroke={color}
|
|
226
|
+
strokeWidth="2"
|
|
227
|
+
strokeLinecap="round"
|
|
228
|
+
strokeLinejoin="round"
|
|
229
|
+
className={className}
|
|
230
|
+
>
|
|
231
|
+
<rect x="2" y="5" width="20" height="14" rx="2" />
|
|
232
|
+
<circle cx="8" cy="12" r="2" />
|
|
233
|
+
<path d="M14 10h4" />
|
|
234
|
+
<path d="M14 14h4" />
|
|
235
|
+
</svg>
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Gear/Cog icon for processes
|
|
240
|
+
*/
|
|
241
|
+
export const GearIcon: React.FC<IconProps> = ({
|
|
242
|
+
size = defaultSize,
|
|
243
|
+
color = defaultColor,
|
|
244
|
+
className,
|
|
245
|
+
}) => (
|
|
246
|
+
<svg
|
|
247
|
+
width={size}
|
|
248
|
+
height={size}
|
|
249
|
+
viewBox="0 0 24 24"
|
|
250
|
+
fill="none"
|
|
251
|
+
stroke={color}
|
|
252
|
+
strokeWidth="2"
|
|
253
|
+
strokeLinecap="round"
|
|
254
|
+
strokeLinejoin="round"
|
|
255
|
+
className={className}
|
|
256
|
+
>
|
|
257
|
+
<circle cx="12" cy="12" r="3" />
|
|
258
|
+
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
259
|
+
</svg>
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Software/App icon
|
|
264
|
+
*/
|
|
265
|
+
export const AppIcon: React.FC<IconProps> = ({
|
|
266
|
+
size = defaultSize,
|
|
267
|
+
color = defaultColor,
|
|
268
|
+
className,
|
|
269
|
+
}) => (
|
|
270
|
+
<svg
|
|
271
|
+
width={size}
|
|
272
|
+
height={size}
|
|
273
|
+
viewBox="0 0 24 24"
|
|
274
|
+
fill="none"
|
|
275
|
+
stroke={color}
|
|
276
|
+
strokeWidth="2"
|
|
277
|
+
strokeLinecap="round"
|
|
278
|
+
strokeLinejoin="round"
|
|
279
|
+
className={className}
|
|
280
|
+
>
|
|
281
|
+
<rect x="3" y="3" width="18" height="18" rx="2" />
|
|
282
|
+
<path d="M9 3v18" />
|
|
283
|
+
<path d="M3 9h18" />
|
|
284
|
+
</svg>
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Registry key icon
|
|
289
|
+
*/
|
|
290
|
+
export const RegistryIcon: React.FC<IconProps> = ({
|
|
291
|
+
size = defaultSize,
|
|
292
|
+
color = defaultColor,
|
|
293
|
+
className,
|
|
294
|
+
}) => (
|
|
295
|
+
<svg
|
|
296
|
+
width={size}
|
|
297
|
+
height={size}
|
|
298
|
+
viewBox="0 0 24 24"
|
|
299
|
+
fill="none"
|
|
300
|
+
stroke={color}
|
|
301
|
+
strokeWidth="2"
|
|
302
|
+
strokeLinecap="round"
|
|
303
|
+
strokeLinejoin="round"
|
|
304
|
+
className={className}
|
|
305
|
+
>
|
|
306
|
+
<path d="m21 2-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4" />
|
|
307
|
+
</svg>
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Skull icon for threat actors
|
|
312
|
+
*/
|
|
313
|
+
export const ThreatActorIcon: React.FC<IconProps> = ({
|
|
314
|
+
size = defaultSize,
|
|
315
|
+
color = defaultColor,
|
|
316
|
+
className,
|
|
317
|
+
}) => (
|
|
318
|
+
<svg
|
|
319
|
+
width={size}
|
|
320
|
+
height={size}
|
|
321
|
+
viewBox="0 0 24 24"
|
|
322
|
+
fill="none"
|
|
323
|
+
stroke={color}
|
|
324
|
+
strokeWidth="2"
|
|
325
|
+
strokeLinecap="round"
|
|
326
|
+
strokeLinejoin="round"
|
|
327
|
+
className={className}
|
|
328
|
+
>
|
|
329
|
+
<circle cx="12" cy="10" r="7" />
|
|
330
|
+
<circle cx="9" cy="9" r="1.5" fill={color} />
|
|
331
|
+
<circle cx="15" cy="9" r="1.5" fill={color} />
|
|
332
|
+
<path d="M9 17v-2" />
|
|
333
|
+
<path d="M12 17v-2" />
|
|
334
|
+
<path d="M15 17v-2" />
|
|
335
|
+
</svg>
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Bug icon for malware
|
|
340
|
+
*/
|
|
341
|
+
export const BugIcon: React.FC<IconProps> = ({
|
|
342
|
+
size = defaultSize,
|
|
343
|
+
color = defaultColor,
|
|
344
|
+
className,
|
|
345
|
+
}) => (
|
|
346
|
+
<svg
|
|
347
|
+
width={size}
|
|
348
|
+
height={size}
|
|
349
|
+
viewBox="0 0 24 24"
|
|
350
|
+
fill="none"
|
|
351
|
+
stroke={color}
|
|
352
|
+
strokeWidth="2"
|
|
353
|
+
strokeLinecap="round"
|
|
354
|
+
strokeLinejoin="round"
|
|
355
|
+
className={className}
|
|
356
|
+
>
|
|
357
|
+
<path d="m8 2 1.88 1.88" />
|
|
358
|
+
<path d="M14.12 3.88 16 2" />
|
|
359
|
+
<path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" />
|
|
360
|
+
<path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" />
|
|
361
|
+
<path d="M12 20v-9" />
|
|
362
|
+
<path d="M6.53 9C4.6 8.8 3 7.1 3 5" />
|
|
363
|
+
<path d="M6 13H2" />
|
|
364
|
+
<path d="M3 21c0-2.1 1.7-3.9 3.8-4" />
|
|
365
|
+
<path d="M20.97 5c0 2.1-1.6 3.8-3.5 4" />
|
|
366
|
+
<path d="M22 13h-4" />
|
|
367
|
+
<path d="M17.2 17c2.1.1 3.8 1.9 3.8 4" />
|
|
368
|
+
</svg>
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Sword icon for attack patterns
|
|
373
|
+
*/
|
|
374
|
+
export const SwordIcon: React.FC<IconProps> = ({
|
|
375
|
+
size = defaultSize,
|
|
376
|
+
color = defaultColor,
|
|
377
|
+
className,
|
|
378
|
+
}) => (
|
|
379
|
+
<svg
|
|
380
|
+
width={size}
|
|
381
|
+
height={size}
|
|
382
|
+
viewBox="0 0 24 24"
|
|
383
|
+
fill="none"
|
|
384
|
+
stroke={color}
|
|
385
|
+
strokeWidth="2"
|
|
386
|
+
strokeLinecap="round"
|
|
387
|
+
strokeLinejoin="round"
|
|
388
|
+
className={className}
|
|
389
|
+
>
|
|
390
|
+
<polyline points="14.5,17.5 3,6 3,3 6,3 17.5,14.5" />
|
|
391
|
+
<line x1="13" y1="19" x2="19" y2="13" />
|
|
392
|
+
<line x1="16" y1="16" x2="20" y2="20" />
|
|
393
|
+
<line x1="19" y1="21" x2="21" y2="19" />
|
|
394
|
+
</svg>
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Target icon for campaigns
|
|
399
|
+
*/
|
|
400
|
+
export const TargetIcon: React.FC<IconProps> = ({
|
|
401
|
+
size = defaultSize,
|
|
402
|
+
color = defaultColor,
|
|
403
|
+
className,
|
|
404
|
+
}) => (
|
|
405
|
+
<svg
|
|
406
|
+
width={size}
|
|
407
|
+
height={size}
|
|
408
|
+
viewBox="0 0 24 24"
|
|
409
|
+
fill="none"
|
|
410
|
+
stroke={color}
|
|
411
|
+
strokeWidth="2"
|
|
412
|
+
strokeLinecap="round"
|
|
413
|
+
strokeLinejoin="round"
|
|
414
|
+
className={className}
|
|
415
|
+
>
|
|
416
|
+
<circle cx="12" cy="12" r="10" />
|
|
417
|
+
<circle cx="12" cy="12" r="6" />
|
|
418
|
+
<circle cx="12" cy="12" r="2" />
|
|
419
|
+
</svg>
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Alert icon for indicators
|
|
424
|
+
*/
|
|
425
|
+
export const AlertIcon: React.FC<IconProps> = ({
|
|
426
|
+
size = defaultSize,
|
|
427
|
+
color = defaultColor,
|
|
428
|
+
className,
|
|
429
|
+
}) => (
|
|
430
|
+
<svg
|
|
431
|
+
width={size}
|
|
432
|
+
height={size}
|
|
433
|
+
viewBox="0 0 24 24"
|
|
434
|
+
fill="none"
|
|
435
|
+
stroke={color}
|
|
436
|
+
strokeWidth="2"
|
|
437
|
+
strokeLinecap="round"
|
|
438
|
+
strokeLinejoin="round"
|
|
439
|
+
className={className}
|
|
440
|
+
>
|
|
441
|
+
<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
|
442
|
+
<line x1="12" y1="9" x2="12" y2="13" />
|
|
443
|
+
<line x1="12" y1="17" x2="12.01" y2="17" />
|
|
444
|
+
</svg>
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Flask icon for artifacts
|
|
449
|
+
*/
|
|
450
|
+
export const FlaskIcon: React.FC<IconProps> = ({
|
|
451
|
+
size = defaultSize,
|
|
452
|
+
color = defaultColor,
|
|
453
|
+
className,
|
|
454
|
+
}) => (
|
|
455
|
+
<svg
|
|
456
|
+
width={size}
|
|
457
|
+
height={size}
|
|
458
|
+
viewBox="0 0 24 24"
|
|
459
|
+
fill="none"
|
|
460
|
+
stroke={color}
|
|
461
|
+
strokeWidth="2"
|
|
462
|
+
strokeLinecap="round"
|
|
463
|
+
strokeLinejoin="round"
|
|
464
|
+
className={className}
|
|
465
|
+
>
|
|
466
|
+
<path d="M10 2v7.527a2 2 0 0 1-.211.896L4.72 20.55a1 1 0 0 0 .9 1.45h12.76a1 1 0 0 0 .9-1.45l-5.069-10.127A2 2 0 0 1 14 9.527V2" />
|
|
467
|
+
<path d="M8.5 2h7" />
|
|
468
|
+
<path d="M7 16h10" />
|
|
469
|
+
</svg>
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Certificate icon
|
|
474
|
+
*/
|
|
475
|
+
export const CertificateIcon: React.FC<IconProps> = ({
|
|
476
|
+
size = defaultSize,
|
|
477
|
+
color = defaultColor,
|
|
478
|
+
className,
|
|
479
|
+
}) => (
|
|
480
|
+
<svg
|
|
481
|
+
width={size}
|
|
482
|
+
height={size}
|
|
483
|
+
viewBox="0 0 24 24"
|
|
484
|
+
fill="none"
|
|
485
|
+
stroke={color}
|
|
486
|
+
strokeWidth="2"
|
|
487
|
+
strokeLinecap="round"
|
|
488
|
+
strokeLinejoin="round"
|
|
489
|
+
className={className}
|
|
490
|
+
>
|
|
491
|
+
<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" />
|
|
492
|
+
<path d="M2 6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6Z" />
|
|
493
|
+
<path d="m9.5 15.5-3 3v3l3.5-1.5 3.5 1.5v-3l-3-3" />
|
|
494
|
+
</svg>
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* MAC address/Wifi icon
|
|
499
|
+
*/
|
|
500
|
+
export const WifiIcon: React.FC<IconProps> = ({
|
|
501
|
+
size = defaultSize,
|
|
502
|
+
color = defaultColor,
|
|
503
|
+
className,
|
|
504
|
+
}) => (
|
|
505
|
+
<svg
|
|
506
|
+
width={size}
|
|
507
|
+
height={size}
|
|
508
|
+
viewBox="0 0 24 24"
|
|
509
|
+
fill="none"
|
|
510
|
+
stroke={color}
|
|
511
|
+
strokeWidth="2"
|
|
512
|
+
strokeLinecap="round"
|
|
513
|
+
strokeLinejoin="round"
|
|
514
|
+
className={className}
|
|
515
|
+
>
|
|
516
|
+
<path d="M5 12.55a11 11 0 0 1 14.08 0" />
|
|
517
|
+
<path d="M1.42 9a16 16 0 0 1 21.16 0" />
|
|
518
|
+
<path d="M8.53 16.11a6 6 0 0 1 6.95 0" />
|
|
519
|
+
<line x1="12" y1="20" x2="12.01" y2="20" />
|
|
520
|
+
</svg>
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Autonomous System/World icon
|
|
525
|
+
*/
|
|
526
|
+
export const WorldIcon: React.FC<IconProps> = ({
|
|
527
|
+
size = defaultSize,
|
|
528
|
+
color = defaultColor,
|
|
529
|
+
className,
|
|
530
|
+
}) => (
|
|
531
|
+
<svg
|
|
532
|
+
width={size}
|
|
533
|
+
height={size}
|
|
534
|
+
viewBox="0 0 24 24"
|
|
535
|
+
fill="none"
|
|
536
|
+
stroke={color}
|
|
537
|
+
strokeWidth="2"
|
|
538
|
+
strokeLinecap="round"
|
|
539
|
+
strokeLinejoin="round"
|
|
540
|
+
className={className}
|
|
541
|
+
>
|
|
542
|
+
<circle cx="12" cy="12" r="10" />
|
|
543
|
+
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
|
|
544
|
+
<path d="M2 12h20" />
|
|
545
|
+
</svg>
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Question mark icon for unknown types
|
|
550
|
+
*/
|
|
551
|
+
export const QuestionIcon: React.FC<IconProps> = ({
|
|
552
|
+
size = defaultSize,
|
|
553
|
+
color = defaultColor,
|
|
554
|
+
className,
|
|
555
|
+
}) => (
|
|
556
|
+
<svg
|
|
557
|
+
width={size}
|
|
558
|
+
height={size}
|
|
559
|
+
viewBox="0 0 24 24"
|
|
560
|
+
fill="none"
|
|
561
|
+
stroke={color}
|
|
562
|
+
strokeWidth="2"
|
|
563
|
+
strokeLinecap="round"
|
|
564
|
+
strokeLinejoin="round"
|
|
565
|
+
className={className}
|
|
566
|
+
>
|
|
567
|
+
<circle cx="12" cy="12" r="10" />
|
|
568
|
+
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
|
|
569
|
+
<path d="M12 17h.01" />
|
|
570
|
+
</svg>
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Checkmark icon for checks
|
|
575
|
+
*/
|
|
576
|
+
export const CheckIcon: React.FC<IconProps> = ({
|
|
577
|
+
size = defaultSize,
|
|
578
|
+
color = defaultColor,
|
|
579
|
+
className,
|
|
580
|
+
}) => (
|
|
581
|
+
<svg
|
|
582
|
+
width={size}
|
|
583
|
+
height={size}
|
|
584
|
+
viewBox="0 0 24 24"
|
|
585
|
+
fill="none"
|
|
586
|
+
stroke={color}
|
|
587
|
+
strokeWidth="2"
|
|
588
|
+
strokeLinecap="round"
|
|
589
|
+
strokeLinejoin="round"
|
|
590
|
+
className={className}
|
|
591
|
+
>
|
|
592
|
+
<path d="M20 6 9 17l-5-5" />
|
|
593
|
+
</svg>
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Box icon for containers
|
|
598
|
+
*/
|
|
599
|
+
export const BoxIcon: React.FC<IconProps> = ({
|
|
600
|
+
size = defaultSize,
|
|
601
|
+
color = defaultColor,
|
|
602
|
+
className,
|
|
603
|
+
}) => (
|
|
604
|
+
<svg
|
|
605
|
+
width={size}
|
|
606
|
+
height={size}
|
|
607
|
+
viewBox="0 0 24 24"
|
|
608
|
+
fill="none"
|
|
609
|
+
stroke={color}
|
|
610
|
+
strokeWidth="2"
|
|
611
|
+
strokeLinecap="round"
|
|
612
|
+
strokeLinejoin="round"
|
|
613
|
+
className={className}
|
|
614
|
+
>
|
|
615
|
+
<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
|
|
616
|
+
<path d="m3.3 7 8.7 5 8.7-5" />
|
|
617
|
+
<path d="M12 22V12" />
|
|
618
|
+
</svg>
|
|
619
|
+
);
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Crosshair icon for root/target
|
|
623
|
+
*/
|
|
624
|
+
export const CrosshairIcon: React.FC<IconProps> = ({
|
|
625
|
+
size = defaultSize,
|
|
626
|
+
color = defaultColor,
|
|
627
|
+
className,
|
|
628
|
+
}) => (
|
|
629
|
+
<svg
|
|
630
|
+
width={size}
|
|
631
|
+
height={size}
|
|
632
|
+
viewBox="0 0 24 24"
|
|
633
|
+
fill="none"
|
|
634
|
+
stroke={color}
|
|
635
|
+
strokeWidth="2"
|
|
636
|
+
strokeLinecap="round"
|
|
637
|
+
strokeLinejoin="round"
|
|
638
|
+
className={className}
|
|
639
|
+
>
|
|
640
|
+
<circle cx="12" cy="12" r="10" />
|
|
641
|
+
<line x1="22" y1="12" x2="18" y2="12" />
|
|
642
|
+
<line x1="6" y1="12" x2="2" y2="12" />
|
|
643
|
+
<line x1="12" y1="6" x2="12" y2="2" />
|
|
644
|
+
<line x1="12" y1="22" x2="12" y2="18" />
|
|
645
|
+
</svg>
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Map observable types to icon components
|
|
650
|
+
*/
|
|
651
|
+
export const OBSERVABLE_ICON_MAP: Record<
|
|
652
|
+
string,
|
|
653
|
+
React.FC<IconProps>
|
|
654
|
+
> = {
|
|
655
|
+
// Network
|
|
656
|
+
"ipv4-addr": GlobeIcon,
|
|
657
|
+
"ipv6-addr": GlobeIcon,
|
|
658
|
+
"domain-name": DomainIcon,
|
|
659
|
+
url: LinkIcon,
|
|
660
|
+
"autonomous-system": WorldIcon,
|
|
661
|
+
"mac-addr": WifiIcon,
|
|
662
|
+
|
|
663
|
+
// Email
|
|
664
|
+
"email-addr": MailIcon,
|
|
665
|
+
"email-message": EnvelopeIcon,
|
|
666
|
+
|
|
667
|
+
// File
|
|
668
|
+
file: FileIcon,
|
|
669
|
+
"file-hash": HashIcon,
|
|
670
|
+
"file:hash:md5": HashIcon,
|
|
671
|
+
"file:hash:sha1": HashIcon,
|
|
672
|
+
"file:hash:sha256": HashIcon,
|
|
673
|
+
|
|
674
|
+
// User/Identity
|
|
675
|
+
user: UserIcon,
|
|
676
|
+
"user-account": UserIcon,
|
|
677
|
+
identity: IdCardIcon,
|
|
678
|
+
|
|
679
|
+
// Process/System
|
|
680
|
+
process: GearIcon,
|
|
681
|
+
software: AppIcon,
|
|
682
|
+
"windows-registry-key": RegistryIcon,
|
|
683
|
+
|
|
684
|
+
// Threat Intelligence
|
|
685
|
+
"threat-actor": ThreatActorIcon,
|
|
686
|
+
malware: BugIcon,
|
|
687
|
+
"attack-pattern": SwordIcon,
|
|
688
|
+
campaign: TargetIcon,
|
|
689
|
+
indicator: AlertIcon,
|
|
690
|
+
|
|
691
|
+
// Artifacts
|
|
692
|
+
artifact: FlaskIcon,
|
|
693
|
+
certificate: CertificateIcon,
|
|
694
|
+
"x509-certificate": CertificateIcon,
|
|
695
|
+
|
|
696
|
+
// Default
|
|
697
|
+
unknown: QuestionIcon,
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Map investigation node types to icons
|
|
702
|
+
*/
|
|
703
|
+
export const INVESTIGATION_ICON_MAP: Record<
|
|
704
|
+
string,
|
|
705
|
+
React.FC<IconProps>
|
|
706
|
+
> = {
|
|
707
|
+
root: CrosshairIcon,
|
|
708
|
+
check: CheckIcon,
|
|
709
|
+
container: BoxIcon,
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Get the icon component for an observable type.
|
|
714
|
+
*/
|
|
715
|
+
export function getObservableIcon(
|
|
716
|
+
observableType: string
|
|
717
|
+
): React.FC<IconProps> {
|
|
718
|
+
const normalized = observableType.toLowerCase().trim();
|
|
719
|
+
return OBSERVABLE_ICON_MAP[normalized] ?? OBSERVABLE_ICON_MAP.unknown;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Get the icon component for an investigation node type.
|
|
724
|
+
*/
|
|
725
|
+
export function getInvestigationIcon(
|
|
726
|
+
nodeType: string
|
|
727
|
+
): React.FC<IconProps> {
|
|
728
|
+
return INVESTIGATION_ICON_MAP[nodeType] ?? QuestionIcon;
|
|
729
|
+
}
|
|
730
|
+
|