pycti 6.0.10__tar.gz → 6.1.1__tar.gz
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-6.0.10 → pycti-6.1.1}/PKG-INFO +2 -2
- {pycti-6.0.10 → pycti-6.1.1}/pycti/__init__.py +1 -1
- {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_client.py +15 -5
- {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_playbook.py +3 -2
- {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/opencti_connector_helper.py +10 -6
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_case_incident.py +1 -1
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_intrusion_set.py +34 -14
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_report.py +13 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_core_object.py +32 -5
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_cyber_observable.py +23 -3
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_domain_object.py +27 -7
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_object_or_stix_relationship.py +88 -4
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/constants.py +0 -1
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2.py +269 -187
- {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/PKG-INFO +2 -2
- {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/requires.txt +1 -1
- {pycti-6.0.10 → pycti-6.1.1}/setup.cfg +1 -1
- {pycti-6.0.10 → pycti-6.1.1}/LICENSE +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/README.md +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/api/__init__.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_connector.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_work.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/__init__.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/opencti_connector.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/opencti_metric_handler.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/__init__.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_attack_pattern.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_campaign.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_case_rfi.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_case_rft.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_channel.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_course_of_action.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_data_component.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_data_source.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_event.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_external_reference.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_feedback.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_grouping.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_identity.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_incident.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_indicator.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_infrastructure.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_kill_chain_phase.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_label.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_language.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_location.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_malware.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_malware_analysis.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_marking_definition.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_narrative.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_note.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_observed_data.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_opinion.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_core_relationship.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_nested_ref_relationship.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_sighting_relationship.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_task.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_threat_actor.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_threat_actor_group.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_threat_actor_individual.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_tool.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_vocabulary.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_vulnerability.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/__init__.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_logger.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2_splitter.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2_update.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2_utils.py +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/SOURCES.txt +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/dependency_links.txt +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/top_level.txt +0 -0
- {pycti-6.0.10 → pycti-6.1.1}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pycti
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.1.1
|
|
4
4
|
Summary: Python API client for OpenCTI.
|
|
5
5
|
Home-page: https://github.com/OpenCTI-Platform/client-python
|
|
6
6
|
Author: Filigran
|
|
@@ -42,7 +42,7 @@ Requires-Dist: pre-commit~=3.7.0; extra == "dev"
|
|
|
42
42
|
Requires-Dist: pytest-cases~=3.8.0; extra == "dev"
|
|
43
43
|
Requires-Dist: pytest-cov~=5.0.0; extra == "dev"
|
|
44
44
|
Requires-Dist: pytest_randomly~=3.15.0; extra == "dev"
|
|
45
|
-
Requires-Dist: pytest~=8.
|
|
45
|
+
Requires-Dist: pytest~=8.2.0; extra == "dev"
|
|
46
46
|
Requires-Dist: types-python-dateutil~=2.9.0; extra == "dev"
|
|
47
47
|
Requires-Dist: wheel~=0.43.0; extra == "dev"
|
|
48
48
|
Provides-Extra: doc
|
|
@@ -207,6 +207,12 @@ class OpenCTIApiClient:
|
|
|
207
207
|
def set_applicant_id_header(self, applicant_id):
|
|
208
208
|
self.request_headers["opencti-applicant-id"] = applicant_id
|
|
209
209
|
|
|
210
|
+
def set_playbook_id_header(self, playbook_id):
|
|
211
|
+
self.request_headers["opencti-playbook-id"] = playbook_id
|
|
212
|
+
|
|
213
|
+
def set_event_id(self, event_id):
|
|
214
|
+
self.request_headers["opencti-event-id"] = event_id
|
|
215
|
+
|
|
210
216
|
def set_synchronized_upsert_header(self, synchronized):
|
|
211
217
|
self.request_headers["synchronized-upsert"] = (
|
|
212
218
|
"true" if synchronized is True else "false"
|
|
@@ -616,18 +622,19 @@ class OpenCTIApiClient:
|
|
|
616
622
|
"""upload a file to OpenCTI API
|
|
617
623
|
|
|
618
624
|
:param `**kwargs`: arguments for file upload (required: `file_name` and `data`)
|
|
619
|
-
:return: returns the query
|
|
625
|
+
:return: returns the query response for the file upload
|
|
620
626
|
:rtype: dict
|
|
621
627
|
"""
|
|
622
628
|
|
|
623
629
|
file_name = kwargs.get("file_name", None)
|
|
630
|
+
file_markings = kwargs.get("file_markings", None)
|
|
624
631
|
data = kwargs.get("data", None)
|
|
625
632
|
mime_type = kwargs.get("mime_type", "text/plain")
|
|
626
633
|
if file_name is not None:
|
|
627
634
|
self.app_logger.info("Uploading a file.")
|
|
628
635
|
query = """
|
|
629
|
-
mutation UploadImport($file: Upload
|
|
630
|
-
uploadImport(file: $file) {
|
|
636
|
+
mutation UploadImport($file: Upload!, $fileMarkings: [String]) {
|
|
637
|
+
uploadImport(file: $file, fileMarkings: $fileMarkings) {
|
|
631
638
|
id
|
|
632
639
|
name
|
|
633
640
|
}
|
|
@@ -639,8 +646,11 @@ class OpenCTIApiClient:
|
|
|
639
646
|
mime_type = "application/json"
|
|
640
647
|
else:
|
|
641
648
|
mime_type = magic.from_file(file_name, mime=True)
|
|
642
|
-
|
|
643
|
-
|
|
649
|
+
query_vars = {"file": (File(file_name, data, mime_type))}
|
|
650
|
+
# optional file markings
|
|
651
|
+
if file_markings is not None:
|
|
652
|
+
query_vars["fileMarkings"] = file_markings
|
|
653
|
+
return self.query(query, query_vars)
|
|
644
654
|
else:
|
|
645
655
|
self.app_logger.error("[upload] Missing parameter: file_name")
|
|
646
656
|
return None
|
|
@@ -9,14 +9,15 @@ class OpenCTIApiPlaybook:
|
|
|
9
9
|
"Executing playbook step", {"playbook_id": playbook["playbook_id"]}
|
|
10
10
|
)
|
|
11
11
|
query = """
|
|
12
|
-
mutation PlaybookStepExecution($execution_id: ID!, $execution_start: DateTime!, $data_instance_id: ID!, $playbook_id: ID!, $previous_step_id: ID!, $step_id: ID!, $previous_bundle: String!, $bundle: String!) {
|
|
13
|
-
playbookStepExecution(execution_id: $execution_id, execution_start: $execution_start, data_instance_id: $data_instance_id, playbook_id: $playbook_id, previous_step_id: $previous_step_id, step_id: $step_id, previous_bundle: $previous_bundle, bundle: $bundle)
|
|
12
|
+
mutation PlaybookStepExecution($execution_id: ID!, $event_id: ID!, $execution_start: DateTime!, $data_instance_id: ID!, $playbook_id: ID!, $previous_step_id: ID!, $step_id: ID!, $previous_bundle: String!, $bundle: String!) {
|
|
13
|
+
playbookStepExecution(execution_id: $execution_id, event_id: $event_id, execution_start: $execution_start, data_instance_id: $data_instance_id, playbook_id: $playbook_id, previous_step_id: $previous_step_id, step_id: $step_id, previous_bundle: $previous_bundle, bundle: $bundle)
|
|
14
14
|
}
|
|
15
15
|
"""
|
|
16
16
|
self.api.query(
|
|
17
17
|
query,
|
|
18
18
|
{
|
|
19
19
|
"execution_id": playbook["execution_id"],
|
|
20
|
+
"event_id": playbook["event_id"],
|
|
20
21
|
"execution_start": playbook["execution_start"],
|
|
21
22
|
"playbook_id": playbook["playbook_id"],
|
|
22
23
|
"data_instance_id": playbook["data_instance_id"],
|
|
@@ -282,18 +282,20 @@ class ListenQueue(threading.Thread):
|
|
|
282
282
|
is_playbook = "playbook" in json_data["internal"]
|
|
283
283
|
# If playbook, compute object on data bundle
|
|
284
284
|
if is_playbook:
|
|
285
|
-
execution_id = json_data["internal"]["playbook"]["execution_id"]
|
|
286
285
|
execution_start = self.helper.date_now()
|
|
287
|
-
|
|
288
|
-
|
|
286
|
+
event_id = json_data["internal"]["playbook"].get("event_id")
|
|
287
|
+
execution_id = json_data["internal"]["playbook"].get("execution_id")
|
|
288
|
+
playbook_id = json_data["internal"]["playbook"].get("playbook_id")
|
|
289
|
+
data_instance_id = json_data["internal"]["playbook"].get(
|
|
289
290
|
"data_instance_id"
|
|
290
|
-
|
|
291
|
+
)
|
|
291
292
|
previous_bundle = json.dumps((json_data["event"]["bundle"]))
|
|
292
293
|
step_id = json_data["internal"]["playbook"]["step_id"]
|
|
293
294
|
previous_step_id = json_data["internal"]["playbook"][
|
|
294
295
|
"previous_step_id"
|
|
295
296
|
]
|
|
296
297
|
playbook_data = {
|
|
298
|
+
"event_id": event_id,
|
|
297
299
|
"execution_id": execution_id,
|
|
298
300
|
"execution_start": execution_start,
|
|
299
301
|
"playbook_id": playbook_id,
|
|
@@ -312,7 +314,9 @@ class ListenQueue(threading.Thread):
|
|
|
312
314
|
# If not playbook but enrichment, compute object on enrichment_entity
|
|
313
315
|
opencti_entity = event_data["enrichment_entity"]
|
|
314
316
|
stix_objects = self.helper.api.stix2.prepare_export(
|
|
315
|
-
self.helper.api.stix2.generate_export(
|
|
317
|
+
entity=self.helper.api.stix2.generate_export(
|
|
318
|
+
copy.copy(opencti_entity)
|
|
319
|
+
)
|
|
316
320
|
)
|
|
317
321
|
stix_entity = [
|
|
318
322
|
e
|
|
@@ -1565,7 +1569,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
|
|
|
1565
1569
|
if bundle is None:
|
|
1566
1570
|
# Generate bundle
|
|
1567
1571
|
stix_objects = self.api.stix2.prepare_export(
|
|
1568
|
-
self.api.stix2.generate_export(copy.copy(opencti_entity))
|
|
1572
|
+
entity=self.api.stix2.generate_export(copy.copy(opencti_entity))
|
|
1569
1573
|
)
|
|
1570
1574
|
else:
|
|
1571
1575
|
stix_objects = bundle["objects"]
|
|
@@ -530,7 +530,7 @@ class CaseIncident:
|
|
|
530
530
|
data = self.opencti.process_multiple(result["data"]["caseIncidents"])
|
|
531
531
|
final_data = final_data + data
|
|
532
532
|
while result["data"]["caseIncidents"]["pageInfo"]["hasNextPage"]:
|
|
533
|
-
after = result["
|
|
533
|
+
after = result["data"]["caseIncidents"]["pageInfo"]["endCursor"]
|
|
534
534
|
self.opencti.app_logger.info("Listing Case Incidents", {"after": after})
|
|
535
535
|
result = self.opencti.query(
|
|
536
536
|
query,
|
|
@@ -275,20 +275,40 @@ class IntrusionSet:
|
|
|
275
275
|
}
|
|
276
276
|
"""
|
|
277
277
|
)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
278
|
+
variables = {
|
|
279
|
+
"filters": filters,
|
|
280
|
+
"search": search,
|
|
281
|
+
"first": first,
|
|
282
|
+
"after": after,
|
|
283
|
+
"orderBy": order_by,
|
|
284
|
+
"orderMode": order_mode,
|
|
285
|
+
}
|
|
286
|
+
result = self.opencti.query(query, variables)
|
|
287
|
+
if get_all:
|
|
288
|
+
final_data = []
|
|
289
|
+
data = self.opencti.process_multiple(result["data"]["intrusionSets"])
|
|
290
|
+
final_data = final_data + data
|
|
291
|
+
while result["data"]["intrusionSets"]["pageInfo"]["hasNextPage"]:
|
|
292
|
+
after = result["data"]["intrusionSets"]["pageInfo"]["endCursor"]
|
|
293
|
+
self.opencti.app_logger.info("Listing Intrusion-Sets", {"after": after})
|
|
294
|
+
result = self.opencti.query(
|
|
295
|
+
query,
|
|
296
|
+
{
|
|
297
|
+
"filters": filters,
|
|
298
|
+
"search": search,
|
|
299
|
+
"first": first,
|
|
300
|
+
"after": after,
|
|
301
|
+
"orderBy": order_by,
|
|
302
|
+
"orderMode": order_mode,
|
|
303
|
+
},
|
|
304
|
+
)
|
|
305
|
+
data = self.opencti.process_multiple(result["data"]["intrusionSets"])
|
|
306
|
+
final_data = final_data + data
|
|
307
|
+
return final_data
|
|
308
|
+
else:
|
|
309
|
+
return self.opencti.process_multiple(
|
|
310
|
+
result["data"]["intrusionSets"], with_pagination
|
|
311
|
+
)
|
|
292
312
|
|
|
293
313
|
"""
|
|
294
314
|
Read a Intrusion-Set object
|
|
@@ -466,6 +466,19 @@ class Report:
|
|
|
466
466
|
id = str(uuid.uuid5(uuid.UUID("00abedb4-aa42-466c-9c01-fed23315a9b7"), data))
|
|
467
467
|
return "report--" + id
|
|
468
468
|
|
|
469
|
+
@staticmethod
|
|
470
|
+
def generate_fixed_fake_id(name, published=None):
|
|
471
|
+
name = name.lower().strip()
|
|
472
|
+
if isinstance(published, datetime.datetime):
|
|
473
|
+
published = published.isoformat()
|
|
474
|
+
if published is not None:
|
|
475
|
+
data = {"name": name, "published": published, "fake": "fake"}
|
|
476
|
+
else:
|
|
477
|
+
data = {"name": name, "fake": "fake"}
|
|
478
|
+
data = canonicalize(data, utf8=False)
|
|
479
|
+
id = str(uuid.uuid5(uuid.UUID("00abedb4-aa42-466c-9c01-fed23315a9b7"), data))
|
|
480
|
+
return "report--" + id
|
|
481
|
+
|
|
469
482
|
"""
|
|
470
483
|
List Report objects
|
|
471
484
|
|
|
@@ -435,9 +435,18 @@ class StixCoreObject:
|
|
|
435
435
|
}
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
|
-
}
|
|
438
|
+
}
|
|
439
439
|
... on StixCyberObservable {
|
|
440
440
|
observable_value
|
|
441
|
+
indicators {
|
|
442
|
+
edges {
|
|
443
|
+
node {
|
|
444
|
+
id
|
|
445
|
+
pattern
|
|
446
|
+
pattern_type
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
441
450
|
}
|
|
442
451
|
... on AutonomousSystem {
|
|
443
452
|
number
|
|
@@ -1090,9 +1099,18 @@ class StixCoreObject:
|
|
|
1090
1099
|
}
|
|
1091
1100
|
}
|
|
1092
1101
|
}
|
|
1093
|
-
}
|
|
1102
|
+
}
|
|
1094
1103
|
... on StixCyberObservable {
|
|
1095
1104
|
observable_value
|
|
1105
|
+
indicators {
|
|
1106
|
+
edges {
|
|
1107
|
+
node {
|
|
1108
|
+
id
|
|
1109
|
+
pattern
|
|
1110
|
+
pattern_type
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1096
1114
|
}
|
|
1097
1115
|
... on AutonomousSystem {
|
|
1098
1116
|
number
|
|
@@ -1459,13 +1477,21 @@ class StixCoreObject:
|
|
|
1459
1477
|
return entity["importFiles"]
|
|
1460
1478
|
|
|
1461
1479
|
def push_list_export(
|
|
1462
|
-
self,
|
|
1480
|
+
self,
|
|
1481
|
+
entity_id,
|
|
1482
|
+
entity_type,
|
|
1483
|
+
file_name,
|
|
1484
|
+
file_markings,
|
|
1485
|
+
data,
|
|
1486
|
+
list_filters="",
|
|
1487
|
+
mime_type=None,
|
|
1463
1488
|
):
|
|
1464
1489
|
query = """
|
|
1465
|
-
mutation StixCoreObjectsExportPush($entity_id: String, $entity_type: String!, $file: Upload!, $listFilters: String) {
|
|
1466
|
-
stixCoreObjectsExportPush(entity_id: $entity_id, entity_type: $entity_type, file: $file, listFilters: $listFilters)
|
|
1490
|
+
mutation StixCoreObjectsExportPush($entity_id: String, $entity_type: String!, $file: Upload!, $file_markings: [String]!, $listFilters: String) {
|
|
1491
|
+
stixCoreObjectsExportPush(entity_id: $entity_id, entity_type: $entity_type, file: $file, file_markings: $file_markings, listFilters: $listFilters)
|
|
1467
1492
|
}
|
|
1468
1493
|
"""
|
|
1494
|
+
|
|
1469
1495
|
if mime_type is None:
|
|
1470
1496
|
file = self.file(file_name, data)
|
|
1471
1497
|
else:
|
|
@@ -1476,6 +1502,7 @@ class StixCoreObject:
|
|
|
1476
1502
|
"entity_id": entity_id,
|
|
1477
1503
|
"entity_type": entity_type,
|
|
1478
1504
|
"file": file,
|
|
1505
|
+
"file_markings": file_markings,
|
|
1479
1506
|
"listFilters": list_filters,
|
|
1480
1507
|
},
|
|
1481
1508
|
)
|
|
@@ -2316,11 +2316,30 @@ class StixCyberObservable:
|
|
|
2316
2316
|
return False
|
|
2317
2317
|
|
|
2318
2318
|
def push_list_export(
|
|
2319
|
-
self,
|
|
2319
|
+
self,
|
|
2320
|
+
entity_id,
|
|
2321
|
+
entity_type,
|
|
2322
|
+
file_name,
|
|
2323
|
+
file_markings,
|
|
2324
|
+
data,
|
|
2325
|
+
list_filters="",
|
|
2326
|
+
mime_type=None,
|
|
2320
2327
|
):
|
|
2321
2328
|
query = """
|
|
2322
|
-
mutation StixCyberObservablesExportPush(
|
|
2323
|
-
|
|
2329
|
+
mutation StixCyberObservablesExportPush(
|
|
2330
|
+
$entity_id: String,
|
|
2331
|
+
$entity_type: String!,
|
|
2332
|
+
$file: Upload!,
|
|
2333
|
+
$file_markings: [String]!,
|
|
2334
|
+
$listFilters: String
|
|
2335
|
+
) {
|
|
2336
|
+
stixCyberObservablesExportPush(
|
|
2337
|
+
entity_id: $entity_id,
|
|
2338
|
+
entity_type: $entity_type,
|
|
2339
|
+
file: $file,
|
|
2340
|
+
file_markings: $file_markings,
|
|
2341
|
+
listFilters: $listFilters
|
|
2342
|
+
)
|
|
2324
2343
|
}
|
|
2325
2344
|
"""
|
|
2326
2345
|
if mime_type is None:
|
|
@@ -2333,6 +2352,7 @@ class StixCyberObservable:
|
|
|
2333
2352
|
"entity_id": entity_id,
|
|
2334
2353
|
"entity_type": entity_type,
|
|
2335
2354
|
"file": file,
|
|
2355
|
+
"file_markings": file_markings,
|
|
2336
2356
|
"listFilters": list_filters,
|
|
2337
2357
|
},
|
|
2338
2358
|
)
|
|
@@ -1325,11 +1325,18 @@ class StixDomainObject:
|
|
|
1325
1325
|
return None
|
|
1326
1326
|
|
|
1327
1327
|
def push_list_export(
|
|
1328
|
-
self,
|
|
1328
|
+
self,
|
|
1329
|
+
entity_id,
|
|
1330
|
+
entity_type,
|
|
1331
|
+
file_name,
|
|
1332
|
+
file_markings,
|
|
1333
|
+
data,
|
|
1334
|
+
list_filters="",
|
|
1335
|
+
mime_type=None,
|
|
1329
1336
|
):
|
|
1330
1337
|
query = """
|
|
1331
|
-
mutation StixDomainObjectsExportPush($entity_id: String, $entity_type: String!, $file: Upload!, $listFilters: String) {
|
|
1332
|
-
stixDomainObjectsExportPush(entity_id: $entity_id, entity_type: $entity_type, file: $file, listFilters: $listFilters)
|
|
1338
|
+
mutation StixDomainObjectsExportPush($entity_id: String, $entity_type: String!, $file: Upload!, $file_markings: [String]!, $listFilters: String) {
|
|
1339
|
+
stixDomainObjectsExportPush(entity_id: $entity_id, entity_type: $entity_type, file: $file, file_markings: $file_markings, listFilters: $listFilters)
|
|
1333
1340
|
}
|
|
1334
1341
|
"""
|
|
1335
1342
|
if mime_type is None:
|
|
@@ -1342,15 +1349,26 @@ class StixDomainObject:
|
|
|
1342
1349
|
"entity_id": entity_id,
|
|
1343
1350
|
"entity_type": entity_type,
|
|
1344
1351
|
"file": file,
|
|
1352
|
+
"file_markings": file_markings,
|
|
1345
1353
|
"listFilters": list_filters,
|
|
1346
1354
|
},
|
|
1347
1355
|
)
|
|
1348
1356
|
|
|
1349
|
-
def push_entity_export(
|
|
1357
|
+
def push_entity_export(
|
|
1358
|
+
self, entity_id, file_name, data, file_markings=None, mime_type=None
|
|
1359
|
+
):
|
|
1360
|
+
if file_markings is None:
|
|
1361
|
+
file_markings = []
|
|
1350
1362
|
query = """
|
|
1351
|
-
mutation StixDomainObjectEdit(
|
|
1363
|
+
mutation StixDomainObjectEdit(
|
|
1364
|
+
$id: ID!, $file: Upload!,
|
|
1365
|
+
$file_markings: [String]!
|
|
1366
|
+
) {
|
|
1352
1367
|
stixDomainObjectEdit(id: $id) {
|
|
1353
|
-
exportPush(
|
|
1368
|
+
exportPush(
|
|
1369
|
+
file: $file,
|
|
1370
|
+
file_markings: $file_markings
|
|
1371
|
+
)
|
|
1354
1372
|
}
|
|
1355
1373
|
}
|
|
1356
1374
|
"""
|
|
@@ -1358,7 +1376,9 @@ class StixDomainObject:
|
|
|
1358
1376
|
file = self.file(file_name, data)
|
|
1359
1377
|
else:
|
|
1360
1378
|
file = self.file(file_name, data, mime_type)
|
|
1361
|
-
self.opencti.query(
|
|
1379
|
+
self.opencti.query(
|
|
1380
|
+
query, {"id": entity_id, "file": file, "file_markings": file_markings}
|
|
1381
|
+
)
|
|
1362
1382
|
|
|
1363
1383
|
"""
|
|
1364
1384
|
Update the Identity author of a Stix-Domain-Object object (created_by)
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class StixObjectOrStixRelationship:
|
|
2
5
|
def __init__(self, opencti):
|
|
3
6
|
self.opencti = opencti
|
|
@@ -329,11 +332,15 @@ class StixObjectOrStixRelationship:
|
|
|
329
332
|
}
|
|
330
333
|
... on Case {
|
|
331
334
|
name
|
|
332
|
-
}
|
|
335
|
+
}
|
|
333
336
|
... on StixCyberObservable {
|
|
334
337
|
observable_value
|
|
335
338
|
}
|
|
336
339
|
... on StixCoreRelationship {
|
|
340
|
+
id
|
|
341
|
+
standard_id
|
|
342
|
+
entity_type
|
|
343
|
+
parent_types
|
|
337
344
|
createdBy {
|
|
338
345
|
... on Identity {
|
|
339
346
|
id
|
|
@@ -396,6 +403,10 @@ class StixObjectOrStixRelationship:
|
|
|
396
403
|
stop_time
|
|
397
404
|
}
|
|
398
405
|
... on StixSightingRelationship {
|
|
406
|
+
id
|
|
407
|
+
standard_id
|
|
408
|
+
entity_type
|
|
409
|
+
parent_types
|
|
399
410
|
createdBy {
|
|
400
411
|
... on Identity {
|
|
401
412
|
id
|
|
@@ -476,9 +487,9 @@ class StixObjectOrStixRelationship:
|
|
|
476
487
|
)
|
|
477
488
|
query = (
|
|
478
489
|
"""
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
490
|
+
query StixObjectOrStixRelationship($id: String!) {
|
|
491
|
+
stixObjectOrStixRelationship(id: $id) {
|
|
492
|
+
"""
|
|
482
493
|
+ (
|
|
483
494
|
custom_attributes
|
|
484
495
|
if custom_attributes is not None
|
|
@@ -496,3 +507,76 @@ class StixObjectOrStixRelationship:
|
|
|
496
507
|
else:
|
|
497
508
|
self.opencti.app_logger.error("Missing parameters: id")
|
|
498
509
|
return None
|
|
510
|
+
|
|
511
|
+
def list(self, **kwargs):
|
|
512
|
+
filters = kwargs.get("filters", None)
|
|
513
|
+
search = kwargs.get("search", None)
|
|
514
|
+
first = kwargs.get("first", 100)
|
|
515
|
+
after = kwargs.get("after", None)
|
|
516
|
+
get_all = kwargs.get("getAll", False)
|
|
517
|
+
with_pagination = kwargs.get("with_pagination", False)
|
|
518
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
519
|
+
|
|
520
|
+
self.opencti.app_logger.info(
|
|
521
|
+
"Listing StixObjectOrStixRelationships with filters",
|
|
522
|
+
{"filters": json.dumps(filters)},
|
|
523
|
+
)
|
|
524
|
+
query = (
|
|
525
|
+
"""
|
|
526
|
+
query StixObjectOrStixRelationships($filters: FilterGroup, $search: String, $first: Int, $after: ID) {
|
|
527
|
+
stixObjectOrStixRelationships(filters: $filters, search: $search, first: $first, after: $after) {
|
|
528
|
+
edges {
|
|
529
|
+
node {
|
|
530
|
+
"""
|
|
531
|
+
+ (custom_attributes if custom_attributes is not None else self.properties)
|
|
532
|
+
+ """
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
pageInfo {
|
|
536
|
+
startCursor
|
|
537
|
+
endCursor
|
|
538
|
+
hasNextPage
|
|
539
|
+
hasPreviousPage
|
|
540
|
+
globalCount
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
"""
|
|
545
|
+
)
|
|
546
|
+
variables = {
|
|
547
|
+
"filters": filters,
|
|
548
|
+
"search": search,
|
|
549
|
+
"first": first,
|
|
550
|
+
"after": after,
|
|
551
|
+
}
|
|
552
|
+
result = self.opencti.query(
|
|
553
|
+
query,
|
|
554
|
+
variables,
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
if get_all:
|
|
558
|
+
final_data = []
|
|
559
|
+
data = self.opencti.process_multiple(
|
|
560
|
+
result["data"]["stixObjectOrStixRelationships"]
|
|
561
|
+
)
|
|
562
|
+
final_data = final_data + data
|
|
563
|
+
while result["data"]["stixObjectOrStixRelationships"]["pageInfo"][
|
|
564
|
+
"hasNextPage"
|
|
565
|
+
]:
|
|
566
|
+
after = result["data"]["stixObjectOrStixRelationships"]["pageInfo"][
|
|
567
|
+
"endCursor"
|
|
568
|
+
]
|
|
569
|
+
self.opencti.app_logger.info(
|
|
570
|
+
"Listing stixObjectOrStixRelationships", {"after": after}
|
|
571
|
+
)
|
|
572
|
+
after_variables = {**variables, **{"after": after}}
|
|
573
|
+
result = self.opencti.query(query, after_variables)
|
|
574
|
+
data = self.opencti.process_multiple(
|
|
575
|
+
result["data"]["stixObjectOrStixRelationships"]
|
|
576
|
+
)
|
|
577
|
+
final_data = final_data + data
|
|
578
|
+
return final_data
|
|
579
|
+
else:
|
|
580
|
+
return self.opencti.process_multiple(
|
|
581
|
+
result["data"]["stixObjectOrStixRelationships"], with_pagination
|
|
582
|
+
)
|
|
@@ -129,7 +129,6 @@ class MultipleRefRelationship(Enum):
|
|
|
129
129
|
CHILD = "child"
|
|
130
130
|
BODY_MULTIPART = "body-multipart"
|
|
131
131
|
VALUES = "values"
|
|
132
|
-
LINKED = "x_opencti_linked-to"
|
|
133
132
|
SERVICE_DDL = "service-dll"
|
|
134
133
|
INSTALLED_SOFTWARE = "installed-software"
|
|
135
134
|
RELATION_ANALYSIS_SCO = "analysis-sco"
|