pycti 6.5.1__py3-none-any.whl → 6.5.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 +1 -1
- pycti/api/opencti_api_client.py +17 -12
- pycti/connector/opencti_connector_helper.py +12 -0
- pycti/utils/opencti_logger.py +3 -3
- {pycti-6.5.1.dist-info → pycti-6.5.2.dist-info}/METADATA +3 -3
- {pycti-6.5.1.dist-info → pycti-6.5.2.dist-info}/RECORD +9 -9
- {pycti-6.5.1.dist-info → pycti-6.5.2.dist-info}/LICENSE +0 -0
- {pycti-6.5.1.dist-info → pycti-6.5.2.dist-info}/WHEEL +0 -0
- {pycti-6.5.1.dist-info → pycti-6.5.2.dist-info}/top_level.txt +0 -0
pycti/__init__.py
CHANGED
pycti/api/opencti_api_client.py
CHANGED
|
@@ -3,7 +3,7 @@ import base64
|
|
|
3
3
|
import datetime
|
|
4
4
|
import io
|
|
5
5
|
import json
|
|
6
|
-
from typing import Union
|
|
6
|
+
from typing import Dict, Tuple, Union
|
|
7
7
|
|
|
8
8
|
import magic
|
|
9
9
|
import requests
|
|
@@ -83,13 +83,13 @@ class OpenCTIApiClient:
|
|
|
83
83
|
:param log_level: log level for the client
|
|
84
84
|
:type log_level: str, optional
|
|
85
85
|
:param ssl_verify: Requiring the requests to verify the TLS certificate at the server.
|
|
86
|
-
:type ssl_verify: bool, optional
|
|
86
|
+
:type ssl_verify: bool, str, optional
|
|
87
87
|
:param proxies:
|
|
88
88
|
:type proxies: dict, optional, The proxy configuration, would have `http` and `https` attributes. Defaults to {}
|
|
89
89
|
```
|
|
90
90
|
proxies: {
|
|
91
|
-
"http: "http://my_proxy:8080"
|
|
92
|
-
"https: "http://my_proxy:8080"
|
|
91
|
+
"http": "http://my_proxy:8080"
|
|
92
|
+
"https": "http://my_proxy:8080"
|
|
93
93
|
}
|
|
94
94
|
```
|
|
95
95
|
:param json_logging: format the logs as json if set to True
|
|
@@ -102,14 +102,14 @@ class OpenCTIApiClient:
|
|
|
102
102
|
|
|
103
103
|
def __init__(
|
|
104
104
|
self,
|
|
105
|
-
url,
|
|
106
|
-
token,
|
|
105
|
+
url: str,
|
|
106
|
+
token: str,
|
|
107
107
|
log_level="info",
|
|
108
|
-
ssl_verify=False,
|
|
109
|
-
proxies=None,
|
|
108
|
+
ssl_verify: Union[bool, str] = False,
|
|
109
|
+
proxies: Union[Dict[str, str], None] = None,
|
|
110
110
|
json_logging=False,
|
|
111
111
|
bundle_send_to_queue=True,
|
|
112
|
-
cert=None,
|
|
112
|
+
cert: Union[str, Tuple[str, str], None] = None,
|
|
113
113
|
auth=None,
|
|
114
114
|
perform_health_check=True,
|
|
115
115
|
):
|
|
@@ -712,12 +712,13 @@ class OpenCTIApiClient:
|
|
|
712
712
|
data = kwargs.get("data", None)
|
|
713
713
|
mime_type = kwargs.get("mime_type", "text/plain")
|
|
714
714
|
entity_id = kwargs.get("entity_id", None)
|
|
715
|
+
file_markings = kwargs.get("file_markings", [])
|
|
715
716
|
|
|
716
717
|
if file_name is not None:
|
|
717
718
|
self.app_logger.info("Uploading a file.")
|
|
718
719
|
query = """
|
|
719
|
-
mutation UploadPending($file: Upload!, $entityId: String) {
|
|
720
|
-
uploadPending(file: $file, entityId: $entityId) {
|
|
720
|
+
mutation UploadPending($file: Upload!, $entityId: String, $file_markings: [String!]) {
|
|
721
|
+
uploadPending(file: $file, entityId: $entityId, file_markings: $file_markings) {
|
|
721
722
|
id
|
|
722
723
|
name
|
|
723
724
|
}
|
|
@@ -731,7 +732,11 @@ class OpenCTIApiClient:
|
|
|
731
732
|
mime_type = magic.from_file(file_name, mime=True)
|
|
732
733
|
return self.query(
|
|
733
734
|
query,
|
|
734
|
-
{
|
|
735
|
+
{
|
|
736
|
+
"file": (File(file_name, data, mime_type)),
|
|
737
|
+
"entityId": entity_id,
|
|
738
|
+
"file_markings": file_markings,
|
|
739
|
+
},
|
|
735
740
|
)
|
|
736
741
|
else:
|
|
737
742
|
self.app_logger.error("[upload] Missing parameter: file_name")
|
|
@@ -769,6 +769,9 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
769
769
|
def __init__(self, config: Dict, playbook_compatible=False) -> None:
|
|
770
770
|
sys.excepthook = killProgramHook
|
|
771
771
|
|
|
772
|
+
# Cache
|
|
773
|
+
self.stream_collections = {}
|
|
774
|
+
|
|
772
775
|
# Load API config
|
|
773
776
|
self.config = config
|
|
774
777
|
self.opencti_url = get_config_variable(
|
|
@@ -1063,6 +1066,9 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1063
1066
|
"stream_live": True,
|
|
1064
1067
|
"stream_public": False,
|
|
1065
1068
|
}
|
|
1069
|
+
# Get from cache
|
|
1070
|
+
elif self.connect_live_stream_id in self.stream_collections:
|
|
1071
|
+
return self.stream_collections[self.connect_live_stream_id]
|
|
1066
1072
|
else:
|
|
1067
1073
|
query = """
|
|
1068
1074
|
query StreamCollection($id: String!) {
|
|
@@ -1076,6 +1082,10 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1076
1082
|
}
|
|
1077
1083
|
"""
|
|
1078
1084
|
result = self.api.query(query, {"id": self.connect_live_stream_id})
|
|
1085
|
+
# Put in cache
|
|
1086
|
+
self.stream_collections[self.connect_live_stream_id] = result["data"][
|
|
1087
|
+
"streamCollection"
|
|
1088
|
+
]
|
|
1079
1089
|
return result["data"]["streamCollection"]
|
|
1080
1090
|
else:
|
|
1081
1091
|
raise ValueError("This connector is not connected to any stream")
|
|
@@ -1581,6 +1591,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1581
1591
|
event_version = kwargs.get("event_version", None)
|
|
1582
1592
|
bypass_validation = kwargs.get("bypass_validation", False)
|
|
1583
1593
|
entity_id = kwargs.get("entity_id", None)
|
|
1594
|
+
file_markings = kwargs.get("file_markings", None)
|
|
1584
1595
|
file_name = kwargs.get("file_name", None)
|
|
1585
1596
|
bundle_send_to_queue = kwargs.get("send_to_queue", self.bundle_send_to_queue)
|
|
1586
1597
|
cleanup_inconsistent_bundle = kwargs.get("cleanup_inconsistent_bundle", False)
|
|
@@ -1648,6 +1659,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1648
1659
|
data=bundle,
|
|
1649
1660
|
mime_type="application/json",
|
|
1650
1661
|
entity_id=entity_id,
|
|
1662
|
+
file_markings=file_markings,
|
|
1651
1663
|
)
|
|
1652
1664
|
return []
|
|
1653
1665
|
elif validation_mode == "draft" and not draft_id:
|
pycti/utils/opencti_logger.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import datetime
|
|
2
1
|
import logging
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
3
|
|
|
4
4
|
from pythonjsonlogger import jsonlogger
|
|
5
5
|
|
|
@@ -9,8 +9,8 @@ class CustomJsonFormatter(jsonlogger.JsonFormatter):
|
|
|
9
9
|
super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
|
|
10
10
|
if not log_record.get("timestamp"):
|
|
11
11
|
# This doesn't use record.created, so it is slightly off
|
|
12
|
-
now = datetime.
|
|
13
|
-
log_record["timestamp"] = now
|
|
12
|
+
now = datetime.now(tz=timezone.utc)
|
|
13
|
+
log_record["timestamp"] = now.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
|
14
14
|
if log_record.get("level"):
|
|
15
15
|
log_record["level"] = log_record["level"].upper()
|
|
16
16
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: pycti
|
|
3
|
-
Version: 6.5.
|
|
3
|
+
Version: 6.5.2
|
|
4
4
|
Summary: Python API client for OpenCTI.
|
|
5
5
|
Home-page: https://github.com/OpenCTI-Platform/client-python
|
|
6
6
|
Author: Filigran
|
|
@@ -40,8 +40,8 @@ Requires-Dist: stix2~=3.0.1
|
|
|
40
40
|
Provides-Extra: dev
|
|
41
41
|
Requires-Dist: black~=24.4.0; extra == "dev"
|
|
42
42
|
Requires-Dist: build~=1.2.1; extra == "dev"
|
|
43
|
-
Requires-Dist: isort~=
|
|
44
|
-
Requires-Dist: types-pytz~=
|
|
43
|
+
Requires-Dist: isort~=6.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: types-pytz~=2025.1.0.20250204; extra == "dev"
|
|
45
45
|
Requires-Dist: pre-commit~=3.8.0; extra == "dev"
|
|
46
46
|
Requires-Dist: pytest-cases~=3.8.0; extra == "dev"
|
|
47
47
|
Requires-Dist: pytest-cov~=5.0.0; extra == "dev"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
pycti/__init__.py,sha256=
|
|
1
|
+
pycti/__init__.py,sha256=vuINZwJahwqFmxz7ZhxCxVAk8eEKHZO6_pveLWsEQ3U,5218
|
|
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=6TKvtgAk0iYQL2RaLTUV6cxCBefEgwmlL_iVHgzf_ow,32745
|
|
4
4
|
pycti/api/opencti_api_connector.py,sha256=ubM_zPjTD8L33TEugCQgf_YF9zugDFg_7FgNubGlwJw,5447
|
|
5
5
|
pycti/api/opencti_api_playbook.py,sha256=456We78vESukfSOi_CctfZ9dbBJEi76EHClRc2f21Js,1628
|
|
6
6
|
pycti/api/opencti_api_work.py,sha256=qIRJMCfyC9odXf7LMRg9ImYizqF2WHUOU7Ty5IUFGg8,8351
|
|
7
7
|
pycti/connector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
pycti/connector/opencti_connector.py,sha256=5oVvS27KWhzRiofJAeQPDtba-EP83FziSistyEd5l-U,2561
|
|
9
|
-
pycti/connector/opencti_connector_helper.py,sha256=
|
|
9
|
+
pycti/connector/opencti_connector_helper.py,sha256=ee8Ej43Ox9W7G44PEfHNGZuU_NmBVNl7dE3V3BzE4sE,81286
|
|
10
10
|
pycti/connector/opencti_metric_handler.py,sha256=4jXHeJflomtHjuQ_YU0b36TG7o26vOWbY_jvU8Ezobs,3725
|
|
11
11
|
pycti/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
pycti/entities/opencti_attack_pattern.py,sha256=rj3o2bFCoXniLmD9Ithi09S9Us8ab1G-GFLgqS8jll0,22237
|
|
@@ -61,14 +61,14 @@ pycti/entities/stix_cyber_observable/opencti_stix_cyber_observable_deprecated.py
|
|
|
61
61
|
pycti/entities/stix_cyber_observable/opencti_stix_cyber_observable_properties.py,sha256=MN56CW8RWZwB0Pr8UiHZy_4nSzbgFbwdhSFKpsZ_d1Y,11293
|
|
62
62
|
pycti/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
63
|
pycti/utils/constants.py,sha256=ZgOVxY5bnrHiNvPgOfZLWk16sSDnaE_tg8JVjZpw24Q,11831
|
|
64
|
-
pycti/utils/opencti_logger.py,sha256=
|
|
64
|
+
pycti/utils/opencti_logger.py,sha256=BHNy9fJuTUTn_JEYSCmyvVwd6y-9ZJKxO40mY4iZ0bc,2226
|
|
65
65
|
pycti/utils/opencti_stix2.py,sha256=pUx1Oglb1EnREheMzmJBrmRS17vGnZzF8PCmB-pjNM0,117680
|
|
66
66
|
pycti/utils/opencti_stix2_identifier.py,sha256=k8L1z4q1xdCBfxqUba4YS_kT-MmbJFxYh0RvfGOmrOs,837
|
|
67
67
|
pycti/utils/opencti_stix2_splitter.py,sha256=etnAWMDzNi2JCovSUJ5Td-XLVdzgKRdsV1XfpXOGols,11070
|
|
68
68
|
pycti/utils/opencti_stix2_update.py,sha256=CnMyqkeVA0jgyxEcgqna8sABU4YPMjkEJ228GVurIn4,14658
|
|
69
69
|
pycti/utils/opencti_stix2_utils.py,sha256=xgBZzm7HC76rLQYwTKkaUd_w9jJnVMoryHx7KDDIB_g,5065
|
|
70
|
-
pycti-6.5.
|
|
71
|
-
pycti-6.5.
|
|
72
|
-
pycti-6.5.
|
|
73
|
-
pycti-6.5.
|
|
74
|
-
pycti-6.5.
|
|
70
|
+
pycti-6.5.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
71
|
+
pycti-6.5.2.dist-info/METADATA,sha256=t7YyxQyOxdyFCqF7DF_iWCG9XK-Hj8vMWuB9vHvrRlQ,5418
|
|
72
|
+
pycti-6.5.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
73
|
+
pycti-6.5.2.dist-info/top_level.txt,sha256=cqEpxitAhHP4VgSA6xmrak6Yk9MeBkwoMTB6k7d2ZnE,6
|
|
74
|
+
pycti-6.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|