@cyvest/cyvest-js 4.4.1 → 5.0.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 +5 -4
- package/dist/index.cjs +248 -333
- package/dist/index.d.cts +255 -121
- package/dist/index.d.ts +255 -121
- package/dist/index.js +219 -312
- package/package.json +1 -1
- package/src/finders.ts +101 -186
- package/src/getters.ts +176 -104
- package/src/graph.ts +4 -4
- package/src/keys.ts +84 -30
- package/src/levels.ts +7 -7
- package/src/types.generated.ts +25 -24
- package/tests/getters-finders.test.ts +225 -126
- package/tests/graph.test.ts +6 -7
- package/tests/keys-levels.test.ts +14 -15
package/package.json
CHANGED
package/src/finders.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
Observable,
|
|
11
11
|
Check,
|
|
12
12
|
ThreatIntel,
|
|
13
|
-
|
|
13
|
+
Tag,
|
|
14
14
|
Level,
|
|
15
15
|
} from "./types.generated";
|
|
16
16
|
import { isLevelAtLeast, isLevelHigherThan, LEVEL_VALUES } from "./levels";
|
|
@@ -187,39 +187,6 @@ export function findObservablesWithThreatIntel(
|
|
|
187
187
|
// Check Finders
|
|
188
188
|
// ============================================================================
|
|
189
189
|
|
|
190
|
-
/**
|
|
191
|
-
* Find all checks in a specific scope.
|
|
192
|
-
*
|
|
193
|
-
* @param inv - The investigation to search
|
|
194
|
-
* @param scope - Check scope
|
|
195
|
-
* @returns Array of checks in the scope
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```ts
|
|
199
|
-
* const emailChecks = findChecksByScope(investigation, "email_headers");
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
export function findChecksByScope(
|
|
203
|
-
inv: CyvestInvestigation,
|
|
204
|
-
scope: string
|
|
205
|
-
): Check[] {
|
|
206
|
-
const normalizedScope = scope.trim().toLowerCase();
|
|
207
|
-
|
|
208
|
-
// Try direct lookup first
|
|
209
|
-
if (inv.checks[scope]) {
|
|
210
|
-
return inv.checks[scope];
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Fallback to normalized search
|
|
214
|
-
for (const [key, checks] of Object.entries(inv.checks)) {
|
|
215
|
-
if (key.toLowerCase() === normalizedScope) {
|
|
216
|
-
return checks;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return [];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
190
|
/**
|
|
224
191
|
* Find all checks at a specific level.
|
|
225
192
|
*
|
|
@@ -231,15 +198,7 @@ export function findChecksByLevel(
|
|
|
231
198
|
inv: CyvestInvestigation,
|
|
232
199
|
level: Level
|
|
233
200
|
): Check[] {
|
|
234
|
-
|
|
235
|
-
for (const checks of Object.values(inv.checks)) {
|
|
236
|
-
for (const check of checks) {
|
|
237
|
-
if (check.level === level) {
|
|
238
|
-
result.push(check);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return result;
|
|
201
|
+
return Object.values(inv.checks).filter((check) => check.level === level);
|
|
243
202
|
}
|
|
244
203
|
|
|
245
204
|
/**
|
|
@@ -253,39 +212,26 @@ export function findChecksAtLeast(
|
|
|
253
212
|
inv: CyvestInvestigation,
|
|
254
213
|
minLevel: Level
|
|
255
214
|
): Check[] {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (isLevelAtLeast(check.level, minLevel)) {
|
|
260
|
-
result.push(check);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return result;
|
|
215
|
+
return Object.values(inv.checks).filter((check) =>
|
|
216
|
+
isLevelAtLeast(check.level, minLevel)
|
|
217
|
+
);
|
|
265
218
|
}
|
|
266
219
|
|
|
267
220
|
/**
|
|
268
|
-
* Find checks by check
|
|
221
|
+
* Find checks by check name.
|
|
269
222
|
*
|
|
270
223
|
* @param inv - The investigation to search
|
|
271
|
-
* @param
|
|
272
|
-
* @returns
|
|
224
|
+
* @param checkName - Check name to search for
|
|
225
|
+
* @returns The matching check or undefined
|
|
273
226
|
*/
|
|
274
|
-
export function
|
|
227
|
+
export function findCheckByName(
|
|
275
228
|
inv: CyvestInvestigation,
|
|
276
|
-
|
|
277
|
-
): Check
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
for (const check of checks) {
|
|
283
|
-
if (check.check_id.toLowerCase() === normalizedId) {
|
|
284
|
-
result.push(check);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return result;
|
|
229
|
+
checkName: string
|
|
230
|
+
): Check | undefined {
|
|
231
|
+
const normalizedName = checkName.trim().toLowerCase();
|
|
232
|
+
return Object.values(inv.checks).find(
|
|
233
|
+
(check) => check.check_name.toLowerCase() === normalizedName
|
|
234
|
+
);
|
|
289
235
|
}
|
|
290
236
|
|
|
291
237
|
// ============================================================================
|
|
@@ -340,59 +286,51 @@ export function findThreatIntelAtLeast(
|
|
|
340
286
|
}
|
|
341
287
|
|
|
342
288
|
// ============================================================================
|
|
343
|
-
//
|
|
289
|
+
// Tag Finders
|
|
344
290
|
// ============================================================================
|
|
345
291
|
|
|
346
292
|
/**
|
|
347
|
-
* Find
|
|
293
|
+
* Find tags at a specific direct level.
|
|
348
294
|
*
|
|
349
295
|
* @param inv - The investigation to search
|
|
350
|
-
* @param level -
|
|
351
|
-
* @returns Array of matching
|
|
296
|
+
* @param level - Direct level to filter by
|
|
297
|
+
* @returns Array of matching tags
|
|
352
298
|
*/
|
|
353
|
-
export function
|
|
299
|
+
export function findTagsByLevel(
|
|
354
300
|
inv: CyvestInvestigation,
|
|
355
301
|
level: Level
|
|
356
|
-
):
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
function searchContainers(containers: Record<string, Container>): void {
|
|
360
|
-
for (const container of Object.values(containers)) {
|
|
361
|
-
if (container.aggregated_level === level) {
|
|
362
|
-
result.push(container);
|
|
363
|
-
}
|
|
364
|
-
searchContainers(container.sub_containers);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
searchContainers(inv.containers);
|
|
369
|
-
return result;
|
|
302
|
+
): Tag[] {
|
|
303
|
+
return Object.values(inv.tags).filter((tag) => tag.direct_level === level);
|
|
370
304
|
}
|
|
371
305
|
|
|
372
306
|
/**
|
|
373
|
-
* Find
|
|
307
|
+
* Find tags at or above a minimum direct level.
|
|
374
308
|
*
|
|
375
309
|
* @param inv - The investigation to search
|
|
376
|
-
* @param minLevel - Minimum
|
|
377
|
-
* @returns Array of matching
|
|
310
|
+
* @param minLevel - Minimum direct level
|
|
311
|
+
* @returns Array of matching tags
|
|
378
312
|
*/
|
|
379
|
-
export function
|
|
313
|
+
export function findTagsAtLeast(
|
|
380
314
|
inv: CyvestInvestigation,
|
|
381
315
|
minLevel: Level
|
|
382
|
-
):
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (isLevelAtLeast(container.aggregated_level, minLevel)) {
|
|
388
|
-
result.push(container);
|
|
389
|
-
}
|
|
390
|
-
searchContainers(container.sub_containers);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
316
|
+
): Tag[] {
|
|
317
|
+
return Object.values(inv.tags).filter((tag) =>
|
|
318
|
+
isLevelAtLeast(tag.direct_level, minLevel)
|
|
319
|
+
);
|
|
320
|
+
}
|
|
393
321
|
|
|
394
|
-
|
|
395
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Find tags by name pattern.
|
|
324
|
+
*
|
|
325
|
+
* @param inv - The investigation to search
|
|
326
|
+
* @param pattern - Pattern to match against tag names
|
|
327
|
+
* @returns Array of matching tags
|
|
328
|
+
*/
|
|
329
|
+
export function findTagsByNamePattern(
|
|
330
|
+
inv: CyvestInvestigation,
|
|
331
|
+
pattern: RegExp
|
|
332
|
+
): Tag[] {
|
|
333
|
+
return Object.values(inv.tags).filter((tag) => pattern.test(tag.name));
|
|
396
334
|
}
|
|
397
335
|
|
|
398
336
|
// ============================================================================
|
|
@@ -400,7 +338,7 @@ export function findContainersAtLeast(
|
|
|
400
338
|
// ============================================================================
|
|
401
339
|
|
|
402
340
|
/**
|
|
403
|
-
*
|
|
341
|
+
* Find all checks that generated or reference a specific observable.
|
|
404
342
|
*
|
|
405
343
|
* @param inv - The investigation to search
|
|
406
344
|
* @param observableKey - Key of the observable
|
|
@@ -408,27 +346,20 @@ export function findContainersAtLeast(
|
|
|
408
346
|
*
|
|
409
347
|
* @example
|
|
410
348
|
* ```ts
|
|
411
|
-
* const checks =
|
|
349
|
+
* const checks = findChecksForObservable(investigation, "obs:ipv4-addr:192.168.1.1");
|
|
412
350
|
* ```
|
|
413
351
|
*/
|
|
414
|
-
export function
|
|
352
|
+
export function findChecksForObservable(
|
|
415
353
|
inv: CyvestInvestigation,
|
|
416
354
|
observableKey: string
|
|
417
355
|
): Check[] {
|
|
418
356
|
const result: Check[] = [];
|
|
419
357
|
const seen = new Set<string>();
|
|
420
|
-
const checkLookup = new Map<string, Check>();
|
|
421
|
-
|
|
422
|
-
for (const checks of Object.values(inv.checks)) {
|
|
423
|
-
for (const check of checks) {
|
|
424
|
-
checkLookup.set(check.key, check);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
358
|
|
|
428
359
|
const observable = inv.observables[observableKey];
|
|
429
360
|
if (observable) {
|
|
430
361
|
for (const checkKey of observable.check_links) {
|
|
431
|
-
const check =
|
|
362
|
+
const check = inv.checks[checkKey];
|
|
432
363
|
if (check && !seen.has(check.key)) {
|
|
433
364
|
result.push(check);
|
|
434
365
|
seen.add(check.key);
|
|
@@ -436,7 +367,7 @@ export function getChecksForObservable(
|
|
|
436
367
|
}
|
|
437
368
|
}
|
|
438
369
|
|
|
439
|
-
for (const check of
|
|
370
|
+
for (const check of Object.values(inv.checks)) {
|
|
440
371
|
if (seen.has(check.key)) {
|
|
441
372
|
continue;
|
|
442
373
|
}
|
|
@@ -451,13 +382,13 @@ export function getChecksForObservable(
|
|
|
451
382
|
}
|
|
452
383
|
|
|
453
384
|
/**
|
|
454
|
-
*
|
|
385
|
+
* Find all threat intel entries for a specific observable.
|
|
455
386
|
*
|
|
456
387
|
* @param inv - The investigation to search
|
|
457
388
|
* @param observableKey - Key of the observable
|
|
458
389
|
* @returns Array of threat intel for this observable
|
|
459
390
|
*/
|
|
460
|
-
export function
|
|
391
|
+
export function findThreatIntelsForObservable(
|
|
461
392
|
inv: CyvestInvestigation,
|
|
462
393
|
observableKey: string
|
|
463
394
|
): ThreatIntel[] {
|
|
@@ -476,83 +407,71 @@ export function getThreatIntelsForObservable(
|
|
|
476
407
|
}
|
|
477
408
|
|
|
478
409
|
/**
|
|
479
|
-
*
|
|
410
|
+
* Find all observables referenced by a specific check.
|
|
480
411
|
*
|
|
481
412
|
* @param inv - The investigation to search
|
|
482
413
|
* @param checkKey - Key of the check
|
|
483
414
|
* @returns Array of observables referenced by this check
|
|
484
415
|
*/
|
|
485
|
-
export function
|
|
416
|
+
export function findObservablesForCheck(
|
|
486
417
|
inv: CyvestInvestigation,
|
|
487
418
|
checkKey: string
|
|
488
419
|
): Observable[] {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
for (const link of check.observable_links) {
|
|
495
|
-
keys.add(link.observable_key);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
return Array.from(keys)
|
|
499
|
-
.map((obsKey) => inv.observables[obsKey])
|
|
500
|
-
.filter((obs): obs is Observable => obs !== undefined);
|
|
501
|
-
}
|
|
420
|
+
const check = inv.checks[checkKey];
|
|
421
|
+
if (check) {
|
|
422
|
+
const keys = new Set<string>();
|
|
423
|
+
for (const link of check.observable_links) {
|
|
424
|
+
keys.add(link.observable_key);
|
|
502
425
|
}
|
|
426
|
+
|
|
427
|
+
return Array.from(keys)
|
|
428
|
+
.map((obsKey) => inv.observables[obsKey])
|
|
429
|
+
.filter((obs): obs is Observable => obs !== undefined);
|
|
503
430
|
}
|
|
504
431
|
return [];
|
|
505
432
|
}
|
|
506
433
|
|
|
507
434
|
/**
|
|
508
|
-
*
|
|
435
|
+
* Find all checks for a specific tag.
|
|
509
436
|
*
|
|
510
437
|
* @param inv - The investigation to search
|
|
511
|
-
* @param
|
|
512
|
-
* @param recursive - Include checks from
|
|
513
|
-
* @returns Array of checks in the
|
|
438
|
+
* @param tagKey - Key of the tag
|
|
439
|
+
* @param recursive - Include checks from descendant tags (default: false)
|
|
440
|
+
* @returns Array of checks in the tag
|
|
514
441
|
*/
|
|
515
|
-
export function
|
|
442
|
+
export function findChecksForTag(
|
|
516
443
|
inv: CyvestInvestigation,
|
|
517
|
-
|
|
444
|
+
tagKey: string,
|
|
518
445
|
recursive = false
|
|
519
446
|
): Check[] {
|
|
520
447
|
const result: Check[] = [];
|
|
448
|
+
const tag = inv.tags[tagKey];
|
|
521
449
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
450
|
+
if (!tag) {
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Get direct checks
|
|
455
|
+
for (const checkKey of tag.checks) {
|
|
456
|
+
const check = inv.checks[checkKey];
|
|
457
|
+
if (check) {
|
|
458
|
+
result.push(check);
|
|
531
459
|
}
|
|
532
|
-
return undefined;
|
|
533
460
|
}
|
|
534
461
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
462
|
+
// If recursive, get checks from descendant tags
|
|
463
|
+
if (recursive) {
|
|
464
|
+
const prefix = tag.name + ":";
|
|
465
|
+
for (const otherTag of Object.values(inv.tags)) {
|
|
466
|
+
if (otherTag.name.startsWith(prefix)) {
|
|
467
|
+
for (const checkKey of otherTag.checks) {
|
|
468
|
+
const check = inv.checks[checkKey];
|
|
469
|
+
if (check) {
|
|
540
470
|
result.push(check);
|
|
541
471
|
}
|
|
542
472
|
}
|
|
543
473
|
}
|
|
544
474
|
}
|
|
545
|
-
|
|
546
|
-
if (recursive) {
|
|
547
|
-
for (const subContainer of Object.values(container.sub_containers)) {
|
|
548
|
-
collectChecks(subContainer);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const container = findContainer(inv.containers);
|
|
554
|
-
if (container) {
|
|
555
|
-
collectChecks(container);
|
|
556
475
|
}
|
|
557
476
|
|
|
558
477
|
return result;
|
|
@@ -611,13 +530,13 @@ export function sortChecksByLevel(checks: Check[]): Check[] {
|
|
|
611
530
|
// ============================================================================
|
|
612
531
|
|
|
613
532
|
/**
|
|
614
|
-
*
|
|
533
|
+
* Find the highest scoring observables.
|
|
615
534
|
*
|
|
616
535
|
* @param inv - The investigation to search
|
|
617
536
|
* @param n - Number of results to return (default: 10)
|
|
618
537
|
* @returns Array of highest scoring observables
|
|
619
538
|
*/
|
|
620
|
-
export function
|
|
539
|
+
export function findHighestScoringObservables(
|
|
621
540
|
inv: CyvestInvestigation,
|
|
622
541
|
n = 10
|
|
623
542
|
): Observable[] {
|
|
@@ -625,70 +544,66 @@ export function getHighestScoringObservables(
|
|
|
625
544
|
}
|
|
626
545
|
|
|
627
546
|
/**
|
|
628
|
-
*
|
|
547
|
+
* Find the highest scoring checks.
|
|
629
548
|
*
|
|
630
549
|
* @param inv - The investigation to search
|
|
631
550
|
* @param n - Number of results to return (default: 10)
|
|
632
551
|
* @returns Array of highest scoring checks
|
|
633
552
|
*/
|
|
634
|
-
export function
|
|
553
|
+
export function findHighestScoringChecks(
|
|
635
554
|
inv: CyvestInvestigation,
|
|
636
555
|
n = 10
|
|
637
556
|
): Check[] {
|
|
638
|
-
|
|
639
|
-
for (const checks of Object.values(inv.checks)) {
|
|
640
|
-
allChecks.push(...checks);
|
|
641
|
-
}
|
|
642
|
-
return sortChecksByScore(allChecks).slice(0, n);
|
|
557
|
+
return sortChecksByScore(Object.values(inv.checks)).slice(0, n);
|
|
643
558
|
}
|
|
644
559
|
|
|
645
560
|
/**
|
|
646
|
-
*
|
|
561
|
+
* Find all malicious observables (convenience function).
|
|
647
562
|
*
|
|
648
563
|
* @param inv - The investigation to search
|
|
649
564
|
* @returns Array of malicious observables
|
|
650
565
|
*/
|
|
651
|
-
export function
|
|
566
|
+
export function findMaliciousObservables(inv: CyvestInvestigation): Observable[] {
|
|
652
567
|
return findObservablesByLevel(inv, "MALICIOUS");
|
|
653
568
|
}
|
|
654
569
|
|
|
655
570
|
/**
|
|
656
|
-
*
|
|
571
|
+
* Find all suspicious observables (convenience function).
|
|
657
572
|
*
|
|
658
573
|
* @param inv - The investigation to search
|
|
659
574
|
* @returns Array of suspicious observables
|
|
660
575
|
*/
|
|
661
|
-
export function
|
|
576
|
+
export function findSuspiciousObservables(inv: CyvestInvestigation): Observable[] {
|
|
662
577
|
return findObservablesByLevel(inv, "SUSPICIOUS");
|
|
663
578
|
}
|
|
664
579
|
|
|
665
580
|
/**
|
|
666
|
-
*
|
|
581
|
+
* Find all malicious checks (convenience function).
|
|
667
582
|
*
|
|
668
583
|
* @param inv - The investigation to search
|
|
669
584
|
* @returns Array of malicious checks
|
|
670
585
|
*/
|
|
671
|
-
export function
|
|
586
|
+
export function findMaliciousChecks(inv: CyvestInvestigation): Check[] {
|
|
672
587
|
return findChecksByLevel(inv, "MALICIOUS");
|
|
673
588
|
}
|
|
674
589
|
|
|
675
590
|
/**
|
|
676
|
-
*
|
|
591
|
+
* Find all suspicious checks (convenience function).
|
|
677
592
|
*
|
|
678
593
|
* @param inv - The investigation to search
|
|
679
594
|
* @returns Array of suspicious checks
|
|
680
595
|
*/
|
|
681
|
-
export function
|
|
596
|
+
export function findSuspiciousChecks(inv: CyvestInvestigation): Check[] {
|
|
682
597
|
return findChecksByLevel(inv, "SUSPICIOUS");
|
|
683
598
|
}
|
|
684
599
|
|
|
685
600
|
/**
|
|
686
|
-
* Get all
|
|
601
|
+
* Get all check keys in the investigation.
|
|
687
602
|
*
|
|
688
603
|
* @param inv - The investigation
|
|
689
|
-
* @returns Array of
|
|
604
|
+
* @returns Array of check keys
|
|
690
605
|
*/
|
|
691
|
-
export function
|
|
606
|
+
export function getAllCheckKeys(inv: CyvestInvestigation): string[] {
|
|
692
607
|
return Object.keys(inv.checks);
|
|
693
608
|
}
|
|
694
609
|
|