@cyvest/cyvest-js 5.4.1 → 6.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 +1 -1
- package/dist/index.cjs +558 -196
- package/dist/index.d.cts +181 -107
- package/dist/index.d.ts +181 -107
- package/dist/index.js +539 -179
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -36,30 +36,30 @@ __export(index_exports, {
|
|
|
36
36
|
areConnected: () => areConnected,
|
|
37
37
|
compareLevels: () => compareLevels,
|
|
38
38
|
countRelationshipsByType: () => countRelationshipsByType,
|
|
39
|
-
findCheckByName: () => findCheckByName,
|
|
40
|
-
findChecksAtLeast: () => findChecksAtLeast,
|
|
41
|
-
findChecksByLevel: () => findChecksByLevel,
|
|
42
|
-
findChecksForObservable: () => findChecksForObservable,
|
|
43
|
-
findChecksForTag: () => findChecksForTag,
|
|
44
39
|
findExternalObservables: () => findExternalObservables,
|
|
45
|
-
|
|
40
|
+
findFindingByName: () => findFindingByName,
|
|
41
|
+
findFindingsAtLeast: () => findFindingsAtLeast,
|
|
42
|
+
findFindingsByLevel: () => findFindingsByLevel,
|
|
43
|
+
findFindingsForObservable: () => findFindingsForObservable,
|
|
44
|
+
findFindingsForTag: () => findFindingsForTag,
|
|
45
|
+
findHighestScoringFindings: () => findHighestScoringFindings,
|
|
46
46
|
findHighestScoringObservables: () => findHighestScoringObservables,
|
|
47
47
|
findInternalObservables: () => findInternalObservables,
|
|
48
48
|
findLeafObservables: () => findLeafObservables,
|
|
49
|
-
|
|
49
|
+
findMaliciousFindings: () => findMaliciousFindings,
|
|
50
50
|
findMaliciousObservables: () => findMaliciousObservables,
|
|
51
51
|
findObservablesAtLeast: () => findObservablesAtLeast,
|
|
52
52
|
findObservablesByLevel: () => findObservablesByLevel,
|
|
53
53
|
findObservablesByType: () => findObservablesByType,
|
|
54
54
|
findObservablesByValue: () => findObservablesByValue,
|
|
55
55
|
findObservablesContaining: () => findObservablesContaining,
|
|
56
|
-
|
|
56
|
+
findObservablesForFinding: () => findObservablesForFinding,
|
|
57
57
|
findObservablesMatching: () => findObservablesMatching,
|
|
58
58
|
findObservablesWithThreatIntel: () => findObservablesWithThreatIntel,
|
|
59
59
|
findOrphanObservables: () => findOrphanObservables,
|
|
60
60
|
findPath: () => findPath,
|
|
61
61
|
findSourceObservables: () => findSourceObservables,
|
|
62
|
-
|
|
62
|
+
findSuspiciousFindings: () => findSuspiciousFindings,
|
|
63
63
|
findSuspiciousObservables: () => findSuspiciousObservables,
|
|
64
64
|
findTagsAtLeast: () => findTagsAtLeast,
|
|
65
65
|
findTagsByLevel: () => findTagsByLevel,
|
|
@@ -69,22 +69,21 @@ __export(index_exports, {
|
|
|
69
69
|
findThreatIntelBySource: () => findThreatIntelBySource,
|
|
70
70
|
findThreatIntelsForObservable: () => findThreatIntelsForObservable,
|
|
71
71
|
findWhitelistedObservables: () => findWhitelistedObservables,
|
|
72
|
-
generateCheckKey: () => generateCheckKey,
|
|
73
72
|
generateEnrichmentKey: () => generateEnrichmentKey,
|
|
73
|
+
generateFindingKey: () => generateFindingKey,
|
|
74
74
|
generateObservableKey: () => generateObservableKey,
|
|
75
75
|
generateTagKey: () => generateTagKey,
|
|
76
76
|
generateThreatIntelKey: () => generateThreatIntelKey,
|
|
77
|
-
getAllCheckKeys: () => getAllCheckKeys,
|
|
78
|
-
getAllChecks: () => getAllChecks,
|
|
79
77
|
getAllEnrichments: () => getAllEnrichments,
|
|
78
|
+
getAllEvidences: () => getAllEvidences,
|
|
79
|
+
getAllFindingKeys: () => getAllFindingKeys,
|
|
80
|
+
getAllFindings: () => getAllFindings,
|
|
80
81
|
getAllObservableTypes: () => getAllObservableTypes,
|
|
81
82
|
getAllObservables: () => getAllObservables,
|
|
82
83
|
getAllRelationshipTypes: () => getAllRelationshipTypes,
|
|
83
84
|
getAllTags: () => getAllTags,
|
|
84
85
|
getAllThreatIntelSources: () => getAllThreatIntelSources,
|
|
85
86
|
getAllThreatIntels: () => getAllThreatIntels,
|
|
86
|
-
getCheck: () => getCheck,
|
|
87
|
-
getCheckByName: () => getCheckByName,
|
|
88
87
|
getColorForLevel: () => getColorForLevel,
|
|
89
88
|
getColorForScore: () => getColorForScore,
|
|
90
89
|
getCounts: () => getCounts,
|
|
@@ -92,6 +91,9 @@ __export(index_exports, {
|
|
|
92
91
|
getEnrichment: () => getEnrichment,
|
|
93
92
|
getEnrichmentByName: () => getEnrichmentByName,
|
|
94
93
|
getEntityLevel: () => getEntityLevel,
|
|
94
|
+
getEvidence: () => getEvidence,
|
|
95
|
+
getFinding: () => getFinding,
|
|
96
|
+
getFindingByName: () => getFindingByName,
|
|
95
97
|
getLevelFromScore: () => getLevelFromScore,
|
|
96
98
|
getObservable: () => getObservable,
|
|
97
99
|
getObservableByTypeValue: () => getObservableByTypeValue,
|
|
@@ -127,13 +129,13 @@ __export(index_exports, {
|
|
|
127
129
|
maxLevel: () => maxLevel,
|
|
128
130
|
minLevel: () => minLevel,
|
|
129
131
|
normalizeLevel: () => normalizeLevel,
|
|
130
|
-
parseCheckKey: () => parseCheckKey,
|
|
131
132
|
parseCyvest: () => parseCyvest,
|
|
133
|
+
parseFindingKey: () => parseFindingKey,
|
|
132
134
|
parseKeyType: () => parseKeyType,
|
|
133
135
|
parseObservableKey: () => parseObservableKey,
|
|
134
136
|
parseThreatIntelKey: () => parseThreatIntelKey,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
sortFindingsByLevel: () => sortFindingsByLevel,
|
|
138
|
+
sortFindingsByScore: () => sortFindingsByScore,
|
|
137
139
|
sortObservablesByLevel: () => sortObservablesByLevel,
|
|
138
140
|
sortObservablesByScore: () => sortObservablesByScore,
|
|
139
141
|
validateKey: () => validateKey
|
|
@@ -238,69 +240,6 @@ var cyvest_schema_default = {
|
|
|
238
240
|
title: "AuditEvent",
|
|
239
241
|
type: "object"
|
|
240
242
|
},
|
|
241
|
-
Check: {
|
|
242
|
-
description: "Represents a verification step in the investigation.\n\nA check validates a specific aspect of the data under investigation\nand contributes to the overall investigation score.",
|
|
243
|
-
properties: {
|
|
244
|
-
check_name: {
|
|
245
|
-
title: "Check Name",
|
|
246
|
-
type: "string"
|
|
247
|
-
},
|
|
248
|
-
description: {
|
|
249
|
-
title: "Description",
|
|
250
|
-
type: "string"
|
|
251
|
-
},
|
|
252
|
-
comment: {
|
|
253
|
-
title: "Comment",
|
|
254
|
-
type: "string"
|
|
255
|
-
},
|
|
256
|
-
extra: {
|
|
257
|
-
additionalProperties: true,
|
|
258
|
-
title: "Extra",
|
|
259
|
-
type: "object"
|
|
260
|
-
},
|
|
261
|
-
score: {
|
|
262
|
-
title: "Score",
|
|
263
|
-
type: "number"
|
|
264
|
-
},
|
|
265
|
-
level: {
|
|
266
|
-
$ref: "#/$defs/Level"
|
|
267
|
-
},
|
|
268
|
-
origin_investigation_id: {
|
|
269
|
-
title: "Origin Investigation Id",
|
|
270
|
-
type: "string"
|
|
271
|
-
},
|
|
272
|
-
observable_links: {
|
|
273
|
-
items: {
|
|
274
|
-
$ref: "#/$defs/ObservableLink"
|
|
275
|
-
},
|
|
276
|
-
title: "Observable Links",
|
|
277
|
-
type: "array"
|
|
278
|
-
},
|
|
279
|
-
key: {
|
|
280
|
-
title: "Key",
|
|
281
|
-
type: "string"
|
|
282
|
-
},
|
|
283
|
-
score_display: {
|
|
284
|
-
readOnly: true,
|
|
285
|
-
title: "Score Display",
|
|
286
|
-
type: "string"
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
|
-
required: [
|
|
290
|
-
"check_name",
|
|
291
|
-
"description",
|
|
292
|
-
"comment",
|
|
293
|
-
"extra",
|
|
294
|
-
"score",
|
|
295
|
-
"level",
|
|
296
|
-
"origin_investigation_id",
|
|
297
|
-
"observable_links",
|
|
298
|
-
"key",
|
|
299
|
-
"score_display"
|
|
300
|
-
],
|
|
301
|
-
title: "Check",
|
|
302
|
-
type: "object"
|
|
303
|
-
},
|
|
304
243
|
DataExtractionSchema: {
|
|
305
244
|
additionalProperties: false,
|
|
306
245
|
description: "Schema for data extraction metadata.",
|
|
@@ -361,6 +300,182 @@ var cyvest_schema_default = {
|
|
|
361
300
|
title: "Enrichment",
|
|
362
301
|
type: "object"
|
|
363
302
|
},
|
|
303
|
+
Evidence: {
|
|
304
|
+
description: "Structured material supporting one or more findings.",
|
|
305
|
+
properties: {
|
|
306
|
+
type: {
|
|
307
|
+
title: "Type",
|
|
308
|
+
type: "string"
|
|
309
|
+
},
|
|
310
|
+
title: {
|
|
311
|
+
title: "Title",
|
|
312
|
+
type: "string"
|
|
313
|
+
},
|
|
314
|
+
description: {
|
|
315
|
+
title: "Description",
|
|
316
|
+
type: "string"
|
|
317
|
+
},
|
|
318
|
+
source: {
|
|
319
|
+
title: "Source",
|
|
320
|
+
type: "string"
|
|
321
|
+
},
|
|
322
|
+
external_id: {
|
|
323
|
+
anyOf: [
|
|
324
|
+
{
|
|
325
|
+
type: "string"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
type: "null"
|
|
329
|
+
}
|
|
330
|
+
],
|
|
331
|
+
title: "External Id"
|
|
332
|
+
},
|
|
333
|
+
content: {
|
|
334
|
+
anyOf: [
|
|
335
|
+
{},
|
|
336
|
+
{
|
|
337
|
+
type: "null"
|
|
338
|
+
}
|
|
339
|
+
],
|
|
340
|
+
title: "Content"
|
|
341
|
+
},
|
|
342
|
+
uri: {
|
|
343
|
+
anyOf: [
|
|
344
|
+
{
|
|
345
|
+
type: "string"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
type: "null"
|
|
349
|
+
}
|
|
350
|
+
],
|
|
351
|
+
title: "Uri"
|
|
352
|
+
},
|
|
353
|
+
captured_at: {
|
|
354
|
+
format: "date-time",
|
|
355
|
+
title: "Captured At",
|
|
356
|
+
type: "string"
|
|
357
|
+
},
|
|
358
|
+
extra: {
|
|
359
|
+
additionalProperties: true,
|
|
360
|
+
title: "Extra",
|
|
361
|
+
type: "object"
|
|
362
|
+
},
|
|
363
|
+
key: {
|
|
364
|
+
title: "Key",
|
|
365
|
+
type: "string"
|
|
366
|
+
},
|
|
367
|
+
finding_links: {
|
|
368
|
+
description: "Findings that currently link to this evidence (navigation-only).",
|
|
369
|
+
items: {
|
|
370
|
+
type: "string"
|
|
371
|
+
},
|
|
372
|
+
readOnly: true,
|
|
373
|
+
title: "Finding Links",
|
|
374
|
+
type: "array"
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
required: [
|
|
378
|
+
"type",
|
|
379
|
+
"title",
|
|
380
|
+
"description",
|
|
381
|
+
"source",
|
|
382
|
+
"external_id",
|
|
383
|
+
"content",
|
|
384
|
+
"uri",
|
|
385
|
+
"captured_at",
|
|
386
|
+
"extra",
|
|
387
|
+
"key",
|
|
388
|
+
"finding_links"
|
|
389
|
+
],
|
|
390
|
+
title: "Evidence",
|
|
391
|
+
type: "object"
|
|
392
|
+
},
|
|
393
|
+
EvidenceLink: {
|
|
394
|
+
additionalProperties: false,
|
|
395
|
+
description: "Edge metadata for a Finding\u2194Evidence association.",
|
|
396
|
+
properties: {
|
|
397
|
+
evidence_key: {
|
|
398
|
+
title: "Evidence Key",
|
|
399
|
+
type: "string"
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
required: [
|
|
403
|
+
"evidence_key"
|
|
404
|
+
],
|
|
405
|
+
title: "EvidenceLink",
|
|
406
|
+
type: "object"
|
|
407
|
+
},
|
|
408
|
+
Finding: {
|
|
409
|
+
description: "Represents a verification step in the investigation.\n\nA finding validates a specific aspect of the data under investigation\nand contributes to the overall investigation score.",
|
|
410
|
+
properties: {
|
|
411
|
+
finding_name: {
|
|
412
|
+
title: "Finding Name",
|
|
413
|
+
type: "string"
|
|
414
|
+
},
|
|
415
|
+
description: {
|
|
416
|
+
title: "Description",
|
|
417
|
+
type: "string"
|
|
418
|
+
},
|
|
419
|
+
comment: {
|
|
420
|
+
title: "Comment",
|
|
421
|
+
type: "string"
|
|
422
|
+
},
|
|
423
|
+
extra: {
|
|
424
|
+
additionalProperties: true,
|
|
425
|
+
title: "Extra",
|
|
426
|
+
type: "object"
|
|
427
|
+
},
|
|
428
|
+
score: {
|
|
429
|
+
title: "Score",
|
|
430
|
+
type: "number"
|
|
431
|
+
},
|
|
432
|
+
level: {
|
|
433
|
+
$ref: "#/$defs/Level"
|
|
434
|
+
},
|
|
435
|
+
origin_investigation_id: {
|
|
436
|
+
title: "Origin Investigation Id",
|
|
437
|
+
type: "string"
|
|
438
|
+
},
|
|
439
|
+
observable_links: {
|
|
440
|
+
items: {
|
|
441
|
+
$ref: "#/$defs/ObservableLink"
|
|
442
|
+
},
|
|
443
|
+
title: "Observable Links",
|
|
444
|
+
type: "array"
|
|
445
|
+
},
|
|
446
|
+
evidence_links: {
|
|
447
|
+
items: {
|
|
448
|
+
$ref: "#/$defs/EvidenceLink"
|
|
449
|
+
},
|
|
450
|
+
title: "Evidence Links",
|
|
451
|
+
type: "array"
|
|
452
|
+
},
|
|
453
|
+
key: {
|
|
454
|
+
title: "Key",
|
|
455
|
+
type: "string"
|
|
456
|
+
},
|
|
457
|
+
score_display: {
|
|
458
|
+
readOnly: true,
|
|
459
|
+
title: "Score Display",
|
|
460
|
+
type: "string"
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
required: [
|
|
464
|
+
"finding_name",
|
|
465
|
+
"description",
|
|
466
|
+
"comment",
|
|
467
|
+
"extra",
|
|
468
|
+
"score",
|
|
469
|
+
"level",
|
|
470
|
+
"origin_investigation_id",
|
|
471
|
+
"observable_links",
|
|
472
|
+
"evidence_links",
|
|
473
|
+
"key",
|
|
474
|
+
"score_display"
|
|
475
|
+
],
|
|
476
|
+
title: "Finding",
|
|
477
|
+
type: "object"
|
|
478
|
+
},
|
|
364
479
|
InvestigationWhitelist: {
|
|
365
480
|
description: "Represents a whitelist entry on an investigation.",
|
|
366
481
|
properties: {
|
|
@@ -395,7 +510,7 @@ var cyvest_schema_default = {
|
|
|
395
510
|
type: "object"
|
|
396
511
|
},
|
|
397
512
|
Level: {
|
|
398
|
-
description: "Security level classification for
|
|
513
|
+
description: "Security level classification for findings, observables, and threat intelligence.\n\nLevels are ordered from lowest (NONE) to highest (MALICIOUS) severity.",
|
|
399
514
|
enum: [
|
|
400
515
|
"NONE",
|
|
401
516
|
"TRUSTED",
|
|
@@ -409,12 +524,35 @@ var cyvest_schema_default = {
|
|
|
409
524
|
type: "string"
|
|
410
525
|
},
|
|
411
526
|
Observable: {
|
|
412
|
-
description: "Represents a cyber observable (IP, URL, domain, hash, etc.).\n\nObservables can be linked to threat intelligence,
|
|
527
|
+
description: "Represents a cyber observable (IP, URL, domain, hash, etc.).\n\nObservables can be linked to threat intelligence, findings, and other observables\nthrough relationships.",
|
|
413
528
|
properties: {
|
|
414
529
|
type: {
|
|
415
530
|
title: "Type",
|
|
416
531
|
type: "string"
|
|
417
532
|
},
|
|
533
|
+
subtype: {
|
|
534
|
+
anyOf: [
|
|
535
|
+
{
|
|
536
|
+
type: "string"
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
type: "null"
|
|
540
|
+
}
|
|
541
|
+
],
|
|
542
|
+
title: "Subtype"
|
|
543
|
+
},
|
|
544
|
+
namespace: {
|
|
545
|
+
anyOf: [
|
|
546
|
+
{
|
|
547
|
+
type: "string"
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
type: "null"
|
|
551
|
+
}
|
|
552
|
+
],
|
|
553
|
+
default: null,
|
|
554
|
+
title: "Namespace"
|
|
555
|
+
},
|
|
418
556
|
value: {
|
|
419
557
|
title: "Value",
|
|
420
558
|
type: "string"
|
|
@@ -443,6 +581,19 @@ var cyvest_schema_default = {
|
|
|
443
581
|
level: {
|
|
444
582
|
$ref: "#/$defs/Level"
|
|
445
583
|
},
|
|
584
|
+
aliases: {
|
|
585
|
+
items: {
|
|
586
|
+
$ref: "#/$defs/ObservableAlias"
|
|
587
|
+
},
|
|
588
|
+
title: "Aliases",
|
|
589
|
+
type: "array"
|
|
590
|
+
},
|
|
591
|
+
occurrence_count: {
|
|
592
|
+
default: 1,
|
|
593
|
+
minimum: 1,
|
|
594
|
+
title: "Occurrence Count",
|
|
595
|
+
type: "integer"
|
|
596
|
+
},
|
|
446
597
|
threat_intels: {
|
|
447
598
|
items: {
|
|
448
599
|
type: "string"
|
|
@@ -461,13 +612,13 @@ var cyvest_schema_default = {
|
|
|
461
612
|
title: "Key",
|
|
462
613
|
type: "string"
|
|
463
614
|
},
|
|
464
|
-
|
|
465
|
-
description: "
|
|
615
|
+
finding_links: {
|
|
616
|
+
description: "Findings that currently link to this observable (navigation-only).",
|
|
466
617
|
items: {
|
|
467
618
|
type: "string"
|
|
468
619
|
},
|
|
469
620
|
readOnly: true,
|
|
470
|
-
title: "
|
|
621
|
+
title: "Finding Links",
|
|
471
622
|
type: "array"
|
|
472
623
|
},
|
|
473
624
|
score_display: {
|
|
@@ -485,18 +636,67 @@ var cyvest_schema_default = {
|
|
|
485
636
|
"extra",
|
|
486
637
|
"score",
|
|
487
638
|
"level",
|
|
639
|
+
"aliases",
|
|
488
640
|
"threat_intels",
|
|
489
641
|
"relationships",
|
|
490
642
|
"key",
|
|
491
|
-
"
|
|
643
|
+
"finding_links",
|
|
492
644
|
"score_display"
|
|
493
645
|
],
|
|
494
646
|
title: "Observable",
|
|
495
647
|
type: "object"
|
|
496
648
|
},
|
|
649
|
+
ObservableAlias: {
|
|
650
|
+
description: "Source observable identity attached to a canonical observable.",
|
|
651
|
+
properties: {
|
|
652
|
+
type: {
|
|
653
|
+
title: "Type",
|
|
654
|
+
type: "string"
|
|
655
|
+
},
|
|
656
|
+
subtype: {
|
|
657
|
+
anyOf: [
|
|
658
|
+
{
|
|
659
|
+
type: "string"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
type: "null"
|
|
663
|
+
}
|
|
664
|
+
],
|
|
665
|
+
title: "Subtype"
|
|
666
|
+
},
|
|
667
|
+
namespace: {
|
|
668
|
+
anyOf: [
|
|
669
|
+
{
|
|
670
|
+
type: "string"
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
type: "null"
|
|
674
|
+
}
|
|
675
|
+
],
|
|
676
|
+
default: null,
|
|
677
|
+
title: "Namespace"
|
|
678
|
+
},
|
|
679
|
+
value: {
|
|
680
|
+
title: "Value",
|
|
681
|
+
type: "string"
|
|
682
|
+
},
|
|
683
|
+
count: {
|
|
684
|
+
default: 1,
|
|
685
|
+
minimum: 1,
|
|
686
|
+
title: "Count",
|
|
687
|
+
type: "integer"
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
required: [
|
|
691
|
+
"type",
|
|
692
|
+
"value"
|
|
693
|
+
],
|
|
694
|
+
title: "ObservableAlias",
|
|
695
|
+
type: "object"
|
|
696
|
+
},
|
|
497
697
|
ObservableLink: {
|
|
498
698
|
additionalProperties: false,
|
|
499
|
-
description: "Edge metadata for a
|
|
699
|
+
description: "Edge metadata for a Finding\u2194Observable association.",
|
|
500
700
|
properties: {
|
|
501
701
|
observable_key: {
|
|
502
702
|
title: "Observable Key",
|
|
@@ -514,7 +714,7 @@ var cyvest_schema_default = {
|
|
|
514
714
|
type: "object"
|
|
515
715
|
},
|
|
516
716
|
PropagationMode: {
|
|
517
|
-
description: "Controls how a
|
|
717
|
+
description: "Controls how a Finding\u2194Observable link propagates across merged investigations.",
|
|
518
718
|
enum: [
|
|
519
719
|
"LOCAL_ONLY",
|
|
520
720
|
"GLOBAL"
|
|
@@ -615,24 +815,45 @@ var cyvest_schema_default = {
|
|
|
615
815
|
title: "Observables By Type And Level",
|
|
616
816
|
type: "object"
|
|
617
817
|
},
|
|
618
|
-
|
|
818
|
+
total_findings: {
|
|
619
819
|
minimum: 0,
|
|
620
|
-
title: "Total
|
|
820
|
+
title: "Total Findings",
|
|
621
821
|
type: "integer"
|
|
622
822
|
},
|
|
623
|
-
|
|
823
|
+
applied_findings: {
|
|
624
824
|
minimum: 0,
|
|
625
|
-
title: "Applied
|
|
825
|
+
title: "Applied Findings",
|
|
626
826
|
type: "integer"
|
|
627
827
|
},
|
|
628
|
-
|
|
828
|
+
findings_by_level: {
|
|
629
829
|
additionalProperties: {
|
|
630
830
|
items: {
|
|
631
831
|
type: "string"
|
|
632
832
|
},
|
|
633
833
|
type: "array"
|
|
634
834
|
},
|
|
635
|
-
title: "
|
|
835
|
+
title: "Findings By Level",
|
|
836
|
+
type: "object"
|
|
837
|
+
},
|
|
838
|
+
total_evidences: {
|
|
839
|
+
minimum: 0,
|
|
840
|
+
title: "Total Evidences",
|
|
841
|
+
type: "integer"
|
|
842
|
+
},
|
|
843
|
+
evidences_by_type: {
|
|
844
|
+
additionalProperties: {
|
|
845
|
+
minimum: 0,
|
|
846
|
+
type: "integer"
|
|
847
|
+
},
|
|
848
|
+
title: "Evidences By Type",
|
|
849
|
+
type: "object"
|
|
850
|
+
},
|
|
851
|
+
evidences_by_source: {
|
|
852
|
+
additionalProperties: {
|
|
853
|
+
minimum: 0,
|
|
854
|
+
type: "integer"
|
|
855
|
+
},
|
|
856
|
+
title: "Evidences By Source",
|
|
636
857
|
type: "object"
|
|
637
858
|
},
|
|
638
859
|
total_threat_intel: {
|
|
@@ -667,8 +888,9 @@ var cyvest_schema_default = {
|
|
|
667
888
|
"internal_observables",
|
|
668
889
|
"external_observables",
|
|
669
890
|
"whitelisted_observables",
|
|
670
|
-
"
|
|
671
|
-
"
|
|
891
|
+
"total_findings",
|
|
892
|
+
"applied_findings",
|
|
893
|
+
"total_evidences",
|
|
672
894
|
"total_threat_intel",
|
|
673
895
|
"total_tags"
|
|
674
896
|
],
|
|
@@ -677,7 +899,7 @@ var cyvest_schema_default = {
|
|
|
677
899
|
},
|
|
678
900
|
Tag: {
|
|
679
901
|
additionalProperties: false,
|
|
680
|
-
description: 'Groups
|
|
902
|
+
description: 'Groups findings for categorical organization.\n\nTags allow structuring the investigation into logical sections\nwith aggregated scores and levels. Hierarchy is automatic based on\nthe ":" delimiter in tag names (e.g., "header:auth:dkim").',
|
|
681
903
|
properties: {
|
|
682
904
|
name: {
|
|
683
905
|
title: "Name",
|
|
@@ -688,11 +910,11 @@ var cyvest_schema_default = {
|
|
|
688
910
|
title: "Description",
|
|
689
911
|
type: "string"
|
|
690
912
|
},
|
|
691
|
-
|
|
913
|
+
findings: {
|
|
692
914
|
items: {
|
|
693
915
|
type: "string"
|
|
694
916
|
},
|
|
695
|
-
title: "
|
|
917
|
+
title: "Findings",
|
|
696
918
|
type: "array"
|
|
697
919
|
},
|
|
698
920
|
key: {
|
|
@@ -700,20 +922,20 @@ var cyvest_schema_default = {
|
|
|
700
922
|
type: "string"
|
|
701
923
|
},
|
|
702
924
|
direct_score: {
|
|
703
|
-
description: "Calculate the score from direct
|
|
925
|
+
description: "Calculate the score from direct findings only (no hierarchy).\n\nFor hierarchical aggregation (including descendant tags), use\nInvestigation.get_tag_aggregated_score() or TagProxy.get_aggregated_score().\n\nReturns:\n Total score from direct findings",
|
|
704
926
|
readOnly: true,
|
|
705
927
|
title: "Direct Score",
|
|
706
928
|
type: "number"
|
|
707
929
|
},
|
|
708
930
|
direct_level: {
|
|
709
931
|
$ref: "#/$defs/Level",
|
|
710
|
-
description: "Calculate the level from direct
|
|
932
|
+
description: "Calculate the level from direct findings only (no hierarchy).\n\nFor hierarchical aggregation (including descendant tags), use\nInvestigation.get_tag_aggregated_level() or TagProxy.get_aggregated_level().\n\nReturns:\n Level based on direct score",
|
|
711
933
|
readOnly: true
|
|
712
934
|
}
|
|
713
935
|
},
|
|
714
936
|
required: [
|
|
715
937
|
"name",
|
|
716
|
-
"
|
|
938
|
+
"findings",
|
|
717
939
|
"key",
|
|
718
940
|
"direct_score",
|
|
719
941
|
"direct_level"
|
|
@@ -809,6 +1031,12 @@ var cyvest_schema_default = {
|
|
|
809
1031
|
additionalProperties: false,
|
|
810
1032
|
description: "Schema for a complete serialized investigation.\n\nThis model describes the output of `serialize_investigation()` from\n`cyvest.io_serialization`. It is the top-level schema for exported investigations.\n\nEntity types reference the runtime models directly. When generating schemas with\n`mode='serialization'`, Pydantic respects field_serializer decorators and produces\nschemas matching the actual model_dump() output.",
|
|
811
1033
|
properties: {
|
|
1034
|
+
schema_version: {
|
|
1035
|
+
const: "6.0.0",
|
|
1036
|
+
default: "6.0.0",
|
|
1037
|
+
title: "Schema Version",
|
|
1038
|
+
type: "string"
|
|
1039
|
+
},
|
|
812
1040
|
investigation_id: {
|
|
813
1041
|
description: "Stable investigation identity (ULID).",
|
|
814
1042
|
title: "Investigation Id",
|
|
@@ -872,12 +1100,20 @@ var cyvest_schema_default = {
|
|
|
872
1100
|
title: "Observables",
|
|
873
1101
|
type: "object"
|
|
874
1102
|
},
|
|
875
|
-
|
|
1103
|
+
findings: {
|
|
1104
|
+
additionalProperties: {
|
|
1105
|
+
$ref: "#/$defs/Finding"
|
|
1106
|
+
},
|
|
1107
|
+
description: "Findings keyed by their unique key.",
|
|
1108
|
+
title: "Findings",
|
|
1109
|
+
type: "object"
|
|
1110
|
+
},
|
|
1111
|
+
evidences: {
|
|
876
1112
|
additionalProperties: {
|
|
877
|
-
$ref: "#/$defs/
|
|
1113
|
+
$ref: "#/$defs/Evidence"
|
|
878
1114
|
},
|
|
879
|
-
description: "
|
|
880
|
-
title: "
|
|
1115
|
+
description: "Evidence objects keyed by their unique key.",
|
|
1116
|
+
title: "Evidences",
|
|
881
1117
|
type: "object"
|
|
882
1118
|
},
|
|
883
1119
|
threat_intels: {
|
|
@@ -926,7 +1162,8 @@ var cyvest_schema_default = {
|
|
|
926
1162
|
"whitelisted",
|
|
927
1163
|
"whitelists",
|
|
928
1164
|
"observables",
|
|
929
|
-
"
|
|
1165
|
+
"findings",
|
|
1166
|
+
"evidences",
|
|
930
1167
|
"threat_intels",
|
|
931
1168
|
"enrichments",
|
|
932
1169
|
"tags",
|
|
@@ -965,6 +1202,108 @@ function isCyvest(json) {
|
|
|
965
1202
|
function normalizeValue(value) {
|
|
966
1203
|
return value.trim().toLowerCase();
|
|
967
1204
|
}
|
|
1205
|
+
function normalizeObservableValue(obsType, value, subtype) {
|
|
1206
|
+
const normalizedType = normalizeValue(obsType);
|
|
1207
|
+
const normalizedSubtype = subtype ? normalizeValue(subtype) : void 0;
|
|
1208
|
+
const stripped = value.trim();
|
|
1209
|
+
if (normalizedType === "command_line") return stripped;
|
|
1210
|
+
if (normalizedType === "email" || normalizedType === "host") {
|
|
1211
|
+
return stripped.toLowerCase();
|
|
1212
|
+
}
|
|
1213
|
+
if (normalizedType === "user" && (normalizedSubtype === "email" || normalizedSubtype === "upn")) {
|
|
1214
|
+
return stripped.toLowerCase();
|
|
1215
|
+
}
|
|
1216
|
+
if (normalizedSubtype === "uid" || normalizedSubtype === "pid") {
|
|
1217
|
+
if (!/^[+-]?\d+$/.test(stripped)) {
|
|
1218
|
+
throw new Error(`${normalizedSubtype} observable values must be base-10 integers`);
|
|
1219
|
+
}
|
|
1220
|
+
return BigInt(stripped).toString(10);
|
|
1221
|
+
}
|
|
1222
|
+
return stripped;
|
|
1223
|
+
}
|
|
1224
|
+
function sha256(content) {
|
|
1225
|
+
const bytes = new TextEncoder().encode(content);
|
|
1226
|
+
const words = [];
|
|
1227
|
+
const bitLength = bytes.length * 8;
|
|
1228
|
+
for (const byte of bytes) {
|
|
1229
|
+
words.push(byte);
|
|
1230
|
+
}
|
|
1231
|
+
words.push(128);
|
|
1232
|
+
while (words.length % 64 !== 56) words.push(0);
|
|
1233
|
+
for (let i = 7; i >= 0; i--) {
|
|
1234
|
+
words.push(Math.floor(bitLength / 2 ** (i * 8)) & 255);
|
|
1235
|
+
}
|
|
1236
|
+
const h = [
|
|
1237
|
+
1779033703,
|
|
1238
|
+
3144134277,
|
|
1239
|
+
1013904242,
|
|
1240
|
+
2773480762,
|
|
1241
|
+
1359893119,
|
|
1242
|
+
2600822924,
|
|
1243
|
+
528734635,
|
|
1244
|
+
1541459225
|
|
1245
|
+
];
|
|
1246
|
+
const k = Array.from({ length: 64 }, (_, index) => {
|
|
1247
|
+
let primeCount = 0;
|
|
1248
|
+
let candidate = 2;
|
|
1249
|
+
while (true) {
|
|
1250
|
+
let prime = true;
|
|
1251
|
+
for (let divisor = 2; divisor * divisor <= candidate; divisor++) {
|
|
1252
|
+
if (candidate % divisor === 0) {
|
|
1253
|
+
prime = false;
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (prime && primeCount++ === index) {
|
|
1258
|
+
return Math.floor(Math.cbrt(candidate) % 1 * 2 ** 32) >>> 0;
|
|
1259
|
+
}
|
|
1260
|
+
candidate++;
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
const rotateRight = (value, amount) => value >>> amount | value << 32 - amount;
|
|
1264
|
+
for (let offset = 0; offset < words.length; offset += 64) {
|
|
1265
|
+
const schedule = new Array(64);
|
|
1266
|
+
for (let i = 0; i < 16; i++) {
|
|
1267
|
+
const base = offset + i * 4;
|
|
1268
|
+
schedule[i] = (words[base] << 24 | words[base + 1] << 16 | words[base + 2] << 8 | words[base + 3]) >>> 0;
|
|
1269
|
+
}
|
|
1270
|
+
for (let i = 16; i < 64; i++) {
|
|
1271
|
+
const s0 = rotateRight(schedule[i - 15], 7) ^ rotateRight(schedule[i - 15], 18) ^ schedule[i - 15] >>> 3;
|
|
1272
|
+
const s1 = rotateRight(schedule[i - 2], 17) ^ rotateRight(schedule[i - 2], 19) ^ schedule[i - 2] >>> 10;
|
|
1273
|
+
schedule[i] = schedule[i - 16] + s0 + schedule[i - 7] + s1 >>> 0;
|
|
1274
|
+
}
|
|
1275
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
1276
|
+
for (let i = 0; i < 64; i++) {
|
|
1277
|
+
const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
|
|
1278
|
+
const choice = e & f ^ ~e & g;
|
|
1279
|
+
const temp1 = hh + s1 + choice + k[i] + schedule[i] >>> 0;
|
|
1280
|
+
const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
|
|
1281
|
+
const majority = a & b ^ a & c ^ b & c;
|
|
1282
|
+
const temp2 = s0 + majority >>> 0;
|
|
1283
|
+
hh = g;
|
|
1284
|
+
g = f;
|
|
1285
|
+
f = e;
|
|
1286
|
+
e = d + temp1 >>> 0;
|
|
1287
|
+
d = c;
|
|
1288
|
+
c = b;
|
|
1289
|
+
b = a;
|
|
1290
|
+
a = temp1 + temp2 >>> 0;
|
|
1291
|
+
}
|
|
1292
|
+
[a, b, c, d, e, f, g, hh].forEach((value, index) => {
|
|
1293
|
+
h[index] = h[index] + value >>> 0;
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
return h.map((value) => value.toString(16).padStart(8, "0")).join("");
|
|
1297
|
+
}
|
|
1298
|
+
function encodeKeyPart(value, keepSlash = false) {
|
|
1299
|
+
let encoded = encodeURIComponent(value).replace(
|
|
1300
|
+
/[!'()*]/g,
|
|
1301
|
+
(char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
|
|
1302
|
+
);
|
|
1303
|
+
encoded = encoded.replace(/%40/gi, "@");
|
|
1304
|
+
if (keepSlash) encoded = encoded.replace(/%2F/gi, "/").replace(/%5C/gi, "\\");
|
|
1305
|
+
return encoded;
|
|
1306
|
+
}
|
|
968
1307
|
function hashString(content, length = 16) {
|
|
969
1308
|
let hash = 0;
|
|
970
1309
|
for (let i = 0; i < content.length; i++) {
|
|
@@ -974,14 +1313,35 @@ function hashString(content, length = 16) {
|
|
|
974
1313
|
const hex = Math.abs(hash).toString(16).padStart(8, "0");
|
|
975
1314
|
return hex.slice(0, length);
|
|
976
1315
|
}
|
|
977
|
-
function generateObservableKey(obsType, value) {
|
|
1316
|
+
function generateObservableKey(obsType, value, subtype, namespace) {
|
|
978
1317
|
const normalizedType = normalizeValue(obsType);
|
|
979
|
-
const
|
|
980
|
-
|
|
1318
|
+
const normalizedSubtype = subtype ? normalizeValue(subtype) : void 0;
|
|
1319
|
+
const normalizedNamespace = namespace?.trim().toLowerCase() || void 0;
|
|
1320
|
+
const normalizedValue = normalizeObservableValue(
|
|
1321
|
+
normalizedType,
|
|
1322
|
+
value,
|
|
1323
|
+
normalizedSubtype
|
|
1324
|
+
);
|
|
1325
|
+
const identity = JSON.stringify({
|
|
1326
|
+
namespace: normalizedNamespace ?? null,
|
|
1327
|
+
subtype: normalizedSubtype ?? null,
|
|
1328
|
+
type: normalizedType,
|
|
1329
|
+
value: normalizedValue
|
|
1330
|
+
});
|
|
1331
|
+
if (normalizedType === "command_line" || new TextEncoder().encode(identity).length > 128) {
|
|
1332
|
+
return `obs:${normalizedType}:sha256:${sha256(identity)}`;
|
|
1333
|
+
}
|
|
1334
|
+
if (!normalizedSubtype && !normalizedNamespace) {
|
|
1335
|
+
return `obs:${normalizedType}:${normalizedValue.toLowerCase()}`;
|
|
1336
|
+
}
|
|
1337
|
+
const parts = ["obs", encodeKeyPart(normalizedType), normalizedSubtype ? encodeKeyPart(normalizedSubtype) : "_"];
|
|
1338
|
+
if (normalizedNamespace) parts.push(encodeKeyPart(normalizedNamespace));
|
|
1339
|
+
parts.push(encodeKeyPart(normalizedValue, true));
|
|
1340
|
+
return parts.join(":");
|
|
981
1341
|
}
|
|
982
|
-
function
|
|
983
|
-
const normalizedName = normalizeValue(
|
|
984
|
-
return `
|
|
1342
|
+
function generateFindingKey(findingName) {
|
|
1343
|
+
const normalizedName = normalizeValue(findingName);
|
|
1344
|
+
return `fnd:${normalizedName}`;
|
|
985
1345
|
}
|
|
986
1346
|
function generateThreatIntelKey(source, observableKey) {
|
|
987
1347
|
const normalizedSource = normalizeValue(source);
|
|
@@ -1020,7 +1380,7 @@ function isTagDescendantOf(descendantName, ancestorName) {
|
|
|
1020
1380
|
function parseKeyType(key) {
|
|
1021
1381
|
if (key.includes(":")) {
|
|
1022
1382
|
const prefix = key.split(":", 1)[0];
|
|
1023
|
-
if (["obs", "
|
|
1383
|
+
if (["obs", "fnd", "evd", "ti", "enr", "tag"].includes(prefix)) {
|
|
1024
1384
|
return prefix;
|
|
1025
1385
|
}
|
|
1026
1386
|
}
|
|
@@ -1053,14 +1413,14 @@ function parseObservableKey(key) {
|
|
|
1053
1413
|
}
|
|
1054
1414
|
return null;
|
|
1055
1415
|
}
|
|
1056
|
-
function
|
|
1057
|
-
if (!validateKey(key, "
|
|
1416
|
+
function parseFindingKey(key) {
|
|
1417
|
+
if (!validateKey(key, "fnd")) {
|
|
1058
1418
|
return null;
|
|
1059
1419
|
}
|
|
1060
1420
|
const parts = key.split(":");
|
|
1061
1421
|
if (parts.length >= 2) {
|
|
1062
1422
|
return {
|
|
1063
|
-
|
|
1423
|
+
findingName: parts.slice(1).join(":")
|
|
1064
1424
|
};
|
|
1065
1425
|
}
|
|
1066
1426
|
return null;
|
|
@@ -1193,15 +1553,8 @@ function getEntityLevel(entity) {
|
|
|
1193
1553
|
function getObservable(inv, key) {
|
|
1194
1554
|
return inv.observables[key];
|
|
1195
1555
|
}
|
|
1196
|
-
function getObservableByTypeValue(inv, type, value) {
|
|
1197
|
-
|
|
1198
|
-
const normalizedValue = value.trim().toLowerCase();
|
|
1199
|
-
for (const obs of Object.values(inv.observables)) {
|
|
1200
|
-
if (obs.type.toLowerCase() === normalizedType && obs.value.toLowerCase() === normalizedValue) {
|
|
1201
|
-
return obs;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
return void 0;
|
|
1556
|
+
function getObservableByTypeValue(inv, type, value, subtype, namespace) {
|
|
1557
|
+
return inv.observables[generateObservableKey(type, value, subtype, namespace)];
|
|
1205
1558
|
}
|
|
1206
1559
|
function getRootObservable(inv) {
|
|
1207
1560
|
const rootType = inv.data_extraction.root_type;
|
|
@@ -1211,15 +1564,21 @@ function getRootObservable(inv) {
|
|
|
1211
1564
|
const rootKey = generateObservableKey(rootType, "root");
|
|
1212
1565
|
return inv.observables[rootKey];
|
|
1213
1566
|
}
|
|
1214
|
-
function
|
|
1215
|
-
return inv.
|
|
1567
|
+
function getFinding(inv, key) {
|
|
1568
|
+
return inv.findings[key];
|
|
1569
|
+
}
|
|
1570
|
+
function getFindingByName(inv, findingName) {
|
|
1571
|
+
const key = generateFindingKey(findingName);
|
|
1572
|
+
return inv.findings[key];
|
|
1573
|
+
}
|
|
1574
|
+
function getAllFindings(inv) {
|
|
1575
|
+
return Object.values(inv.findings);
|
|
1216
1576
|
}
|
|
1217
|
-
function
|
|
1218
|
-
|
|
1219
|
-
return inv.checks[key];
|
|
1577
|
+
function getEvidence(inv, key) {
|
|
1578
|
+
return inv.evidences[key];
|
|
1220
1579
|
}
|
|
1221
|
-
function
|
|
1222
|
-
return Object.values(inv.
|
|
1580
|
+
function getAllEvidences(inv) {
|
|
1581
|
+
return Object.values(inv.evidences);
|
|
1223
1582
|
}
|
|
1224
1583
|
function getThreatIntel(inv, key) {
|
|
1225
1584
|
return inv.threat_intels[key];
|
|
@@ -1276,7 +1635,8 @@ function getDataExtraction(inv) {
|
|
|
1276
1635
|
function getCounts(inv) {
|
|
1277
1636
|
return {
|
|
1278
1637
|
observables: Object.keys(inv.observables).length,
|
|
1279
|
-
|
|
1638
|
+
findings: getAllFindings(inv).length,
|
|
1639
|
+
evidences: getAllEvidences(inv).length,
|
|
1280
1640
|
threatIntels: Object.keys(inv.threat_intels).length,
|
|
1281
1641
|
enrichments: Object.keys(inv.enrichments).length,
|
|
1282
1642
|
tags: getAllTags(inv).length,
|
|
@@ -1358,18 +1718,18 @@ function findObservablesWithThreatIntel(inv) {
|
|
|
1358
1718
|
(obs) => obs.threat_intels.length > 0
|
|
1359
1719
|
);
|
|
1360
1720
|
}
|
|
1361
|
-
function
|
|
1362
|
-
return Object.values(inv.
|
|
1721
|
+
function findFindingsByLevel(inv, level) {
|
|
1722
|
+
return Object.values(inv.findings).filter((finding) => finding.level === level);
|
|
1363
1723
|
}
|
|
1364
|
-
function
|
|
1365
|
-
return Object.values(inv.
|
|
1366
|
-
(
|
|
1724
|
+
function findFindingsAtLeast(inv, minLevel2) {
|
|
1725
|
+
return Object.values(inv.findings).filter(
|
|
1726
|
+
(finding) => isLevelAtLeast(finding.level, minLevel2)
|
|
1367
1727
|
);
|
|
1368
1728
|
}
|
|
1369
|
-
function
|
|
1370
|
-
const normalizedName =
|
|
1371
|
-
return Object.values(inv.
|
|
1372
|
-
(
|
|
1729
|
+
function findFindingByName(inv, findingName) {
|
|
1730
|
+
const normalizedName = findingName.trim().toLowerCase();
|
|
1731
|
+
return Object.values(inv.findings).find(
|
|
1732
|
+
(finding) => finding.finding_name.toLowerCase() === normalizedName
|
|
1373
1733
|
);
|
|
1374
1734
|
}
|
|
1375
1735
|
function findThreatIntelBySource(inv, source) {
|
|
@@ -1397,26 +1757,26 @@ function findTagsAtLeast(inv, minLevel2) {
|
|
|
1397
1757
|
function findTagsByNamePattern(inv, pattern) {
|
|
1398
1758
|
return Object.values(inv.tags).filter((tag) => pattern.test(tag.name));
|
|
1399
1759
|
}
|
|
1400
|
-
function
|
|
1760
|
+
function findFindingsForObservable(inv, observableKey) {
|
|
1401
1761
|
const result = [];
|
|
1402
1762
|
const seen = /* @__PURE__ */ new Set();
|
|
1403
1763
|
const observable = inv.observables[observableKey];
|
|
1404
1764
|
if (observable) {
|
|
1405
|
-
for (const
|
|
1406
|
-
const
|
|
1407
|
-
if (
|
|
1408
|
-
result.push(
|
|
1409
|
-
seen.add(
|
|
1765
|
+
for (const findingKey of observable.finding_links) {
|
|
1766
|
+
const finding = inv.findings[findingKey];
|
|
1767
|
+
if (finding && !seen.has(finding.key)) {
|
|
1768
|
+
result.push(finding);
|
|
1769
|
+
seen.add(finding.key);
|
|
1410
1770
|
}
|
|
1411
1771
|
}
|
|
1412
1772
|
}
|
|
1413
|
-
for (const
|
|
1414
|
-
if (seen.has(
|
|
1773
|
+
for (const finding of Object.values(inv.findings)) {
|
|
1774
|
+
if (seen.has(finding.key)) {
|
|
1415
1775
|
continue;
|
|
1416
1776
|
}
|
|
1417
|
-
if (
|
|
1418
|
-
result.push(
|
|
1419
|
-
seen.add(
|
|
1777
|
+
if (finding.observable_links.some((link) => link.observable_key === observableKey)) {
|
|
1778
|
+
result.push(finding);
|
|
1779
|
+
seen.add(finding.key);
|
|
1420
1780
|
}
|
|
1421
1781
|
}
|
|
1422
1782
|
return result;
|
|
@@ -1430,37 +1790,37 @@ function findThreatIntelsForObservable(inv, observableKey) {
|
|
|
1430
1790
|
(ti) => ti.observable_key === observableKey
|
|
1431
1791
|
);
|
|
1432
1792
|
}
|
|
1433
|
-
function
|
|
1434
|
-
const
|
|
1435
|
-
if (
|
|
1793
|
+
function findObservablesForFinding(inv, findingKey) {
|
|
1794
|
+
const finding = inv.findings[findingKey];
|
|
1795
|
+
if (finding) {
|
|
1436
1796
|
const keys = /* @__PURE__ */ new Set();
|
|
1437
|
-
for (const link of
|
|
1797
|
+
for (const link of finding.observable_links) {
|
|
1438
1798
|
keys.add(link.observable_key);
|
|
1439
1799
|
}
|
|
1440
1800
|
return Array.from(keys).map((obsKey) => inv.observables[obsKey]).filter((obs) => obs !== void 0);
|
|
1441
1801
|
}
|
|
1442
1802
|
return [];
|
|
1443
1803
|
}
|
|
1444
|
-
function
|
|
1804
|
+
function findFindingsForTag(inv, tagKey, recursive = false) {
|
|
1445
1805
|
const result = [];
|
|
1446
1806
|
const tag = inv.tags[tagKey];
|
|
1447
1807
|
if (!tag) {
|
|
1448
1808
|
return result;
|
|
1449
1809
|
}
|
|
1450
|
-
for (const
|
|
1451
|
-
const
|
|
1452
|
-
if (
|
|
1453
|
-
result.push(
|
|
1810
|
+
for (const findingKey of tag.findings) {
|
|
1811
|
+
const finding = inv.findings[findingKey];
|
|
1812
|
+
if (finding) {
|
|
1813
|
+
result.push(finding);
|
|
1454
1814
|
}
|
|
1455
1815
|
}
|
|
1456
1816
|
if (recursive) {
|
|
1457
1817
|
const prefix = tag.name + ":";
|
|
1458
1818
|
for (const otherTag of Object.values(inv.tags)) {
|
|
1459
1819
|
if (otherTag.name.startsWith(prefix)) {
|
|
1460
|
-
for (const
|
|
1461
|
-
const
|
|
1462
|
-
if (
|
|
1463
|
-
result.push(
|
|
1820
|
+
for (const findingKey of otherTag.findings) {
|
|
1821
|
+
const finding = inv.findings[findingKey];
|
|
1822
|
+
if (finding) {
|
|
1823
|
+
result.push(finding);
|
|
1464
1824
|
}
|
|
1465
1825
|
}
|
|
1466
1826
|
}
|
|
@@ -1471,24 +1831,24 @@ function findChecksForTag(inv, tagKey, recursive = false) {
|
|
|
1471
1831
|
function sortObservablesByScore(observables) {
|
|
1472
1832
|
return [...observables].sort((a, b) => b.score - a.score);
|
|
1473
1833
|
}
|
|
1474
|
-
function
|
|
1475
|
-
return [...
|
|
1834
|
+
function sortFindingsByScore(findings) {
|
|
1835
|
+
return [...findings].sort((a, b) => b.score - a.score);
|
|
1476
1836
|
}
|
|
1477
1837
|
function sortObservablesByLevel(observables) {
|
|
1478
1838
|
return [...observables].sort(
|
|
1479
1839
|
(a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
|
|
1480
1840
|
);
|
|
1481
1841
|
}
|
|
1482
|
-
function
|
|
1483
|
-
return [...
|
|
1842
|
+
function sortFindingsByLevel(findings) {
|
|
1843
|
+
return [...findings].sort(
|
|
1484
1844
|
(a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
|
|
1485
1845
|
);
|
|
1486
1846
|
}
|
|
1487
1847
|
function findHighestScoringObservables(inv, n = 10) {
|
|
1488
1848
|
return sortObservablesByScore(Object.values(inv.observables)).slice(0, n);
|
|
1489
1849
|
}
|
|
1490
|
-
function
|
|
1491
|
-
return
|
|
1850
|
+
function findHighestScoringFindings(inv, n = 10) {
|
|
1851
|
+
return sortFindingsByScore(Object.values(inv.findings)).slice(0, n);
|
|
1492
1852
|
}
|
|
1493
1853
|
function findMaliciousObservables(inv) {
|
|
1494
1854
|
return findObservablesByLevel(inv, "MALICIOUS");
|
|
@@ -1496,14 +1856,14 @@ function findMaliciousObservables(inv) {
|
|
|
1496
1856
|
function findSuspiciousObservables(inv) {
|
|
1497
1857
|
return findObservablesByLevel(inv, "SUSPICIOUS");
|
|
1498
1858
|
}
|
|
1499
|
-
function
|
|
1500
|
-
return
|
|
1859
|
+
function findMaliciousFindings(inv) {
|
|
1860
|
+
return findFindingsByLevel(inv, "MALICIOUS");
|
|
1501
1861
|
}
|
|
1502
|
-
function
|
|
1503
|
-
return
|
|
1862
|
+
function findSuspiciousFindings(inv) {
|
|
1863
|
+
return findFindingsByLevel(inv, "SUSPICIOUS");
|
|
1504
1864
|
}
|
|
1505
|
-
function
|
|
1506
|
-
return Object.keys(inv.
|
|
1865
|
+
function getAllFindingKeys(inv) {
|
|
1866
|
+
return Object.keys(inv.findings);
|
|
1507
1867
|
}
|
|
1508
1868
|
function getAllObservableTypes(inv) {
|
|
1509
1869
|
const types = /* @__PURE__ */ new Set();
|
|
@@ -1788,30 +2148,30 @@ function getRelationshipsForObservable(inv, observableKey) {
|
|
|
1788
2148
|
areConnected,
|
|
1789
2149
|
compareLevels,
|
|
1790
2150
|
countRelationshipsByType,
|
|
1791
|
-
findCheckByName,
|
|
1792
|
-
findChecksAtLeast,
|
|
1793
|
-
findChecksByLevel,
|
|
1794
|
-
findChecksForObservable,
|
|
1795
|
-
findChecksForTag,
|
|
1796
2151
|
findExternalObservables,
|
|
1797
|
-
|
|
2152
|
+
findFindingByName,
|
|
2153
|
+
findFindingsAtLeast,
|
|
2154
|
+
findFindingsByLevel,
|
|
2155
|
+
findFindingsForObservable,
|
|
2156
|
+
findFindingsForTag,
|
|
2157
|
+
findHighestScoringFindings,
|
|
1798
2158
|
findHighestScoringObservables,
|
|
1799
2159
|
findInternalObservables,
|
|
1800
2160
|
findLeafObservables,
|
|
1801
|
-
|
|
2161
|
+
findMaliciousFindings,
|
|
1802
2162
|
findMaliciousObservables,
|
|
1803
2163
|
findObservablesAtLeast,
|
|
1804
2164
|
findObservablesByLevel,
|
|
1805
2165
|
findObservablesByType,
|
|
1806
2166
|
findObservablesByValue,
|
|
1807
2167
|
findObservablesContaining,
|
|
1808
|
-
|
|
2168
|
+
findObservablesForFinding,
|
|
1809
2169
|
findObservablesMatching,
|
|
1810
2170
|
findObservablesWithThreatIntel,
|
|
1811
2171
|
findOrphanObservables,
|
|
1812
2172
|
findPath,
|
|
1813
2173
|
findSourceObservables,
|
|
1814
|
-
|
|
2174
|
+
findSuspiciousFindings,
|
|
1815
2175
|
findSuspiciousObservables,
|
|
1816
2176
|
findTagsAtLeast,
|
|
1817
2177
|
findTagsByLevel,
|
|
@@ -1821,22 +2181,21 @@ function getRelationshipsForObservable(inv, observableKey) {
|
|
|
1821
2181
|
findThreatIntelBySource,
|
|
1822
2182
|
findThreatIntelsForObservable,
|
|
1823
2183
|
findWhitelistedObservables,
|
|
1824
|
-
generateCheckKey,
|
|
1825
2184
|
generateEnrichmentKey,
|
|
2185
|
+
generateFindingKey,
|
|
1826
2186
|
generateObservableKey,
|
|
1827
2187
|
generateTagKey,
|
|
1828
2188
|
generateThreatIntelKey,
|
|
1829
|
-
getAllCheckKeys,
|
|
1830
|
-
getAllChecks,
|
|
1831
2189
|
getAllEnrichments,
|
|
2190
|
+
getAllEvidences,
|
|
2191
|
+
getAllFindingKeys,
|
|
2192
|
+
getAllFindings,
|
|
1832
2193
|
getAllObservableTypes,
|
|
1833
2194
|
getAllObservables,
|
|
1834
2195
|
getAllRelationshipTypes,
|
|
1835
2196
|
getAllTags,
|
|
1836
2197
|
getAllThreatIntelSources,
|
|
1837
2198
|
getAllThreatIntels,
|
|
1838
|
-
getCheck,
|
|
1839
|
-
getCheckByName,
|
|
1840
2199
|
getColorForLevel,
|
|
1841
2200
|
getColorForScore,
|
|
1842
2201
|
getCounts,
|
|
@@ -1844,6 +2203,9 @@ function getRelationshipsForObservable(inv, observableKey) {
|
|
|
1844
2203
|
getEnrichment,
|
|
1845
2204
|
getEnrichmentByName,
|
|
1846
2205
|
getEntityLevel,
|
|
2206
|
+
getEvidence,
|
|
2207
|
+
getFinding,
|
|
2208
|
+
getFindingByName,
|
|
1847
2209
|
getLevelFromScore,
|
|
1848
2210
|
getObservable,
|
|
1849
2211
|
getObservableByTypeValue,
|
|
@@ -1879,13 +2241,13 @@ function getRelationshipsForObservable(inv, observableKey) {
|
|
|
1879
2241
|
maxLevel,
|
|
1880
2242
|
minLevel,
|
|
1881
2243
|
normalizeLevel,
|
|
1882
|
-
parseCheckKey,
|
|
1883
2244
|
parseCyvest,
|
|
2245
|
+
parseFindingKey,
|
|
1884
2246
|
parseKeyType,
|
|
1885
2247
|
parseObservableKey,
|
|
1886
2248
|
parseThreatIntelKey,
|
|
1887
|
-
|
|
1888
|
-
|
|
2249
|
+
sortFindingsByLevel,
|
|
2250
|
+
sortFindingsByScore,
|
|
1889
2251
|
sortObservablesByLevel,
|
|
1890
2252
|
sortObservablesByScore,
|
|
1891
2253
|
validateKey
|