@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyvest/cyvest-js",
3
- "version": "4.4.1",
3
+ "version": "5.0.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
package/src/finders.ts CHANGED
@@ -10,7 +10,7 @@ import type {
10
10
  Observable,
11
11
  Check,
12
12
  ThreatIntel,
13
- Container,
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
- const result: Check[] = [];
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
- const result: Check[] = [];
257
- for (const checks of Object.values(inv.checks)) {
258
- for (const check of checks) {
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 ID (across all scopes).
221
+ * Find checks by check name.
269
222
  *
270
223
  * @param inv - The investigation to search
271
- * @param checkId - Check identifier to search for
272
- * @returns Array of matching checks
224
+ * @param checkName - Check name to search for
225
+ * @returns The matching check or undefined
273
226
  */
274
- export function findChecksByCheckId(
227
+ export function findCheckByName(
275
228
  inv: CyvestInvestigation,
276
- checkId: string
277
- ): Check[] {
278
- const normalizedId = checkId.trim().toLowerCase();
279
- const result: Check[] = [];
280
-
281
- for (const checks of Object.values(inv.checks)) {
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
- // Container Finders
289
+ // Tag Finders
344
290
  // ============================================================================
345
291
 
346
292
  /**
347
- * Find containers at a specific aggregated level.
293
+ * Find tags at a specific direct level.
348
294
  *
349
295
  * @param inv - The investigation to search
350
- * @param level - Aggregated level to filter by
351
- * @returns Array of matching containers
296
+ * @param level - Direct level to filter by
297
+ * @returns Array of matching tags
352
298
  */
353
- export function findContainersByLevel(
299
+ export function findTagsByLevel(
354
300
  inv: CyvestInvestigation,
355
301
  level: Level
356
- ): Container[] {
357
- const result: Container[] = [];
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 containers at or above a minimum aggregated level.
307
+ * Find tags at or above a minimum direct level.
374
308
  *
375
309
  * @param inv - The investigation to search
376
- * @param minLevel - Minimum aggregated level
377
- * @returns Array of matching containers
310
+ * @param minLevel - Minimum direct level
311
+ * @returns Array of matching tags
378
312
  */
379
- export function findContainersAtLeast(
313
+ export function findTagsAtLeast(
380
314
  inv: CyvestInvestigation,
381
315
  minLevel: Level
382
- ): Container[] {
383
- const result: Container[] = [];
384
-
385
- function searchContainers(containers: Record<string, Container>): void {
386
- for (const container of Object.values(containers)) {
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
- searchContainers(inv.containers);
395
- return result;
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
- * Get all checks that generated or reference a specific observable.
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 = getChecksForObservable(investigation, "obs:ipv4-addr:192.168.1.1");
349
+ * const checks = findChecksForObservable(investigation, "obs:ipv4-addr:192.168.1.1");
412
350
  * ```
413
351
  */
414
- export function getChecksForObservable(
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 = checkLookup.get(checkKey);
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 checkLookup.values()) {
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
- * Get all threat intel entries for a specific observable.
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 getThreatIntelsForObservable(
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
- * Get all observables referenced by a specific check.
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 getObservablesForCheck(
416
+ export function findObservablesForCheck(
486
417
  inv: CyvestInvestigation,
487
418
  checkKey: string
488
419
  ): Observable[] {
489
- // Find the check
490
- for (const checks of Object.values(inv.checks)) {
491
- for (const check of checks) {
492
- if (check.key === checkKey) {
493
- const keys = new Set<string>();
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
- * Get all checks for a specific container.
435
+ * Find all checks for a specific tag.
509
436
  *
510
437
  * @param inv - The investigation to search
511
- * @param containerKey - Key of the container
512
- * @param recursive - Include checks from sub-containers (default: false)
513
- * @returns Array of checks in the container
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 getChecksForContainer(
442
+ export function findChecksForTag(
516
443
  inv: CyvestInvestigation,
517
- containerKey: string,
444
+ tagKey: string,
518
445
  recursive = false
519
446
  ): Check[] {
520
447
  const result: Check[] = [];
448
+ const tag = inv.tags[tagKey];
521
449
 
522
- function findContainer(
523
- containers: Record<string, Container>
524
- ): Container | undefined {
525
- for (const container of Object.values(containers)) {
526
- if (container.key === containerKey) {
527
- return container;
528
- }
529
- const found = findContainer(container.sub_containers);
530
- if (found) return found;
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
- function collectChecks(container: Container): void {
536
- for (const checkKey of container.checks) {
537
- for (const checks of Object.values(inv.checks)) {
538
- for (const check of checks) {
539
- if (check.key === checkKey) {
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
- * Get the highest scoring observables.
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 getHighestScoringObservables(
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
- * Get the highest scoring checks.
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 getHighestScoringChecks(
553
+ export function findHighestScoringChecks(
635
554
  inv: CyvestInvestigation,
636
555
  n = 10
637
556
  ): Check[] {
638
- const allChecks: Check[] = [];
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
- * Get all malicious observables (convenience function).
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 getMaliciousObservables(inv: CyvestInvestigation): Observable[] {
566
+ export function findMaliciousObservables(inv: CyvestInvestigation): Observable[] {
652
567
  return findObservablesByLevel(inv, "MALICIOUS");
653
568
  }
654
569
 
655
570
  /**
656
- * Get all suspicious observables (convenience function).
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 getSuspiciousObservables(inv: CyvestInvestigation): Observable[] {
576
+ export function findSuspiciousObservables(inv: CyvestInvestigation): Observable[] {
662
577
  return findObservablesByLevel(inv, "SUSPICIOUS");
663
578
  }
664
579
 
665
580
  /**
666
- * Get all malicious checks (convenience function).
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 getMaliciousChecks(inv: CyvestInvestigation): Check[] {
586
+ export function findMaliciousChecks(inv: CyvestInvestigation): Check[] {
672
587
  return findChecksByLevel(inv, "MALICIOUS");
673
588
  }
674
589
 
675
590
  /**
676
- * Get all suspicious checks (convenience function).
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 getSuspiciousChecks(inv: CyvestInvestigation): Check[] {
596
+ export function findSuspiciousChecks(inv: CyvestInvestigation): Check[] {
682
597
  return findChecksByLevel(inv, "SUSPICIOUS");
683
598
  }
684
599
 
685
600
  /**
686
- * Get all scopes that have checks.
601
+ * Get all check keys in the investigation.
687
602
  *
688
603
  * @param inv - The investigation
689
- * @returns Array of scope names
604
+ * @returns Array of check keys
690
605
  */
691
- export function getAllScopes(inv: CyvestInvestigation): string[] {
606
+ export function getAllCheckKeys(inv: CyvestInvestigation): string[] {
692
607
  return Object.keys(inv.checks);
693
608
  }
694
609