pycti 6.6.18__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 CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- __version__ = "6.6.18"
2
+ __version__ = "6.7.0"
3
3
 
4
4
  from .api.opencti_api_client import OpenCTIApiClient
5
5
  from .api.opencti_api_connector import OpenCTIApiConnector
@@ -10,8 +10,14 @@ import requests
10
10
 
11
11
  from pycti import __version__
12
12
  from pycti.api.opencti_api_connector import OpenCTIApiConnector
13
+ from pycti.api.opencti_api_draft import OpenCTIApiDraft
14
+ from pycti.api.opencti_api_notification import OpenCTIApiNotification
15
+ from pycti.api.opencti_api_pir import OpenCTIApiPir
13
16
  from pycti.api.opencti_api_playbook import OpenCTIApiPlaybook
17
+ from pycti.api.opencti_api_public_dashboard import OpenCTIApiPublicDashboard
18
+ from pycti.api.opencti_api_trash import OpenCTIApiTrash
14
19
  from pycti.api.opencti_api_work import OpenCTIApiWork
20
+ from pycti.api.opencti_api_workspace import OpenCTIApiWorkspace
15
21
  from pycti.entities.opencti_attack_pattern import AttackPattern
16
22
  from pycti.entities.opencti_campaign import Campaign
17
23
  from pycti.entities.opencti_capability import Capability
@@ -167,9 +173,15 @@ class OpenCTIApiClient:
167
173
  self.session = requests.session()
168
174
  # Define the dependencies
169
175
  self.work = OpenCTIApiWork(self)
176
+ self.notification = OpenCTIApiNotification(self)
177
+ self.trash = OpenCTIApiTrash(self)
178
+ self.draft = OpenCTIApiDraft(self)
179
+ self.workspace = OpenCTIApiWorkspace(self)
180
+ self.public_dashboard = OpenCTIApiPublicDashboard(self)
170
181
  self.playbook = OpenCTIApiPlaybook(self)
171
182
  self.connector = OpenCTIApiConnector(self)
172
183
  self.stix2 = OpenCTIStix2(self)
184
+ self.pir = OpenCTIApiPir(self)
173
185
 
174
186
  # Define the entities
175
187
  self.vocabulary = Vocabulary(self)
@@ -0,0 +1,19 @@
1
+ class OpenCTIApiDraft:
2
+ """OpenCTIApiDraft"""
3
+
4
+ def __init__(self, api):
5
+ self.api = api
6
+
7
+ def delete(self, **kwargs):
8
+ id = kwargs.get("id", None)
9
+ query = """
10
+ mutation DraftWorkspaceDelete($id: ID!) {
11
+ draftWorkspaceDelete(id: $id)
12
+ }
13
+ """
14
+ self.api.query(
15
+ query,
16
+ {
17
+ "id": id,
18
+ },
19
+ )
@@ -0,0 +1,39 @@
1
+ class OpenCTIApiNotification:
2
+ """OpenCTIApiJob"""
3
+
4
+ def __init__(self, api):
5
+ self.api = api
6
+
7
+ def delete(self, **kwargs):
8
+ notification_id = kwargs.get("id", None)
9
+ self.api.app_logger.info(
10
+ "Deleting notifcation", {"notification_id": notification_id}
11
+ )
12
+ query = """
13
+ mutation notificationDelete($id: ID!) {
14
+ notificationDelete(id: $id)
15
+ }
16
+ """
17
+ self.api.query(query, {"id": notification_id})
18
+
19
+ def update_field(self, **kwargs):
20
+ notification_id = kwargs.get("id", None)
21
+ input = kwargs.get("input", None)
22
+ for input_value in input:
23
+ if input_value["key"] == "is_read":
24
+ is_read_value = bool(input_value["value"][0])
25
+ self.mark_as_read(notification_id, is_read_value)
26
+
27
+ def mark_as_read(self, notification_id: str, read: bool):
28
+ self.api.app_logger.info(
29
+ "Marking notifcation as read",
30
+ {"notification_id": notification_id, "read": read},
31
+ )
32
+ query = """
33
+ mutation notificationMarkRead($id: ID!, $read: Boolean!) {
34
+ notificationMarkRead(id: $id, read: $read) {
35
+ id
36
+ }
37
+ }
38
+ """
39
+ self.api.query(query, {"id": notification_id, "read": read})
@@ -0,0 +1,37 @@
1
+ class OpenCTIApiPir:
2
+ """OpenCTIApiPir"""
3
+
4
+ def __init__(self, api):
5
+ self.api = api
6
+
7
+ def pir_flag_element(self, **kwargs):
8
+ id = kwargs.get("id", None)
9
+ input = kwargs.get("input", None)
10
+ query = """
11
+ mutation PirFlagElement($id: ID!, $input: PirFlagElementInput!) {
12
+ pirFlagElement(id: $id, input: $input)
13
+ }
14
+ """
15
+ self.api.query(
16
+ query,
17
+ {
18
+ "id": id,
19
+ "input": input,
20
+ },
21
+ )
22
+
23
+ def pir_unflag_element(self, **kwargs):
24
+ id = kwargs.get("id", None)
25
+ input = kwargs.get("input", None)
26
+ query = """
27
+ mutation PirUnflagElement($id: ID!, $input: PirUnflagElementInput!) {
28
+ pirUnflagElement(id: $id, input: $input)
29
+ }
30
+ """
31
+ self.api.query(
32
+ query,
33
+ {
34
+ "id": id,
35
+ "input": input,
36
+ },
37
+ )
@@ -32,3 +32,23 @@ class OpenCTIApiPlaybook:
32
32
  "bundle": bundle,
33
33
  },
34
34
  )
35
+
36
+ def delete(self, **kwargs):
37
+ id = kwargs.get("id", None)
38
+ if id is not None:
39
+ query = """
40
+ mutation PlaybookDelete($id: ID!) {
41
+ playbookDelete(id: $id)
42
+ }
43
+ """
44
+ self.api.query(
45
+ query,
46
+ {
47
+ "id": id,
48
+ },
49
+ )
50
+ else:
51
+ self.opencti.app_logger.error(
52
+ "[stix_playbook] Cant delete playbook, missing parameters: id"
53
+ )
54
+ return None
@@ -0,0 +1,25 @@
1
+ class OpenCTIApiPublicDashboard:
2
+ """OpenCTIApiPublicDashboard"""
3
+
4
+ def __init__(self, api):
5
+ self.api = api
6
+
7
+ def delete(self, **kwargs):
8
+ id = kwargs.get("id", None)
9
+ if id is not None:
10
+ query = """
11
+ mutation PublicDashboardDelete($id: ID!) {
12
+ publicDashboardDelete(id: $id)
13
+ }
14
+ """
15
+ self.api.query(
16
+ query,
17
+ {
18
+ "id": id,
19
+ },
20
+ )
21
+ else:
22
+ self.opencti.app_logger.error(
23
+ "[stix_public_dashboard] Cant delete public dashboard, missing parameters: id"
24
+ )
25
+ return None
@@ -0,0 +1,42 @@
1
+ class OpenCTIApiTrash:
2
+ """OpenCTIApiTrash"""
3
+
4
+ def __init__(self, api):
5
+ self.api = api
6
+
7
+ def restore(self, operation_id: str):
8
+ query = """
9
+ mutation DeleteOperationRestore($id: ID!) {
10
+ deleteOperationRestore(id: $id)
11
+ }
12
+ """
13
+ self.api.query(
14
+ query,
15
+ {
16
+ "id": operation_id,
17
+ },
18
+ )
19
+
20
+ def delete(self, **kwargs):
21
+ """Delete a trash item given its ID
22
+
23
+ :param id: ID for the delete operation on the platform.
24
+ :type id: str
25
+ """
26
+ id = kwargs.get("id", None)
27
+ if id is None:
28
+ self.api.admin_logger.error(
29
+ "[opencti_trash] Cant confirm delete, missing parameter: id"
30
+ )
31
+ return None
32
+ query = """
33
+ mutation DeleteOperationConfirm($id: ID!) {
34
+ deleteOperationConfirm(id: $id)
35
+ }
36
+ """
37
+ self.api.query(
38
+ query,
39
+ {
40
+ "id": id,
41
+ },
42
+ )
@@ -131,6 +131,25 @@ class OpenCTIApiWork:
131
131
  work = self.api.query(query, {"workId": work_id}, True)
132
132
  return work["data"]
133
133
 
134
+ def delete(self, **kwargs):
135
+ id = kwargs.get("id", None)
136
+ if id is None:
137
+ self.opencti.admin_logger.error(
138
+ "[opencti_work] Cant delete work, missing parameter: id"
139
+ )
140
+ return None
141
+ query = """
142
+ mutation ConnectorWorksMutation($workId: ID!) {
143
+ workEdit(id: $workId) {
144
+ delete
145
+ }
146
+ }"""
147
+ work = self.api.query(
148
+ query,
149
+ {"workId": id},
150
+ )
151
+ return work["data"]
152
+
134
153
  def wait_for_work_to_finish(self, work_id: str):
135
154
  status = ""
136
155
  cnt = 0
@@ -0,0 +1,24 @@
1
+ class OpenCTIApiWorkspace:
2
+ """OpenCTIApiWorkspace"""
3
+
4
+ def __init__(self, api):
5
+ self.api = api
6
+
7
+ def delete(self, **kwargs):
8
+ id = kwargs.get("id", None)
9
+ if id is None:
10
+ self.api.admin_logger.error(
11
+ "[opencti_workspace] Cant delete workspace, missing parameter: id"
12
+ )
13
+ return None
14
+ query = """
15
+ mutation WorkspaceDelete($id: ID!) {
16
+ workspaceDelete(id: $id)
17
+ }
18
+ """
19
+ self.api.query(
20
+ query,
21
+ {
22
+ "id": id,
23
+ },
24
+ )
@@ -315,12 +315,18 @@ class Group:
315
315
  )
316
316
  return self.opencti.process_multiple_fields(result["data"]["groupAdd"])
317
317
 
318
- def delete(self, id: str):
318
+ def delete(self, **kwargs):
319
319
  """Delete a given group from OpenCTI
320
320
 
321
321
  :param id: ID of the group to delete.
322
322
  :type id: str
323
323
  """
324
+ id = kwargs.get("id", None)
325
+ if id is None:
326
+ self.opencti.admin_logger.error(
327
+ "[opencti_group] Cant delete group, missing parameter: id"
328
+ )
329
+ return None
324
330
  self.opencti.admin_logger.info("Deleting group", {"id": id})
325
331
  query = """
326
332
  mutation GroupDelete($id: ID!) {
@@ -51,11 +51,15 @@ class Identity:
51
51
  }
52
52
  ... on Organization {
53
53
  x_opencti_organization_type
54
+ x_opencti_score
54
55
  }
55
56
  ... on Individual {
56
57
  x_opencti_firstname
57
58
  x_opencti_lastname
58
59
  }
60
+ ... on SecurityPlatform {
61
+ security_platform_type
62
+ }
59
63
  }
60
64
  objectMarking {
61
65
  id
@@ -110,6 +114,10 @@ class Identity:
110
114
  }
111
115
  ... on Organization {
112
116
  x_opencti_organization_type
117
+ x_opencti_score
118
+ }
119
+ ... on SecurityPlatform {
120
+ security_platform_type
113
121
  }
114
122
  """
115
123
  self.properties_with_files = """
@@ -152,11 +160,15 @@ class Identity:
152
160
  }
153
161
  ... on Organization {
154
162
  x_opencti_organization_type
163
+ x_opencti_score
155
164
  }
156
165
  ... on Individual {
157
166
  x_opencti_firstname
158
167
  x_opencti_lastname
159
168
  }
169
+ ... on SecurityPlatform {
170
+ security_platform_type
171
+ }
160
172
  }
161
173
  objectMarking {
162
174
  id
@@ -224,6 +236,10 @@ class Identity:
224
236
  }
225
237
  ... on Organization {
226
238
  x_opencti_organization_type
239
+ x_opencti_score
240
+ }
241
+ ... on SecurityPlatform {
242
+ security_platform_type
227
243
  }
228
244
  importFiles {
229
245
  edges {
@@ -410,8 +426,10 @@ class Identity:
410
426
  contact_information = kwargs.get("contact_information", None)
411
427
  roles = kwargs.get("roles", None)
412
428
  x_opencti_aliases = kwargs.get("x_opencti_aliases", None)
429
+ security_platform_type = kwargs.get("security_platform_type", None)
413
430
  x_opencti_organization_type = kwargs.get("x_opencti_organization_type", None)
414
431
  x_opencti_reliability = kwargs.get("x_opencti_reliability", None)
432
+ x_opencti_score = kwargs.get("x_opencti_score", None)
415
433
  x_opencti_firstname = kwargs.get("x_opencti_firstname", None)
416
434
  x_opencti_lastname = kwargs.get("x_opencti_lastname", None)
417
435
  x_opencti_stix_ids = kwargs.get("x_opencti_stix_ids", None)
@@ -456,7 +474,26 @@ class Identity:
456
474
  x_opencti_organization_type
457
475
  )
458
476
  input_variables["x_opencti_reliability"] = x_opencti_reliability
477
+ input_variables["x_opencti_score"] = x_opencti_score
459
478
  result_data_field = "organizationAdd"
479
+ elif type == IdentityTypes.SECURITYPLATFORM.value:
480
+ query = """
481
+ mutation SecurityPlatformAdd($input: SecurityPlatformAddInput!) {
482
+ securityPlatformAdd(input: $input) {
483
+ id
484
+ standard_id
485
+ entity_type
486
+ parent_types
487
+ }
488
+ }
489
+ """
490
+ input_variables["security_platform_type"] = security_platform_type
491
+ # no need for these attributes for security platform
492
+ del input_variables["contact_information"]
493
+ del input_variables["lang"]
494
+ del input_variables["roles"]
495
+ del input_variables["x_opencti_aliases"]
496
+ result_data_field = "securityPlatformAdd"
460
497
  elif type == IdentityTypes.INDIVIDUAL.value:
461
498
  query = """
462
499
  mutation IndividualAdd($input: IndividualAddInput!) {
@@ -536,6 +573,8 @@ class Identity:
536
573
  type = "Sector"
537
574
  elif stix_object["identity_class"] == "system":
538
575
  type = "System"
576
+ elif stix_object["identity_class"] == "securityplatform":
577
+ type = "SecurityPlatform"
539
578
 
540
579
  # Search in extensions
541
580
  if "x_opencti_aliases" not in stix_object:
@@ -548,10 +587,20 @@ class Identity:
548
587
  "organization_type", stix_object
549
588
  )
550
589
  )
590
+ if "security_platform_type" not in stix_object:
591
+ stix_object["security_platform_type"] = (
592
+ self.opencti.get_attribute_in_extension(
593
+ "security_platform_type", stix_object
594
+ )
595
+ )
551
596
  if "x_opencti_reliability" not in stix_object:
552
597
  stix_object["x_opencti_reliability"] = (
553
598
  self.opencti.get_attribute_in_extension("reliability", stix_object)
554
599
  )
600
+ if "x_opencti_score" not in stix_object:
601
+ stix_object["x_opencti_score"] = (
602
+ self.opencti.get_attribute_in_extension("score", stix_object)
603
+ )
555
604
  if "x_opencti_organization_type" not in stix_object:
556
605
  stix_object["x_opencti_organization_type"] = (
557
606
  self.opencti.get_attribute_in_extension(
@@ -625,11 +674,21 @@ class Identity:
625
674
  if "x_opencti_organization_type" in stix_object
626
675
  else None
627
676
  ),
677
+ security_platform_type=(
678
+ stix_object["security_platform_type"]
679
+ if "security_platform_type" in stix_object
680
+ else None
681
+ ),
628
682
  x_opencti_reliability=(
629
683
  stix_object["x_opencti_reliability"]
630
684
  if "x_opencti_reliability" in stix_object
631
685
  else None
632
686
  ),
687
+ x_opencti_score=(
688
+ stix_object["x_opencti_score"]
689
+ if "x_opencti_score" in stix_object
690
+ else None
691
+ ),
633
692
  x_opencti_firstname=(
634
693
  stix_object["x_opencti_firstname"]
635
694
  if "x_opencti_firstname" in stix_object
@@ -301,6 +301,43 @@ class Indicator:
301
301
  "name or pattern or pattern_type or x_opencti_main_observable_type"
302
302
  )
303
303
 
304
+ """
305
+ Update an Indicator object field
306
+
307
+ :param id: the Indicator id
308
+ :param input: the input of the field
309
+ """
310
+
311
+ def update_field(self, **kwargs):
312
+ id = kwargs.get("id", None)
313
+ input = kwargs.get("input", None)
314
+ if id is not None and input is not None:
315
+ self.opencti.app_logger.info("Updating Indicator", {"id": id})
316
+ query = """
317
+ mutation IndicatorFieldPatch($id: ID!, $input: [EditInput!]!) {
318
+ indicatorFieldPatch(id: $id, input: $input) {
319
+ id
320
+ standard_id
321
+ entity_type
322
+ }
323
+ }
324
+ """
325
+ result = self.opencti.query(
326
+ query,
327
+ {
328
+ "id": id,
329
+ "input": input,
330
+ },
331
+ )
332
+ return self.opencti.process_multiple_fields(
333
+ result["data"]["indicatorFieldPatch"]
334
+ )
335
+ else:
336
+ self.opencti.app_logger.error(
337
+ "[opencti_stix_domain_object] Cant update indicator field, missing parameters: id and input"
338
+ )
339
+ return None
340
+
304
341
  def add_stix_cyber_observable(self, **kwargs):
305
342
  """
306
343
  Add a Stix-Cyber-Observable object to Indicator object (based-on)
@@ -11,16 +11,17 @@ class Stix:
11
11
 
12
12
  def delete(self, **kwargs):
13
13
  id = kwargs.get("id", None)
14
+ force_delete = kwargs.get("force_delete", True)
14
15
  if id is not None:
15
16
  self.opencti.app_logger.info("Deleting Stix element", {"id": id})
16
17
  query = """
17
- mutation StixEdit($id: ID!) {
18
+ mutation StixEdit($id: ID!, $forceDelete: Boolean) {
18
19
  stixEdit(id: $id) {
19
- delete
20
+ delete(forceDelete: $forceDelete)
20
21
  }
21
22
  }
22
23
  """
23
- self.opencti.query(query, {"id": id})
24
+ self.opencti.query(query, {"id": id, "forceDelete": force_delete})
24
25
  else:
25
26
  self.opencti.app_logger.error("[opencti_stix] Missing parameters: id")
26
27
  return None