pycti 6.6.0__py3-none-any.whl → 6.6.2__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 +13 -1
- pycti/api/opencti_api_client.py +13 -0
- pycti/connector/opencti_connector_helper.py +24 -6
- pycti/entities/opencti_capability.py +52 -0
- pycti/entities/opencti_group.py +716 -0
- pycti/entities/opencti_indicator.py +6 -0
- pycti/entities/opencti_role.py +408 -0
- pycti/entities/opencti_settings.py +385 -0
- pycti/entities/opencti_user.py +803 -0
- pycti/utils/opencti_stix2.py +90 -22
- {pycti-6.6.0.dist-info → pycti-6.6.2.dist-info}/METADATA +1 -1
- {pycti-6.6.0.dist-info → pycti-6.6.2.dist-info}/RECORD +15 -10
- {pycti-6.6.0.dist-info → pycti-6.6.2.dist-info}/WHEEL +0 -0
- {pycti-6.6.0.dist-info → pycti-6.6.2.dist-info}/licenses/LICENSE +0 -0
- {pycti-6.6.0.dist-info → pycti-6.6.2.dist-info}/top_level.txt +0 -0
pycti/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
__version__ = "6.6.
|
|
2
|
+
__version__ = "6.6.2"
|
|
3
3
|
|
|
4
4
|
from .api.opencti_api_client import OpenCTIApiClient
|
|
5
5
|
from .api.opencti_api_connector import OpenCTIApiConnector
|
|
@@ -12,6 +12,9 @@ from .connector.opencti_connector_helper import (
|
|
|
12
12
|
from .connector.opencti_metric_handler import OpenCTIMetricHandler
|
|
13
13
|
from .entities.opencti_attack_pattern import AttackPattern
|
|
14
14
|
from .entities.opencti_campaign import Campaign
|
|
15
|
+
|
|
16
|
+
# Administrative entities
|
|
17
|
+
from .entities.opencti_capability import Capability
|
|
15
18
|
from .entities.opencti_case_incident import CaseIncident
|
|
16
19
|
from .entities.opencti_case_rfi import CaseRfi
|
|
17
20
|
from .entities.opencti_case_rft import CaseRft
|
|
@@ -21,6 +24,7 @@ from .entities.opencti_data_component import DataComponent
|
|
|
21
24
|
from .entities.opencti_data_source import DataSource
|
|
22
25
|
from .entities.opencti_external_reference import ExternalReference
|
|
23
26
|
from .entities.opencti_feedback import Feedback
|
|
27
|
+
from .entities.opencti_group import Group
|
|
24
28
|
from .entities.opencti_grouping import Grouping
|
|
25
29
|
from .entities.opencti_identity import Identity
|
|
26
30
|
from .entities.opencti_incident import Incident
|
|
@@ -37,6 +41,8 @@ from .entities.opencti_note import Note
|
|
|
37
41
|
from .entities.opencti_observed_data import ObservedData
|
|
38
42
|
from .entities.opencti_opinion import Opinion
|
|
39
43
|
from .entities.opencti_report import Report
|
|
44
|
+
from .entities.opencti_role import Role
|
|
45
|
+
from .entities.opencti_settings import Settings
|
|
40
46
|
from .entities.opencti_stix_core_relationship import StixCoreRelationship
|
|
41
47
|
from .entities.opencti_stix_cyber_observable import StixCyberObservable
|
|
42
48
|
from .entities.opencti_stix_domain_object import StixDomainObject
|
|
@@ -50,6 +56,7 @@ from .entities.opencti_threat_actor import ThreatActor
|
|
|
50
56
|
from .entities.opencti_threat_actor_group import ThreatActorGroup
|
|
51
57
|
from .entities.opencti_threat_actor_individual import ThreatActorIndividual
|
|
52
58
|
from .entities.opencti_tool import Tool
|
|
59
|
+
from .entities.opencti_user import User
|
|
53
60
|
from .entities.opencti_vulnerability import Vulnerability
|
|
54
61
|
from .utils.constants import (
|
|
55
62
|
CustomObjectCaseIncident,
|
|
@@ -151,4 +158,9 @@ __all__ = [
|
|
|
151
158
|
"STIX_EXT_MITRE",
|
|
152
159
|
"STIX_EXT_OCTI_SCO",
|
|
153
160
|
"STIX_EXT_OCTI",
|
|
161
|
+
"Capability",
|
|
162
|
+
"Role",
|
|
163
|
+
"Group",
|
|
164
|
+
"User",
|
|
165
|
+
"Settings",
|
|
154
166
|
]
|
pycti/api/opencti_api_client.py
CHANGED
|
@@ -14,6 +14,7 @@ from pycti.api.opencti_api_playbook import OpenCTIApiPlaybook
|
|
|
14
14
|
from pycti.api.opencti_api_work import OpenCTIApiWork
|
|
15
15
|
from pycti.entities.opencti_attack_pattern import AttackPattern
|
|
16
16
|
from pycti.entities.opencti_campaign import Campaign
|
|
17
|
+
from pycti.entities.opencti_capability import Capability
|
|
17
18
|
from pycti.entities.opencti_case_incident import CaseIncident
|
|
18
19
|
from pycti.entities.opencti_case_rfi import CaseRfi
|
|
19
20
|
from pycti.entities.opencti_case_rft import CaseRft
|
|
@@ -24,6 +25,7 @@ from pycti.entities.opencti_data_source import DataSource
|
|
|
24
25
|
from pycti.entities.opencti_event import Event
|
|
25
26
|
from pycti.entities.opencti_external_reference import ExternalReference
|
|
26
27
|
from pycti.entities.opencti_feedback import Feedback
|
|
28
|
+
from pycti.entities.opencti_group import Group
|
|
27
29
|
from pycti.entities.opencti_grouping import Grouping
|
|
28
30
|
from pycti.entities.opencti_identity import Identity
|
|
29
31
|
from pycti.entities.opencti_incident import Incident
|
|
@@ -42,6 +44,8 @@ from pycti.entities.opencti_note import Note
|
|
|
42
44
|
from pycti.entities.opencti_observed_data import ObservedData
|
|
43
45
|
from pycti.entities.opencti_opinion import Opinion
|
|
44
46
|
from pycti.entities.opencti_report import Report
|
|
47
|
+
from pycti.entities.opencti_role import Role
|
|
48
|
+
from pycti.entities.opencti_settings import Settings
|
|
45
49
|
from pycti.entities.opencti_stix import Stix
|
|
46
50
|
from pycti.entities.opencti_stix_core_object import StixCoreObject
|
|
47
51
|
from pycti.entities.opencti_stix_core_relationship import StixCoreRelationship
|
|
@@ -59,6 +63,7 @@ from pycti.entities.opencti_threat_actor import ThreatActor
|
|
|
59
63
|
from pycti.entities.opencti_threat_actor_group import ThreatActorGroup
|
|
60
64
|
from pycti.entities.opencti_threat_actor_individual import ThreatActorIndividual
|
|
61
65
|
from pycti.entities.opencti_tool import Tool
|
|
66
|
+
from pycti.entities.opencti_user import User
|
|
62
67
|
from pycti.entities.opencti_vocabulary import Vocabulary
|
|
63
68
|
from pycti.entities.opencti_vulnerability import Vulnerability
|
|
64
69
|
from pycti.utils.opencti_logger import logger
|
|
@@ -128,6 +133,7 @@ class OpenCTIApiClient:
|
|
|
128
133
|
# Configure logger
|
|
129
134
|
self.logger_class = logger(log_level.upper(), json_logging)
|
|
130
135
|
self.app_logger = self.logger_class("api")
|
|
136
|
+
self.admin_logger = self.logger_class("admin")
|
|
131
137
|
|
|
132
138
|
# Define API
|
|
133
139
|
self.api_token = token
|
|
@@ -198,6 +204,13 @@ class OpenCTIApiClient:
|
|
|
198
204
|
self.grouping = Grouping(self)
|
|
199
205
|
self.indicator = Indicator(self)
|
|
200
206
|
|
|
207
|
+
# Admin functionality
|
|
208
|
+
self.capability = Capability(self)
|
|
209
|
+
self.role = Role(self)
|
|
210
|
+
self.group = Group(self)
|
|
211
|
+
self.user = User(self)
|
|
212
|
+
self.settings = Settings(self)
|
|
213
|
+
|
|
201
214
|
# Check if openCTI is available
|
|
202
215
|
if perform_health_check and not self.health_check():
|
|
203
216
|
raise ValueError(
|
|
@@ -291,6 +291,11 @@ class ListenQueue(threading.Thread):
|
|
|
291
291
|
{"tag": method.delivery_tag},
|
|
292
292
|
)
|
|
293
293
|
|
|
294
|
+
def _set_draft_id(self, draft_id):
|
|
295
|
+
self.helper.draft_id = draft_id
|
|
296
|
+
self.helper.api.set_draft_id(draft_id)
|
|
297
|
+
self.helper.api_impersonate.set_draft_id(draft_id)
|
|
298
|
+
|
|
294
299
|
def _data_handler(self, json_data) -> None:
|
|
295
300
|
# Execute the callback
|
|
296
301
|
try:
|
|
@@ -298,6 +303,7 @@ class ListenQueue(threading.Thread):
|
|
|
298
303
|
entity_id = event_data.get("entity_id")
|
|
299
304
|
entity_type = event_data.get("entity_type")
|
|
300
305
|
validation_mode = event_data.get("validation_mode", "workbench")
|
|
306
|
+
force_validation = event_data.get("force_validation", False)
|
|
301
307
|
# Set the API headers
|
|
302
308
|
internal_data = json_data["internal"]
|
|
303
309
|
work_id = internal_data["work_id"]
|
|
@@ -305,9 +311,9 @@ class ListenQueue(threading.Thread):
|
|
|
305
311
|
self.helper.work_id = work_id
|
|
306
312
|
|
|
307
313
|
self.helper.validation_mode = validation_mode
|
|
308
|
-
self.helper.
|
|
309
|
-
|
|
310
|
-
self.
|
|
314
|
+
self.helper.force_validation = force_validation
|
|
315
|
+
|
|
316
|
+
self._set_draft_id(draft_id)
|
|
311
317
|
|
|
312
318
|
self.helper.playbook = None
|
|
313
319
|
self.helper.enrichment_shared_organizations = None
|
|
@@ -404,12 +410,14 @@ class ListenQueue(threading.Thread):
|
|
|
404
410
|
message = self.callback(event_data)
|
|
405
411
|
if work_id:
|
|
406
412
|
self.helper.api.work.to_processed(work_id, message)
|
|
413
|
+
self._set_draft_id("")
|
|
407
414
|
|
|
408
415
|
except Exception as e: # pylint: disable=broad-except
|
|
409
416
|
self.helper.metric.inc("error_count")
|
|
410
417
|
self.helper.connector_logger.error(
|
|
411
418
|
"Error in message processing, reporting error to API"
|
|
412
419
|
)
|
|
420
|
+
self._set_draft_id("")
|
|
413
421
|
if work_id:
|
|
414
422
|
try:
|
|
415
423
|
self.helper.api.work.to_processed(work_id, str(e), True)
|
|
@@ -1114,6 +1122,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1114
1122
|
)
|
|
1115
1123
|
self.work_id = None
|
|
1116
1124
|
self.validation_mode = "workbench"
|
|
1125
|
+
self.force_validation = False
|
|
1117
1126
|
self.draft_id = None
|
|
1118
1127
|
self.playbook = None
|
|
1119
1128
|
self.enrichment_shared_organizations = None
|
|
@@ -1764,6 +1773,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1764
1773
|
update = kwargs.get("update", False)
|
|
1765
1774
|
event_version = kwargs.get("event_version", None)
|
|
1766
1775
|
bypass_validation = kwargs.get("bypass_validation", False)
|
|
1776
|
+
force_validation = kwargs.get("force_validation", self.force_validation)
|
|
1767
1777
|
entity_id = kwargs.get("entity_id", None)
|
|
1768
1778
|
file_markings = kwargs.get("file_markings", None)
|
|
1769
1779
|
file_name = kwargs.get("file_name", None)
|
|
@@ -1826,7 +1836,11 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1826
1836
|
if not file_name and work_id:
|
|
1827
1837
|
file_name = f"{work_id}.json"
|
|
1828
1838
|
|
|
1829
|
-
if
|
|
1839
|
+
if (
|
|
1840
|
+
(self.connect_validate_before_import or force_validation)
|
|
1841
|
+
and not bypass_validation
|
|
1842
|
+
and file_name
|
|
1843
|
+
):
|
|
1830
1844
|
if validation_mode == "workbench":
|
|
1831
1845
|
self.api.upload_pending_file(
|
|
1832
1846
|
file_name=file_name,
|
|
@@ -1843,6 +1857,8 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1843
1857
|
if not draft_id:
|
|
1844
1858
|
self.connector_logger.error("Draft couldn't be created")
|
|
1845
1859
|
return []
|
|
1860
|
+
if work_id:
|
|
1861
|
+
self.api.work.add_draft_context(work_id, draft_id)
|
|
1846
1862
|
|
|
1847
1863
|
# If directory setup, write the bundle to the target directory
|
|
1848
1864
|
if bundle_send_to_directory and bundle_send_to_directory_path is not None:
|
|
@@ -1916,8 +1932,10 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1916
1932
|
raise ValueError("Nothing to import")
|
|
1917
1933
|
|
|
1918
1934
|
if bundle_send_to_queue:
|
|
1919
|
-
if work_id
|
|
1920
|
-
self.api.work.
|
|
1935
|
+
if work_id:
|
|
1936
|
+
self.api.work.add_expectations(work_id, expectations_number)
|
|
1937
|
+
if draft_id:
|
|
1938
|
+
self.api.work.add_draft_context(work_id, draft_id)
|
|
1921
1939
|
if entities_types is None:
|
|
1922
1940
|
entities_types = []
|
|
1923
1941
|
if self.queue_protocol == "amqp":
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import Dict, List
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Capability:
|
|
5
|
+
"""Represents a role capability on the OpenCTI platform
|
|
6
|
+
|
|
7
|
+
See the properties attribute to understand which properties are fetched by
|
|
8
|
+
default from the graphql queries.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, opencti):
|
|
12
|
+
self.opencti = opencti
|
|
13
|
+
self.properties = """
|
|
14
|
+
id
|
|
15
|
+
standard_id
|
|
16
|
+
entity_type
|
|
17
|
+
parent_types
|
|
18
|
+
name
|
|
19
|
+
description
|
|
20
|
+
attribute_order
|
|
21
|
+
created_at
|
|
22
|
+
updated_at
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def list(self, **kwargs) -> List[Dict]:
|
|
26
|
+
"""Lists all capabilities available on the platform
|
|
27
|
+
|
|
28
|
+
:param customAttributes: Custom attributes to retrieve from the GraphQL
|
|
29
|
+
query.
|
|
30
|
+
:type customAttributes: str, optional
|
|
31
|
+
:return: List of capabilities
|
|
32
|
+
:rtype: List[Dict]
|
|
33
|
+
"""
|
|
34
|
+
custom_attributes = kwargs.get("customAttributes")
|
|
35
|
+
self.opencti.admin_logger.info("Listing capabilities")
|
|
36
|
+
query = (
|
|
37
|
+
"""
|
|
38
|
+
query CapabilityList {
|
|
39
|
+
capabilities {
|
|
40
|
+
edges {
|
|
41
|
+
node {
|
|
42
|
+
"""
|
|
43
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
44
|
+
+ """
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
"""
|
|
50
|
+
)
|
|
51
|
+
result = self.opencti.query(query)
|
|
52
|
+
return self.opencti.process_multiple(result["data"]["capabilities"])
|