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.

Files changed (73) hide show
  1. {pycti-6.0.10 → pycti-6.1.1}/PKG-INFO +2 -2
  2. {pycti-6.0.10 → pycti-6.1.1}/pycti/__init__.py +1 -1
  3. {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_client.py +15 -5
  4. {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_playbook.py +3 -2
  5. {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/opencti_connector_helper.py +10 -6
  6. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_case_incident.py +1 -1
  7. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_intrusion_set.py +34 -14
  8. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_report.py +13 -0
  9. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_core_object.py +32 -5
  10. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_cyber_observable.py +23 -3
  11. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_domain_object.py +27 -7
  12. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_object_or_stix_relationship.py +88 -4
  13. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/constants.py +0 -1
  14. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2.py +269 -187
  15. {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/PKG-INFO +2 -2
  16. {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/requires.txt +1 -1
  17. {pycti-6.0.10 → pycti-6.1.1}/setup.cfg +1 -1
  18. {pycti-6.0.10 → pycti-6.1.1}/LICENSE +0 -0
  19. {pycti-6.0.10 → pycti-6.1.1}/README.md +0 -0
  20. {pycti-6.0.10 → pycti-6.1.1}/pycti/api/__init__.py +0 -0
  21. {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_connector.py +0 -0
  22. {pycti-6.0.10 → pycti-6.1.1}/pycti/api/opencti_api_work.py +0 -0
  23. {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/__init__.py +0 -0
  24. {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/opencti_connector.py +0 -0
  25. {pycti-6.0.10 → pycti-6.1.1}/pycti/connector/opencti_metric_handler.py +0 -0
  26. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/__init__.py +0 -0
  27. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_attack_pattern.py +0 -0
  28. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_campaign.py +0 -0
  29. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_case_rfi.py +0 -0
  30. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_case_rft.py +0 -0
  31. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_channel.py +0 -0
  32. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_course_of_action.py +0 -0
  33. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_data_component.py +0 -0
  34. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_data_source.py +0 -0
  35. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_event.py +0 -0
  36. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_external_reference.py +0 -0
  37. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_feedback.py +0 -0
  38. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_grouping.py +0 -0
  39. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_identity.py +0 -0
  40. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_incident.py +0 -0
  41. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_indicator.py +0 -0
  42. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_infrastructure.py +0 -0
  43. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_kill_chain_phase.py +0 -0
  44. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_label.py +0 -0
  45. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_language.py +0 -0
  46. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_location.py +0 -0
  47. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_malware.py +0 -0
  48. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_malware_analysis.py +0 -0
  49. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_marking_definition.py +0 -0
  50. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_narrative.py +0 -0
  51. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_note.py +0 -0
  52. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_observed_data.py +0 -0
  53. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_opinion.py +0 -0
  54. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix.py +0 -0
  55. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_core_relationship.py +0 -0
  56. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_nested_ref_relationship.py +0 -0
  57. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_stix_sighting_relationship.py +0 -0
  58. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_task.py +0 -0
  59. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_threat_actor.py +0 -0
  60. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_threat_actor_group.py +0 -0
  61. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_threat_actor_individual.py +0 -0
  62. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_tool.py +0 -0
  63. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_vocabulary.py +0 -0
  64. {pycti-6.0.10 → pycti-6.1.1}/pycti/entities/opencti_vulnerability.py +0 -0
  65. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/__init__.py +0 -0
  66. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_logger.py +0 -0
  67. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2_splitter.py +0 -0
  68. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2_update.py +0 -0
  69. {pycti-6.0.10 → pycti-6.1.1}/pycti/utils/opencti_stix2_utils.py +0 -0
  70. {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/SOURCES.txt +0 -0
  71. {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/dependency_links.txt +0 -0
  72. {pycti-6.0.10 → pycti-6.1.1}/pycti.egg-info/top_level.txt +0 -0
  73. {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.0.10
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.1.1; extra == "dev"
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
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- __version__ = "6.0.10"
2
+ __version__ = "6.1.1"
3
3
 
4
4
  from .api.opencti_api_client import OpenCTIApiClient
5
5
  from .api.opencti_api_connector import OpenCTIApiConnector
@@ -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 respons for the file upload
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
- return self.query(query, {"file": (File(file_name, data, mime_type))})
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
- playbook_id = json_data["internal"]["playbook"]["playbook_id"]
288
- data_instance_id = json_data["internal"]["playbook"][
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(copy.copy(opencti_entity))
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["date"]["caseIncidents"]["pageInfo"]["endCursor"]
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
- result = self.opencti.query(
279
- query,
280
- {
281
- "filters": filters,
282
- "search": search,
283
- "first": first,
284
- "after": after,
285
- "orderBy": order_by,
286
- "orderMode": order_mode,
287
- },
288
- )
289
- return self.opencti.process_multiple(
290
- result["data"]["intrusionSets"], with_pagination
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, entity_id, entity_type, file_name, data, list_filters="", mime_type=None
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, entity_id, entity_type, file_name, data, list_filters="", mime_type=None
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($entity_id: String, $entity_type: String!, $file: Upload!, $listFilters: String) {
2323
- stixCyberObservablesExportPush(entity_id: $entity_id, entity_type: $entity_type, file: $file, listFilters: $listFilters)
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, entity_id, entity_type, file_name, data, list_filters="", mime_type=None
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(self, entity_id, file_name, data, mime_type=None):
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($id: ID!, $file: Upload!) {
1363
+ mutation StixDomainObjectEdit(
1364
+ $id: ID!, $file: Upload!,
1365
+ $file_markings: [String]!
1366
+ ) {
1352
1367
  stixDomainObjectEdit(id: $id) {
1353
- exportPush(file: $file)
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(query, {"id": entity_id, "file": file})
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
- query StixObjectOrStixRelationship($id: String!) {
480
- stixObjectOrStixRelationship(id: $id) {
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"