pycti 6.6.17__py3-none-any.whl → 6.7.0__py3-none-any.whl
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.
Potentially problematic release.
This version of pycti might be problematic. Click here for more details.
- pycti/__init__.py +1 -1
- pycti/api/opencti_api_client.py +12 -0
- pycti/api/opencti_api_draft.py +19 -0
- pycti/api/opencti_api_notification.py +39 -0
- pycti/api/opencti_api_pir.py +37 -0
- pycti/api/opencti_api_playbook.py +20 -0
- pycti/api/opencti_api_public_dashboard.py +25 -0
- pycti/api/opencti_api_trash.py +42 -0
- pycti/api/opencti_api_work.py +19 -0
- pycti/api/opencti_api_workspace.py +24 -0
- pycti/connector/opencti_connector_helper.py +7 -8
- pycti/entities/opencti_group.py +7 -1
- pycti/entities/opencti_identity.py +59 -0
- pycti/entities/opencti_indicator.py +37 -0
- pycti/entities/opencti_stix.py +4 -3
- pycti/entities/opencti_stix_core_object.py +327 -0
- pycti/entities/opencti_stix_core_relationship.py +83 -0
- pycti/entities/opencti_stix_domain_object.py +80 -0
- pycti/entities/opencti_stix_object_or_stix_relationship.py +40 -0
- pycti/entities/opencti_stix_sighting_relationship.py +81 -0
- pycti/entities/opencti_vulnerability.py +623 -36
- pycti/utils/constants.py +2 -1
- pycti/utils/opencti_stix2.py +212 -13
- pycti/utils/opencti_stix2_splitter.py +12 -6
- pycti/utils/opencti_stix2_utils.py +31 -4
- {pycti-6.6.17.dist-info → pycti-6.7.0.dist-info}/METADATA +4 -4
- {pycti-6.6.17.dist-info → pycti-6.7.0.dist-info}/RECORD +30 -24
- {pycti-6.6.17.dist-info → pycti-6.7.0.dist-info}/WHEEL +0 -0
- {pycti-6.6.17.dist-info → pycti-6.7.0.dist-info}/licenses/LICENSE +0 -0
- {pycti-6.6.17.dist-info → pycti-6.7.0.dist-info}/top_level.txt +0 -0
pycti/utils/constants.py
CHANGED
|
@@ -48,7 +48,7 @@ class StixCyberObservableTypes(Enum):
|
|
|
48
48
|
PERSONA = "Persona"
|
|
49
49
|
|
|
50
50
|
@classmethod
|
|
51
|
-
def has_value(cls, value):
|
|
51
|
+
def has_value(cls, value: str) -> bool:
|
|
52
52
|
lower_attr = list(map(lambda x: x.lower(), cls._value2member_map_))
|
|
53
53
|
return value.lower() in lower_attr
|
|
54
54
|
|
|
@@ -58,6 +58,7 @@ class IdentityTypes(Enum):
|
|
|
58
58
|
ORGANIZATION = "Organization"
|
|
59
59
|
INDIVIDUAL = "Individual"
|
|
60
60
|
SYSTEM = "System"
|
|
61
|
+
SECURITYPLATFORM = "SecurityPlatform"
|
|
61
62
|
|
|
62
63
|
@classmethod
|
|
63
64
|
def has_value(cls, value):
|
pycti/utils/opencti_stix2.py
CHANGED
|
@@ -29,7 +29,9 @@ from pycti.utils.opencti_stix2_splitter import OpenCTIStix2Splitter
|
|
|
29
29
|
from pycti.utils.opencti_stix2_update import OpenCTIStix2Update
|
|
30
30
|
from pycti.utils.opencti_stix2_utils import (
|
|
31
31
|
OBSERVABLES_VALUE_INT,
|
|
32
|
+
STIX_CORE_OBJECTS,
|
|
32
33
|
STIX_CYBER_OBSERVABLE_MAPPING,
|
|
34
|
+
STIX_META_OBJECTS,
|
|
33
35
|
)
|
|
34
36
|
|
|
35
37
|
datefinder.ValueError = ValueError, OverflowError
|
|
@@ -418,7 +420,10 @@ class OpenCTIStix2:
|
|
|
418
420
|
stix_object["kill_chain_phases"] = self.opencti.get_attribute_in_extension(
|
|
419
421
|
"kill_chain_phases", stix_object
|
|
420
422
|
)
|
|
421
|
-
if
|
|
423
|
+
if (
|
|
424
|
+
"kill_chain_phases" in stix_object
|
|
425
|
+
and stix_object["kill_chain_phases"] is not None
|
|
426
|
+
):
|
|
422
427
|
for kill_chain_phase in stix_object["kill_chain_phases"]:
|
|
423
428
|
if (
|
|
424
429
|
kill_chain_phase["kill_chain_name"] + kill_chain_phase["phase_name"]
|
|
@@ -461,7 +466,10 @@ class OpenCTIStix2:
|
|
|
461
466
|
"type": kill_chain_phase["entity_type"],
|
|
462
467
|
}
|
|
463
468
|
kill_chain_phases_ids.append(kill_chain_phase["id"])
|
|
464
|
-
elif
|
|
469
|
+
elif (
|
|
470
|
+
"x_opencti_kill_chain_phases" in stix_object
|
|
471
|
+
and stix_object["x_opencti_kill_chain_phases"] is not None
|
|
472
|
+
):
|
|
465
473
|
for kill_chain_phase in stix_object["x_opencti_kill_chain_phases"]:
|
|
466
474
|
if (
|
|
467
475
|
kill_chain_phase["kill_chain_name"] + kill_chain_phase["phase_name"]
|
|
@@ -523,7 +531,10 @@ class OpenCTIStix2:
|
|
|
523
531
|
"external_references", stix_object
|
|
524
532
|
)
|
|
525
533
|
)
|
|
526
|
-
if
|
|
534
|
+
if (
|
|
535
|
+
"external_references" in stix_object
|
|
536
|
+
and stix_object["external_references"] is not None
|
|
537
|
+
):
|
|
527
538
|
for external_reference in stix_object["external_references"]:
|
|
528
539
|
try:
|
|
529
540
|
url = (
|
|
@@ -704,7 +715,10 @@ class OpenCTIStix2:
|
|
|
704
715
|
self.opencti.app_logger.warning(
|
|
705
716
|
"Cannot generate external reference"
|
|
706
717
|
)
|
|
707
|
-
elif
|
|
718
|
+
elif (
|
|
719
|
+
"x_opencti_external_references" in stix_object
|
|
720
|
+
and stix_object["x_opencti_external_references"] is not None
|
|
721
|
+
):
|
|
708
722
|
for external_reference in stix_object["x_opencti_external_references"]:
|
|
709
723
|
url = external_reference["url"] if "url" in external_reference else None
|
|
710
724
|
source_name = (
|
|
@@ -773,7 +787,10 @@ class OpenCTIStix2:
|
|
|
773
787
|
granted_refs_ids = self.opencti.get_attribute_in_extension(
|
|
774
788
|
"granted_refs", stix_object
|
|
775
789
|
)
|
|
776
|
-
elif
|
|
790
|
+
elif (
|
|
791
|
+
"x_opencti_granted_refs" in stix_object
|
|
792
|
+
and stix_object["x_opencti_granted_refs"] is not None
|
|
793
|
+
):
|
|
777
794
|
granted_refs_ids = stix_object["x_opencti_granted_refs"]
|
|
778
795
|
# Sample refs
|
|
779
796
|
sample_refs_ids = (
|
|
@@ -909,6 +926,23 @@ class OpenCTIStix2:
|
|
|
909
926
|
"sighting": self.opencti.stix_sighting_relationship,
|
|
910
927
|
}
|
|
911
928
|
|
|
929
|
+
def get_internal_helper(self):
|
|
930
|
+
# Import
|
|
931
|
+
return {
|
|
932
|
+
"user": self.opencti.user,
|
|
933
|
+
"group": self.opencti.group,
|
|
934
|
+
"capability": self.opencti.capability,
|
|
935
|
+
"role": self.opencti.role,
|
|
936
|
+
"settings": self.opencti.settings,
|
|
937
|
+
"work": self.opencti.work,
|
|
938
|
+
"deleteoperation": self.opencti.trash,
|
|
939
|
+
"draftworkspace": self.opencti.draft,
|
|
940
|
+
"playbook": self.opencti.playbook,
|
|
941
|
+
"workspace": self.opencti.workspace,
|
|
942
|
+
"publicdashboard": self.opencti.public_dashboard,
|
|
943
|
+
"notification": self.opencti.notification,
|
|
944
|
+
}
|
|
945
|
+
|
|
912
946
|
def generate_standard_id_from_stix(self, data):
|
|
913
947
|
stix_helpers = self.get_stix_helper()
|
|
914
948
|
helper = stix_helpers.get(data["type"])
|
|
@@ -2468,24 +2502,173 @@ class OpenCTIStix2:
|
|
|
2468
2502
|
self.opencti.external_reference.update_field(
|
|
2469
2503
|
id=item_id, input=field_patch_without_files
|
|
2470
2504
|
)
|
|
2505
|
+
elif item["type"] == "indicator":
|
|
2506
|
+
self.opencti.indicator.update_field(
|
|
2507
|
+
id=item_id, input=field_patch_without_files
|
|
2508
|
+
)
|
|
2509
|
+
elif item["type"] == "notification":
|
|
2510
|
+
self.opencti.notification.update_field(
|
|
2511
|
+
id=item_id, input=field_patch_without_files
|
|
2512
|
+
)
|
|
2471
2513
|
else:
|
|
2472
2514
|
self.opencti.stix_domain_object.update_field(
|
|
2473
2515
|
id=item_id, input=field_patch_without_files
|
|
2474
2516
|
)
|
|
2475
2517
|
self.apply_patch_files(item)
|
|
2476
2518
|
|
|
2519
|
+
def rule_apply(self, item):
|
|
2520
|
+
rule_id = self.opencti.get_attribute_in_extension("opencti_rule", item)
|
|
2521
|
+
if rule_id is None:
|
|
2522
|
+
rule_id = item["opencti_rule"]
|
|
2523
|
+
self.opencti.stix_core_object.rule_apply(element_id=item["id"], rule_id=rule_id)
|
|
2524
|
+
|
|
2525
|
+
def rule_clear(self, item):
|
|
2526
|
+
rule_id = self.opencti.get_attribute_in_extension("opencti_rule", item)
|
|
2527
|
+
if rule_id is None:
|
|
2528
|
+
rule_id = item["opencti_rule"]
|
|
2529
|
+
self.opencti.stix_core_object.rule_clear(element_id=item["id"], rule_id=rule_id)
|
|
2530
|
+
|
|
2531
|
+
def rules_rescan(self, item):
|
|
2532
|
+
self.opencti.stix_core_object.rules_rescan(element_id=item["id"])
|
|
2533
|
+
|
|
2534
|
+
def organization_share(self, item):
|
|
2535
|
+
organization_ids = self.opencti.get_attribute_in_extension(
|
|
2536
|
+
"sharing_organization_ids", item
|
|
2537
|
+
)
|
|
2538
|
+
if organization_ids is None:
|
|
2539
|
+
organization_ids = item["sharing_organization_ids"]
|
|
2540
|
+
sharing_direct_container = self.opencti.get_attribute_in_extension(
|
|
2541
|
+
"sharing_direct_container", item
|
|
2542
|
+
)
|
|
2543
|
+
if sharing_direct_container is None:
|
|
2544
|
+
sharing_direct_container = item["sharing_direct_container"]
|
|
2545
|
+
|
|
2546
|
+
if item["type"] == "relationship":
|
|
2547
|
+
self.opencti.stix_core_relationship.organization_share(
|
|
2548
|
+
item["id"], organization_ids, sharing_direct_container
|
|
2549
|
+
)
|
|
2550
|
+
elif item["type"] == "sighting":
|
|
2551
|
+
self.opencti.stix_sighting_relationship.organization_share(
|
|
2552
|
+
item["id"], organization_ids, sharing_direct_container
|
|
2553
|
+
)
|
|
2554
|
+
else:
|
|
2555
|
+
# Element is considered stix core object
|
|
2556
|
+
self.opencti.stix_core_object.organization_share(
|
|
2557
|
+
item["id"], organization_ids, sharing_direct_container
|
|
2558
|
+
)
|
|
2559
|
+
|
|
2560
|
+
def organization_unshare(self, item):
|
|
2561
|
+
organization_ids = self.opencti.get_attribute_in_extension(
|
|
2562
|
+
"sharing_organization_ids", item
|
|
2563
|
+
)
|
|
2564
|
+
if organization_ids is None:
|
|
2565
|
+
organization_ids = item["sharing_organization_ids"]
|
|
2566
|
+
sharing_direct_container = self.opencti.get_attribute_in_extension(
|
|
2567
|
+
"sharing_direct_container", item
|
|
2568
|
+
)
|
|
2569
|
+
if sharing_direct_container is None:
|
|
2570
|
+
sharing_direct_container = item["sharing_direct_container"]
|
|
2571
|
+
if item["type"] == "relationship":
|
|
2572
|
+
self.opencti.stix_core_relationship.organization_unshare(
|
|
2573
|
+
item["id"], organization_ids, sharing_direct_container
|
|
2574
|
+
)
|
|
2575
|
+
elif item["type"] == "sighting":
|
|
2576
|
+
self.opencti.stix_sighting_relationship.organization_unshare(
|
|
2577
|
+
item["id"], organization_ids, sharing_direct_container
|
|
2578
|
+
)
|
|
2579
|
+
else:
|
|
2580
|
+
# Element is considered stix core object
|
|
2581
|
+
self.opencti.stix_core_object.organization_unshare(
|
|
2582
|
+
item["id"], organization_ids, sharing_direct_container
|
|
2583
|
+
)
|
|
2584
|
+
|
|
2585
|
+
def element_operation_delete(self, item, operation):
|
|
2586
|
+
# If data is stix, just use the generic stix function for deletion
|
|
2587
|
+
force_delete = operation == "delete_force"
|
|
2588
|
+
if item["type"] == "relationship":
|
|
2589
|
+
self.opencti.stix_core_relationship.delete(id=item["id"])
|
|
2590
|
+
elif item["type"] == "sighting":
|
|
2591
|
+
self.opencti.stix_sighting_relationship.delete(id=item["id"])
|
|
2592
|
+
elif item["type"] in STIX_META_OBJECTS:
|
|
2593
|
+
self.opencti.stix.delete(id=item["id"], force_delete=force_delete)
|
|
2594
|
+
elif item["type"] in list(STIX_CYBER_OBSERVABLE_MAPPING.keys()):
|
|
2595
|
+
self.opencti.stix_cyber_observable.delete(id=item["id"])
|
|
2596
|
+
elif item["type"] in STIX_CORE_OBJECTS:
|
|
2597
|
+
self.opencti.stix_core_object.delete(id=item["id"])
|
|
2598
|
+
else:
|
|
2599
|
+
# Element is not knowledge we need to use the right api
|
|
2600
|
+
stix_helper = self.get_internal_helper().get(item["type"])
|
|
2601
|
+
if stix_helper and hasattr(stix_helper, "delete"):
|
|
2602
|
+
stix_helper.delete(id=item["id"])
|
|
2603
|
+
else:
|
|
2604
|
+
raise ValueError(
|
|
2605
|
+
"Delete operation or not found stix helper", {"type": item["type"]}
|
|
2606
|
+
)
|
|
2607
|
+
|
|
2608
|
+
def element_remove_from_draft(self, item):
|
|
2609
|
+
if item["type"] == "relationship":
|
|
2610
|
+
self.opencti.stix_core_relationship.remove_from_draft(id=item["id"])
|
|
2611
|
+
elif item["type"] == "sighting":
|
|
2612
|
+
self.opencti.stix_sighting_relationship.remove_from_draft(id=item["id"])
|
|
2613
|
+
else:
|
|
2614
|
+
# Element is considered stix core object
|
|
2615
|
+
self.opencti.stix_core_object.remove_from_draft(id=item["id"])
|
|
2616
|
+
|
|
2477
2617
|
def apply_opencti_operation(self, item, operation):
|
|
2478
|
-
if operation == "delete":
|
|
2479
|
-
|
|
2480
|
-
|
|
2618
|
+
if operation == "delete" or operation == "delete_force":
|
|
2619
|
+
self.element_operation_delete(item=item, operation=operation)
|
|
2620
|
+
elif operation == "revert_draft":
|
|
2621
|
+
self.element_remove_from_draft(item=item)
|
|
2622
|
+
elif operation == "restore":
|
|
2623
|
+
self.opencti.trash.restore(item["id"])
|
|
2481
2624
|
elif operation == "merge":
|
|
2482
|
-
target_id =
|
|
2483
|
-
|
|
2625
|
+
target_id = self.opencti.get_attribute_in_extension("merge_target_id", item)
|
|
2626
|
+
if target_id is None:
|
|
2627
|
+
target_id = item["merge_target_id"]
|
|
2628
|
+
source_ids = self.opencti.get_attribute_in_extension(
|
|
2629
|
+
"merge_source_ids", item
|
|
2630
|
+
)
|
|
2631
|
+
if source_ids is None:
|
|
2632
|
+
source_ids = item["merge_source_ids"]
|
|
2484
2633
|
self.opencti.stix.merge(id=target_id, object_ids=source_ids)
|
|
2485
2634
|
elif operation == "patch":
|
|
2486
2635
|
self.apply_patch(item=item)
|
|
2636
|
+
elif operation == "pir_flag_element":
|
|
2637
|
+
id = item["id"]
|
|
2638
|
+
input = item["input"]
|
|
2639
|
+
self.opencti.pir.pir_flag_element(id=id, input=input)
|
|
2640
|
+
elif operation == "pir_unflag_element":
|
|
2641
|
+
id = item["id"]
|
|
2642
|
+
input = item["input"]
|
|
2643
|
+
self.opencti.pir.pir_unflag_element(id=id, input=input)
|
|
2644
|
+
elif operation == "rule_apply":
|
|
2645
|
+
self.rule_apply(item=item)
|
|
2646
|
+
elif operation == "rule_clear":
|
|
2647
|
+
self.rule_clear(item=item)
|
|
2648
|
+
elif operation == "rules_rescan":
|
|
2649
|
+
self.rules_rescan(item=item)
|
|
2650
|
+
elif operation == "share":
|
|
2651
|
+
self.organization_share(item=item)
|
|
2652
|
+
elif operation == "unshare":
|
|
2653
|
+
self.organization_unshare(item=item)
|
|
2654
|
+
elif operation == "clear_access_restriction":
|
|
2655
|
+
self.opencti.stix_core_object.clear_access_restriction(
|
|
2656
|
+
element_id=item["id"]
|
|
2657
|
+
)
|
|
2658
|
+
elif operation == "enrichment":
|
|
2659
|
+
connector_ids = self.opencti.get_attribute_in_extension(
|
|
2660
|
+
"connector_ids", item
|
|
2661
|
+
)
|
|
2662
|
+
if connector_ids is None:
|
|
2663
|
+
connector_ids = item["connector_ids"]
|
|
2664
|
+
self.opencti.stix_core_object.ask_enrichments(
|
|
2665
|
+
element_id=item["id"], connector_ids=connector_ids
|
|
2666
|
+
)
|
|
2487
2667
|
else:
|
|
2488
|
-
raise ValueError(
|
|
2668
|
+
raise ValueError(
|
|
2669
|
+
"Not supported opencti_operation",
|
|
2670
|
+
{"operation": operation},
|
|
2671
|
+
)
|
|
2489
2672
|
|
|
2490
2673
|
def import_item(
|
|
2491
2674
|
self,
|
|
@@ -2748,9 +2931,25 @@ class OpenCTIStix2:
|
|
|
2748
2931
|
)
|
|
2749
2932
|
|
|
2750
2933
|
stix2_splitter = OpenCTIStix2Splitter()
|
|
2751
|
-
_, bundles =
|
|
2752
|
-
|
|
2934
|
+
_, incompatible_elements, bundles = (
|
|
2935
|
+
stix2_splitter.split_bundle_with_expectations(
|
|
2936
|
+
stix_bundle, False, event_version
|
|
2937
|
+
)
|
|
2753
2938
|
)
|
|
2939
|
+
|
|
2940
|
+
# Report every element ignored during bundle splitting
|
|
2941
|
+
if work_id is not None:
|
|
2942
|
+
for incompatible_element in incompatible_elements:
|
|
2943
|
+
self.opencti.work.report_expectation(
|
|
2944
|
+
work_id,
|
|
2945
|
+
{
|
|
2946
|
+
"error": "Incompatible element in bundle",
|
|
2947
|
+
"source": "Element "
|
|
2948
|
+
+ incompatible_element["id"]
|
|
2949
|
+
+ " is incompatible and couldn't be processed",
|
|
2950
|
+
},
|
|
2951
|
+
)
|
|
2952
|
+
|
|
2754
2953
|
# Import every element in a specific order
|
|
2755
2954
|
imported_elements = []
|
|
2756
2955
|
for bundle in bundles:
|
|
@@ -10,6 +10,7 @@ from pycti.utils.opencti_stix2_identifier import (
|
|
|
10
10
|
)
|
|
11
11
|
from pycti.utils.opencti_stix2_utils import (
|
|
12
12
|
STIX_CYBER_OBSERVABLE_MAPPING,
|
|
13
|
+
SUPPORTED_INTERNAL_OBJECTS,
|
|
13
14
|
SUPPORTED_STIX_ENTITY_OBJECTS,
|
|
14
15
|
)
|
|
15
16
|
|
|
@@ -17,8 +18,10 @@ OPENCTI_EXTENSION = "extension-definition--ea279b3e-5c71-4632-ac08-831c66a786ba"
|
|
|
17
18
|
|
|
18
19
|
supported_types = (
|
|
19
20
|
SUPPORTED_STIX_ENTITY_OBJECTS # entities
|
|
21
|
+
+ SUPPORTED_INTERNAL_OBJECTS # internals
|
|
20
22
|
+ list(STIX_CYBER_OBSERVABLE_MAPPING.keys()) # observables
|
|
21
23
|
+ ["relationship", "sighting"] # relationships
|
|
24
|
+
+ ["pir"]
|
|
22
25
|
)
|
|
23
26
|
|
|
24
27
|
|
|
@@ -35,6 +38,7 @@ class OpenCTIStix2Splitter:
|
|
|
35
38
|
self.cache_index = {}
|
|
36
39
|
self.cache_refs = {}
|
|
37
40
|
self.elements = []
|
|
41
|
+
self.incompatible_items = []
|
|
38
42
|
|
|
39
43
|
def get_internal_ids_in_extension(self, item):
|
|
40
44
|
ids = []
|
|
@@ -65,7 +69,7 @@ class OpenCTIStix2Splitter:
|
|
|
65
69
|
for key in list(item.keys()):
|
|
66
70
|
value = item[key]
|
|
67
71
|
# Recursive enlist for every refs
|
|
68
|
-
if key.endswith("_refs"):
|
|
72
|
+
if key.endswith("_refs") and item[key] is not None:
|
|
69
73
|
to_keep = []
|
|
70
74
|
for element_ref in item[key]:
|
|
71
75
|
# We need to check if this ref is not already a reference
|
|
@@ -119,7 +123,7 @@ class OpenCTIStix2Splitter:
|
|
|
119
123
|
else:
|
|
120
124
|
item[key] = None
|
|
121
125
|
# Case for embedded elements (deduplicating and cleanup)
|
|
122
|
-
elif key == "external_references":
|
|
126
|
+
elif key == "external_references" and item[key] is not None:
|
|
123
127
|
# specific case of splitting external references
|
|
124
128
|
# reference_ids = []
|
|
125
129
|
deduplicated_references = []
|
|
@@ -145,7 +149,7 @@ class OpenCTIStix2Splitter:
|
|
|
145
149
|
# reference_ids.append(reference_id)
|
|
146
150
|
# nb_deps += self.enlist_element(reference_id, raw_data)
|
|
147
151
|
item[key] = deduplicated_references
|
|
148
|
-
elif key == "kill_chain_phases":
|
|
152
|
+
elif key == "kill_chain_phases" and item[key] is not None:
|
|
149
153
|
# specific case of splitting kill_chain phases
|
|
150
154
|
# kill_chain_ids = []
|
|
151
155
|
deduplicated_kill_chain = []
|
|
@@ -189,6 +193,8 @@ class OpenCTIStix2Splitter:
|
|
|
189
193
|
is_compatible = is_id_supported(item_id)
|
|
190
194
|
if is_compatible:
|
|
191
195
|
self.elements.append(item)
|
|
196
|
+
else:
|
|
197
|
+
self.incompatible_items.append(item)
|
|
192
198
|
self.cache_index[item_id] = item
|
|
193
199
|
for internal_id in self.get_internal_ids_in_extension(item):
|
|
194
200
|
self.cache_index[internal_id] = item
|
|
@@ -201,7 +207,7 @@ class OpenCTIStix2Splitter:
|
|
|
201
207
|
use_json=True,
|
|
202
208
|
event_version=None,
|
|
203
209
|
cleanup_inconsistent_bundle=False,
|
|
204
|
-
) -> Tuple[int, list]:
|
|
210
|
+
) -> Tuple[int, list, list]:
|
|
205
211
|
"""splits a valid stix2 bundle into a list of bundles"""
|
|
206
212
|
if use_json:
|
|
207
213
|
try:
|
|
@@ -251,11 +257,11 @@ class OpenCTIStix2Splitter:
|
|
|
251
257
|
)
|
|
252
258
|
)
|
|
253
259
|
|
|
254
|
-
return number_expectations, bundles
|
|
260
|
+
return number_expectations, self.incompatible_items, bundles
|
|
255
261
|
|
|
256
262
|
@deprecated("Use split_bundle_with_expectations instead")
|
|
257
263
|
def split_bundle(self, bundle, use_json=True, event_version=None) -> list:
|
|
258
|
-
|
|
264
|
+
_, _, bundles = self.split_bundle_with_expectations(
|
|
259
265
|
bundle, use_json, event_version
|
|
260
266
|
)
|
|
261
267
|
return bundles
|
|
@@ -2,7 +2,29 @@ from typing import Any, Dict
|
|
|
2
2
|
|
|
3
3
|
from stix2 import EqualityComparisonExpression, ObjectPath, ObservationExpression
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
SUPPORTED_INTERNAL_OBJECTS = [
|
|
6
|
+
"user",
|
|
7
|
+
"group",
|
|
8
|
+
"capability",
|
|
9
|
+
"role",
|
|
10
|
+
"settings",
|
|
11
|
+
"notification",
|
|
12
|
+
"work",
|
|
13
|
+
"trash",
|
|
14
|
+
"draftworkspace",
|
|
15
|
+
"playbook",
|
|
16
|
+
"deleteoperation",
|
|
17
|
+
"workspace",
|
|
18
|
+
"publicdashboard",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
STIX_META_OBJECTS = [
|
|
22
|
+
"label",
|
|
23
|
+
"vocabulary",
|
|
24
|
+
"kill-chain-phase",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
STIX_CORE_OBJECTS = [
|
|
6
28
|
"attack-pattern",
|
|
7
29
|
"campaign",
|
|
8
30
|
"case-incident",
|
|
@@ -27,8 +49,6 @@ SUPPORTED_STIX_ENTITY_OBJECTS = [
|
|
|
27
49
|
"indicator",
|
|
28
50
|
"infrastructure",
|
|
29
51
|
"intrusion-set",
|
|
30
|
-
"kill-chain-phase",
|
|
31
|
-
"label",
|
|
32
52
|
"language",
|
|
33
53
|
"location",
|
|
34
54
|
"malware",
|
|
@@ -43,10 +63,11 @@ SUPPORTED_STIX_ENTITY_OBJECTS = [
|
|
|
43
63
|
"x-opencti-task",
|
|
44
64
|
"threat-actor",
|
|
45
65
|
"tool",
|
|
46
|
-
"vocabulary",
|
|
47
66
|
"vulnerability",
|
|
48
67
|
]
|
|
49
68
|
|
|
69
|
+
SUPPORTED_STIX_ENTITY_OBJECTS = STIX_META_OBJECTS + STIX_CORE_OBJECTS
|
|
70
|
+
|
|
50
71
|
STIX_CYBER_OBSERVABLE_MAPPING = {
|
|
51
72
|
"autonomous-system": "Autonomous-System",
|
|
52
73
|
"directory": "Directory",
|
|
@@ -83,6 +104,12 @@ STIX_CYBER_OBSERVABLE_MAPPING = {
|
|
|
83
104
|
"persona": "Persona",
|
|
84
105
|
}
|
|
85
106
|
|
|
107
|
+
STIX_OBJECTS = (
|
|
108
|
+
SUPPORTED_STIX_ENTITY_OBJECTS # entities
|
|
109
|
+
+ list(STIX_CYBER_OBSERVABLE_MAPPING.keys()) # observables
|
|
110
|
+
+ ["relationship", "sighting"] # relationships
|
|
111
|
+
)
|
|
112
|
+
|
|
86
113
|
PATTERN_MAPPING = {
|
|
87
114
|
"Autonomous-System": ["number"],
|
|
88
115
|
"Directory": ["path"],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycti
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.7.0
|
|
4
4
|
Summary: Python API client for OpenCTI.
|
|
5
5
|
Home-page: https://github.com/OpenCTI-Platform/client-python
|
|
6
6
|
Author: Filigran
|
|
@@ -29,7 +29,7 @@ Requires-Dist: python-magic-bin~=0.4.14; sys_platform == "win32"
|
|
|
29
29
|
Requires-Dist: python_json_logger~=3.3.0
|
|
30
30
|
Requires-Dist: PyYAML~=6.0
|
|
31
31
|
Requires-Dist: requests~=2.32.3
|
|
32
|
-
Requires-Dist: setuptools~=
|
|
32
|
+
Requires-Dist: setuptools~=80.9.0
|
|
33
33
|
Requires-Dist: cachetools~=5.5.0
|
|
34
34
|
Requires-Dist: prometheus-client~=0.21.1
|
|
35
35
|
Requires-Dist: opentelemetry-api~=1.32.0
|
|
@@ -46,9 +46,9 @@ Requires-Dist: isort~=6.0.0; extra == "dev"
|
|
|
46
46
|
Requires-Dist: types-pytz~=2025.2.0.20250326; extra == "dev"
|
|
47
47
|
Requires-Dist: pre-commit~=4.2.0; extra == "dev"
|
|
48
48
|
Requires-Dist: pytest-cases~=3.8.0; extra == "dev"
|
|
49
|
-
Requires-Dist: pytest-cov~=6.
|
|
49
|
+
Requires-Dist: pytest-cov~=6.2.1; extra == "dev"
|
|
50
50
|
Requires-Dist: pytest_randomly~=3.16.0; extra == "dev"
|
|
51
|
-
Requires-Dist: pytest~=8.
|
|
51
|
+
Requires-Dist: pytest~=8.4.1; extra == "dev"
|
|
52
52
|
Requires-Dist: types-python-dateutil~=2.9.0; extra == "dev"
|
|
53
53
|
Requires-Dist: wheel~=0.45.1; extra == "dev"
|
|
54
54
|
Provides-Extra: doc
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
pycti/__init__.py,sha256=
|
|
1
|
+
pycti/__init__.py,sha256=BQeMBUpJroFUdRqvvmrtA2LxiUu0IbYvX4_oGT-G6Fo,5676
|
|
2
2
|
pycti/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
pycti/api/opencti_api_client.py,sha256=
|
|
3
|
+
pycti/api/opencti_api_client.py,sha256=EKv6nKNHPNMzF_dBoeZXsO5NJWH-nWH6GN-BFdWH-3s,35239
|
|
4
4
|
pycti/api/opencti_api_connector.py,sha256=8xwHuLINP3ZCImzE9_K_iCR9QEA3K6aHpK4bJhcZf20,5582
|
|
5
|
-
pycti/api/
|
|
6
|
-
pycti/api/
|
|
5
|
+
pycti/api/opencti_api_draft.py,sha256=ZFrva6p7VZA7rCtIpyfyA-KTWvcTaWvpy51_Edi9rG4,428
|
|
6
|
+
pycti/api/opencti_api_notification.py,sha256=uTBSjym2RfSYHTnfBIVmWj5kATrzQ2lRQ178Jy5bsu0,1375
|
|
7
|
+
pycti/api/opencti_api_pir.py,sha256=3yDfUNVe9G_G9OrCcL3pBTE31kcstKXhXCiSrGhpUYY,992
|
|
8
|
+
pycti/api/opencti_api_playbook.py,sha256=9I_x_S4_pj12QUK0x5qC_7sl0-i8AHKtyAb9P0-fCr8,2187
|
|
9
|
+
pycti/api/opencti_api_public_dashboard.py,sha256=aa4trEuaf7WstmiS4WAHoe1qmYmaFWmbO0N4N_iXPGM,711
|
|
10
|
+
pycti/api/opencti_api_trash.py,sha256=r_zi57n5TfLw9LYs2UFg33Nvyy3Huc6CjpK2mRQsmao,1065
|
|
11
|
+
pycti/api/opencti_api_work.py,sha256=uV1mbPz3zmNZjoNHVmX6SyWPQKEHkpSDXkb_a2NIOA4,8982
|
|
12
|
+
pycti/api/opencti_api_workspace.py,sha256=ycqOTEXeUHF2k8H4jhoYDd1W6ijFcNUjYf4eSdLpH0k,611
|
|
7
13
|
pycti/connector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
14
|
pycti/connector/opencti_connector.py,sha256=8lCZFvcA9-S1x6vFl756hgWAlzKfrnq-C4AIdDJr-Kg,2715
|
|
9
|
-
pycti/connector/opencti_connector_helper.py,sha256=
|
|
15
|
+
pycti/connector/opencti_connector_helper.py,sha256=JAmoPXjBv_35aMrwVBwtavpkv9bMBfOj64EEYigz8vg,88546
|
|
10
16
|
pycti/connector/opencti_metric_handler.py,sha256=4jXHeJflomtHjuQ_YU0b36TG7o26vOWbY_jvU8Ezobs,3725
|
|
11
17
|
pycti/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
18
|
pycti/entities/opencti_attack_pattern.py,sha256=HVfLhtd8rlT42xutRS8qOkDsG5_Ws4EoGfObLW5mQl4,22535
|
|
@@ -22,11 +28,11 @@ pycti/entities/opencti_data_source.py,sha256=OqgeOkQl463aREDb8CkFwVrYngKTNYnUTyg
|
|
|
22
28
|
pycti/entities/opencti_event.py,sha256=lGqxCnurlcbIXDMdKIFI2gaxjq2LNJoj8k8HGQnKHXo,17099
|
|
23
29
|
pycti/entities/opencti_external_reference.py,sha256=zSsGOUajrTgSG9T0MHUzq-16XalJ0BHHC54RvBaTD48,13524
|
|
24
30
|
pycti/entities/opencti_feedback.py,sha256=MyFs1CuC6_SZvjLOPyWwe6mWMoUmyoGKJ73o237j-Mg,32710
|
|
25
|
-
pycti/entities/opencti_group.py,sha256=
|
|
31
|
+
pycti/entities/opencti_group.py,sha256=GgtA1zZunjXjxPdXc3wOV8Veitte0IGmRF1WwFYWs80,26390
|
|
26
32
|
pycti/entities/opencti_grouping.py,sha256=cjXfgmRma0laGAP5j1oYMtZzVsQxrNvZ0o0-MsToufg,30569
|
|
27
|
-
pycti/entities/opencti_identity.py,sha256=
|
|
33
|
+
pycti/entities/opencti_identity.py,sha256=Ih2LvYrDKXXFoQOjcsFv0ipTW3PBCtNtrBkyGWU-__8,26703
|
|
28
34
|
pycti/entities/opencti_incident.py,sha256=mQn2PN2enf9CYoM2vFD3f8S2hIZj8pbiBUZOQ4cMT7Q,18966
|
|
29
|
-
pycti/entities/opencti_indicator.py,sha256=
|
|
35
|
+
pycti/entities/opencti_indicator.py,sha256=DX-erowuSw3yfAGacIK5CGKUsIhiUfoTER8NwVH7myI,22732
|
|
30
36
|
pycti/entities/opencti_infrastructure.py,sha256=-vuGCDiwWH60GmLOpUelVDPtvM9XB9DhfGDwM0S2OpI,20331
|
|
31
37
|
pycti/entities/opencti_intrusion_set.py,sha256=Jg-kkh6_kfyUIL6XsRYWg_d7Nejrp9kniJlI-SlAph0,19357
|
|
32
38
|
pycti/entities/opencti_kill_chain_phase.py,sha256=acNzuFdxhwI_8fvZOTEHhP8fC6EGY_r6jcKpA-nKa8Q,7991
|
|
@@ -43,14 +49,14 @@ pycti/entities/opencti_opinion.py,sha256=QwYIcRemOmFVmoVHRnCEUGzSt4NoIHufCU_qh0D
|
|
|
43
49
|
pycti/entities/opencti_report.py,sha256=LY2wB6zcdchBD8URYoNqGWENMqnalOrmxoNKz306EDM,35303
|
|
44
50
|
pycti/entities/opencti_role.py,sha256=ryfPmZ_ch2sRGgqEr6_qxChTcGoeqvHW0MvlGHkLgdw,14039
|
|
45
51
|
pycti/entities/opencti_settings.py,sha256=3dArFaPPdcFTV44uGRffjHpnDE-MKIXgd496QZcH6Bw,13547
|
|
46
|
-
pycti/entities/opencti_stix.py,sha256=
|
|
47
|
-
pycti/entities/opencti_stix_core_object.py,sha256=
|
|
48
|
-
pycti/entities/opencti_stix_core_relationship.py,sha256=
|
|
52
|
+
pycti/entities/opencti_stix.py,sha256=9jVg21hXXaKMl5U8Mh6Df3U8IIjP7k9py5VGzn1qFzk,2410
|
|
53
|
+
pycti/entities/opencti_stix_core_object.py,sha256=1E7yRR18_y4dYGcv5ZSAIcusMUh_hAW9QEujNRHwbPg,63413
|
|
54
|
+
pycti/entities/opencti_stix_core_relationship.py,sha256=aqguOR9n9jyL7Ez7xRoAO5EQ3wA6XcgTXxrYDGjw3cI,47786
|
|
49
55
|
pycti/entities/opencti_stix_cyber_observable.py,sha256=ZbJ4XXXTlCP34hrgC9Jfov_9m1bPUiTj_s2tUjSauEA,92449
|
|
50
|
-
pycti/entities/opencti_stix_domain_object.py,sha256
|
|
56
|
+
pycti/entities/opencti_stix_domain_object.py,sha256=f-n_4i1uNkSBT6f2UD8isgB_OR2MbQwhN56Ypp_5Dd8,82748
|
|
51
57
|
pycti/entities/opencti_stix_nested_ref_relationship.py,sha256=7USJlfTanPFY16aFIH2YONdRakrfoBuIbB0d0I52PSM,12479
|
|
52
|
-
pycti/entities/opencti_stix_object_or_stix_relationship.py,sha256=
|
|
53
|
-
pycti/entities/opencti_stix_sighting_relationship.py,sha256=
|
|
58
|
+
pycti/entities/opencti_stix_object_or_stix_relationship.py,sha256=7USO_fkHkiXBMMalQee1ZNIE99IJfFUmzVRFBvRrdOo,19998
|
|
59
|
+
pycti/entities/opencti_stix_sighting_relationship.py,sha256=JZo9t_nyF2psVZ3Flg6Gkyf3gD5422kQLAByr1qiBAs,31720
|
|
54
60
|
pycti/entities/opencti_task.py,sha256=QOGuPTpH5rI80i9kwhHJ7Lgdr6bKTdAs-jwQ3kQ2Yjo,25457
|
|
55
61
|
pycti/entities/opencti_threat_actor.py,sha256=vFPeo0pOYSqHBKVlWc4o8RjuP2PP0A09KWU6rsYXnvA,11201
|
|
56
62
|
pycti/entities/opencti_threat_actor_group.py,sha256=dV28sDfADoDpATyk8w2fN1ZGOoad3LCk7lnij3nFBY8,20828
|
|
@@ -58,22 +64,22 @@ pycti/entities/opencti_threat_actor_individual.py,sha256=l-E0RShOofXTZgw2HUyrDpr
|
|
|
58
64
|
pycti/entities/opencti_tool.py,sha256=GXeTfWkTgNxFnNGPsO03BOK2dsZGCp5IT-leQHiFWtw,15462
|
|
59
65
|
pycti/entities/opencti_user.py,sha256=zJKhJCvC2N5-3E92uFad2CwiQhCWVAHYrgomzqBwD-s,29735
|
|
60
66
|
pycti/entities/opencti_vocabulary.py,sha256=xupdHJ6TznCmvI3sVYU261SnfblSNc1nwg19MG9yrao,6499
|
|
61
|
-
pycti/entities/opencti_vulnerability.py,sha256=
|
|
67
|
+
pycti/entities/opencti_vulnerability.py,sha256=roG0TPPfGRbkp1qZF7W7bqqcKxafDUX5Y33wPF4St8g,52240
|
|
62
68
|
pycti/entities/indicator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
69
|
pycti/entities/indicator/opencti_indicator_properties.py,sha256=iQvSeMHB-vSTzINnRxqIJfC3OgMHyhbXUVF2juU7DoE,5219
|
|
64
70
|
pycti/entities/stix_cyber_observable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
71
|
pycti/entities/stix_cyber_observable/opencti_stix_cyber_observable_deprecated.py,sha256=q-2G6OOqvUC1U2hSKxD8uT5T18M_IDkl72Tn1KoumQI,1847
|
|
66
72
|
pycti/entities/stix_cyber_observable/opencti_stix_cyber_observable_properties.py,sha256=MN56CW8RWZwB0Pr8UiHZy_4nSzbgFbwdhSFKpsZ_d1Y,11293
|
|
67
73
|
pycti/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
|
-
pycti/utils/constants.py,sha256=
|
|
74
|
+
pycti/utils/constants.py,sha256=VRYRvDm6hkTR0ZcHHWMzQBwqlPRskYnusBpgoX0S05A,12854
|
|
69
75
|
pycti/utils/opencti_logger.py,sha256=BHNy9fJuTUTn_JEYSCmyvVwd6y-9ZJKxO40mY4iZ0bc,2226
|
|
70
|
-
pycti/utils/opencti_stix2.py,sha256=
|
|
76
|
+
pycti/utils/opencti_stix2.py,sha256=BzD5R2EqZWgyVMkqc6_TJfvlpSHFsF1KjebwCFZ-EYE,130062
|
|
71
77
|
pycti/utils/opencti_stix2_identifier.py,sha256=k8L1z4q1xdCBfxqUba4YS_kT-MmbJFxYh0RvfGOmrOs,837
|
|
72
|
-
pycti/utils/opencti_stix2_splitter.py,sha256=
|
|
78
|
+
pycti/utils/opencti_stix2_splitter.py,sha256=sjD9mN6jEea7Zr1k17rNiYaozLcDU4qg0HgIixXRHt4,11371
|
|
73
79
|
pycti/utils/opencti_stix2_update.py,sha256=CnMyqkeVA0jgyxEcgqna8sABU4YPMjkEJ228GVurIn4,14658
|
|
74
|
-
pycti/utils/opencti_stix2_utils.py,sha256=
|
|
75
|
-
pycti-6.
|
|
76
|
-
pycti-6.
|
|
77
|
-
pycti-6.
|
|
78
|
-
pycti-6.
|
|
79
|
-
pycti-6.
|
|
80
|
+
pycti/utils/opencti_stix2_utils.py,sha256=4vu-j3weP9IS3Ky31exOIw4t3fBg00emCTRlVpevrTU,5582
|
|
81
|
+
pycti-6.7.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
82
|
+
pycti-6.7.0.dist-info/METADATA,sha256=Pn7elqBNJWq1aCOjdej2KeqjFGfV7GSsIrRb0arM5HU,5530
|
|
83
|
+
pycti-6.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
84
|
+
pycti-6.7.0.dist-info/top_level.txt,sha256=cqEpxitAhHP4VgSA6xmrak6Yk9MeBkwoMTB6k7d2ZnE,6
|
|
85
|
+
pycti-6.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|