pycti 6.5.6__py3-none-any.whl → 6.5.8__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.5.6"
2
+ __version__ = "6.5.8"
3
3
 
4
4
  from .api.opencti_api_client import OpenCTIApiClient
5
5
  from .api.opencti_api_connector import OpenCTIApiConnector
@@ -751,6 +751,7 @@ class OpenCTIApiClient:
751
751
  """
752
752
 
753
753
  connector_id = kwargs.get("connector_id", None)
754
+ work_id = kwargs.get("work_id", None)
754
755
  bundle = kwargs.get("bundle", None)
755
756
 
756
757
  if connector_id is not None and bundle is not None:
@@ -758,13 +759,13 @@ class OpenCTIApiClient:
758
759
  "Pushing a bundle to queue through API", {connector_id}
759
760
  )
760
761
  mutation = """
761
- mutation StixBundlePush($connectorId: String!, $bundle: String!) {
762
- stixBundlePush(connectorId: $connectorId, bundle: $bundle)
762
+ mutation StixBundlePush($connectorId: String!, $bundle: String!, $work_id: String) {
763
+ stixBundlePush(connectorId: $connectorId, bundle: $bundle, work_id: $work_id)
763
764
  }
764
765
  """
765
766
  return self.query(
766
767
  mutation,
767
- {"connectorId": connector_id, "bundle": bundle},
768
+ {"connectorId": connector_id, "bundle": bundle, "work_id": work_id},
768
769
  )
769
770
  else:
770
771
  self.app_logger.error(
@@ -72,6 +72,7 @@ class OpenCTIApiConnector:
72
72
  }
73
73
  listen
74
74
  listen_exchange
75
+ listen_callback_uri
75
76
  push
76
77
  push_exchange
77
78
  push_routing
@@ -43,6 +43,7 @@ class OpenCTIConnector:
43
43
  auto: bool,
44
44
  only_contextual: bool,
45
45
  playbook_compatible: bool,
46
+ listen_callback_uri=None,
46
47
  ):
47
48
  self.id = connector_id
48
49
  self.name = connector_name
@@ -56,6 +57,7 @@ class OpenCTIConnector:
56
57
  self.auto = auto
57
58
  self.only_contextual = only_contextual
58
59
  self.playbook_compatible = playbook_compatible
60
+ self.listen_callback_uri = listen_callback_uri
59
61
 
60
62
  def to_input(self) -> dict:
61
63
  """connector input to use in API query
@@ -72,5 +74,6 @@ class OpenCTIConnector:
72
74
  "auto": self.auto,
73
75
  "only_contextual": self.only_contextual,
74
76
  "playbook_compatible": self.playbook_compatible,
77
+ "listen_callback_uri": self.listen_callback_uri,
75
78
  }
76
79
  }
@@ -18,6 +18,9 @@ from queue import Queue
18
18
  from typing import Callable, Dict, List, Optional, Union
19
19
 
20
20
  import pika
21
+ import uvicorn
22
+ from fastapi import FastAPI, Request
23
+ from fastapi.responses import JSONResponse
21
24
  from filigran_sseclient import SSEClient
22
25
  from pika.exceptions import NackError, UnroutableError
23
26
  from pydantic import TypeAdapter
@@ -30,6 +33,8 @@ from pycti.utils.opencti_stix2_splitter import OpenCTIStix2Splitter
30
33
  TRUTHY: List[str] = ["yes", "true", "True"]
31
34
  FALSY: List[str] = ["no", "false", "False"]
32
35
 
36
+ app = FastAPI()
37
+
33
38
 
34
39
  def killProgramHook(etype, value, tb):
35
40
  os.kill(os.getpid(), signal.SIGTERM)
@@ -141,6 +146,35 @@ def ssl_cert_chain(ssl_context, cert_data, key_data, passphrase):
141
146
  os.unlink(key_file_path)
142
147
 
143
148
 
149
+ def create_callback_ssl_context(config) -> ssl.SSLContext:
150
+ listen_protocol_api_ssl_key = get_config_variable(
151
+ "LISTEN_PROTOCOL_API_SSL_KEY",
152
+ ["connector", "listen_protocol_api_ssl_key"],
153
+ config,
154
+ default="",
155
+ )
156
+ listen_protocol_api_ssl_cert = get_config_variable(
157
+ "LISTEN_PROTOCOL_API_SSL_CERT",
158
+ ["connector", "listen_protocol_api_ssl_cert"],
159
+ config,
160
+ default="",
161
+ )
162
+ listen_protocol_api_ssl_passphrase = get_config_variable(
163
+ "LISTEN_PROTOCOL_API_SSL_PASSPHRASE",
164
+ ["connector", "listen_protocol_api_ssl_passphrase"],
165
+ config,
166
+ default="",
167
+ )
168
+ ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
169
+ ssl_cert_chain(
170
+ ssl_context,
171
+ listen_protocol_api_ssl_cert,
172
+ listen_protocol_api_ssl_key,
173
+ listen_protocol_api_ssl_passphrase,
174
+ )
175
+ return ssl_context
176
+
177
+
144
178
  def create_mq_ssl_context(config) -> ssl.SSLContext:
145
179
  use_ssl_ca = get_config_variable("MQ_USE_SSL_CA", ["mq", "use_ssl_ca"], config)
146
180
  use_ssl_cert = get_config_variable(
@@ -183,9 +217,14 @@ class ListenQueue(threading.Thread):
183
217
  def __init__(
184
218
  self,
185
219
  helper,
220
+ opencti_token,
186
221
  config: Dict,
187
222
  connector_config: Dict,
188
223
  applicant_id,
224
+ listen_protocol,
225
+ listen_protocol_api_ssl,
226
+ listen_protocol_api_path,
227
+ listen_protocol_api_port,
189
228
  callback,
190
229
  ) -> None:
191
230
  threading.Thread.__init__(self)
@@ -196,6 +235,11 @@ class ListenQueue(threading.Thread):
196
235
  self.helper = helper
197
236
  self.callback = callback
198
237
  self.config = config
238
+ self.opencti_token = opencti_token
239
+ self.listen_protocol = listen_protocol
240
+ self.listen_protocol_api_ssl = listen_protocol_api_ssl
241
+ self.listen_protocol_api_path = listen_protocol_api_path
242
+ self.listen_protocol_api_port = listen_protocol_api_port
199
243
  self.connector_applicant_id = applicant_id
200
244
  self.host = connector_config["connection"]["host"]
201
245
  self.vhost = connector_config["connection"]["vhost"]
@@ -375,52 +419,122 @@ class ListenQueue(threading.Thread):
375
419
  "Failing reporting the processing"
376
420
  )
377
421
 
422
+ async def _http_process_callback(self, request: Request):
423
+ # 01. Check the authentication
424
+ authorization: str = request.headers.get("Authorization", "")
425
+ items = authorization.split() if isinstance(authorization, str) else []
426
+ if (
427
+ len(items) != 2
428
+ or items[0].lower() != "bearer"
429
+ or items[1] != self.opencti_token
430
+ ):
431
+ return JSONResponse(
432
+ status_code=401, content={"error": "Invalid credentials"}
433
+ )
434
+ # 02. Parse the data and execute
435
+ try:
436
+ data = await request.json() # Get the JSON payload
437
+ except json.JSONDecodeError as e:
438
+ self.helper.connector_logger.error(
439
+ "Invalid JSON payload", {"cause": str(e)}
440
+ )
441
+ return JSONResponse(
442
+ status_code=400,
443
+ content={"error": "Invalid JSON payload"},
444
+ )
445
+ try:
446
+ self._data_handler(data)
447
+ except Exception as e:
448
+ self.helper.connector_logger.error(
449
+ "Error processing message", {"cause": str(e)}
450
+ )
451
+ return JSONResponse(
452
+ status_code=500,
453
+ content={"error": "Error processing message"},
454
+ )
455
+ # all good
456
+ return JSONResponse(
457
+ status_code=202, content={"message": "Message successfully received"}
458
+ )
459
+
378
460
  def run(self) -> None:
379
- self.helper.connector_logger.info("Starting ListenQueue thread")
380
- while not self.exit_event.is_set():
381
- try:
382
- self.helper.connector_logger.info("ListenQueue connecting to rabbitMq.")
383
- # Connect the broker
384
- self.pika_credentials = pika.PlainCredentials(self.user, self.password)
385
- self.pika_parameters = pika.ConnectionParameters(
386
- heartbeat=10,
387
- blocked_connection_timeout=30,
388
- host=self.host,
389
- port=self.port,
390
- virtual_host=self.vhost,
391
- credentials=self.pika_credentials,
392
- ssl_options=(
393
- pika.SSLOptions(create_mq_ssl_context(self.config), self.host)
394
- if self.use_ssl
395
- else None
396
- ),
397
- )
398
- self.pika_connection = pika.BlockingConnection(self.pika_parameters)
399
- self.channel = self.pika_connection.channel()
461
+ if self.listen_protocol == "AMQP":
462
+ self.helper.connector_logger.info("Starting ListenQueue thread")
463
+ while not self.exit_event.is_set():
400
464
  try:
401
- # confirm_delivery is only for cluster mode rabbitMQ
402
- # when not in cluster mode this line raise an exception
403
- self.channel.confirm_delivery()
465
+ self.helper.connector_logger.info(
466
+ "ListenQueue connecting to rabbitMq."
467
+ )
468
+ # Connect the broker
469
+ self.pika_credentials = pika.PlainCredentials(
470
+ self.user, self.password
471
+ )
472
+ self.pika_parameters = pika.ConnectionParameters(
473
+ heartbeat=10,
474
+ blocked_connection_timeout=30,
475
+ host=self.host,
476
+ port=self.port,
477
+ virtual_host=self.vhost,
478
+ credentials=self.pika_credentials,
479
+ ssl_options=(
480
+ pika.SSLOptions(
481
+ create_mq_ssl_context(self.config), self.host
482
+ )
483
+ if self.use_ssl
484
+ else None
485
+ ),
486
+ )
487
+ self.pika_connection = pika.BlockingConnection(self.pika_parameters)
488
+ self.channel = self.pika_connection.channel()
489
+ try:
490
+ # confirm_delivery is only for cluster mode rabbitMQ
491
+ # when not in cluster mode this line raise an exception
492
+ self.channel.confirm_delivery()
493
+ except Exception as err: # pylint: disable=broad-except
494
+ self.helper.connector_logger.debug(str(err))
495
+ self.channel.basic_qos(prefetch_count=1)
496
+ assert self.channel is not None
497
+ self.channel.basic_consume(
498
+ queue=self.queue_name, on_message_callback=self._process_message
499
+ )
500
+ self.channel.start_consuming()
404
501
  except Exception as err: # pylint: disable=broad-except
405
- self.helper.connector_logger.debug(str(err))
406
- self.channel.basic_qos(prefetch_count=1)
407
- assert self.channel is not None
408
- self.channel.basic_consume(
409
- queue=self.queue_name, on_message_callback=self._process_message
410
- )
411
- self.channel.start_consuming()
412
- except Exception as err: # pylint: disable=broad-except
413
- try:
414
- self.pika_connection.close()
415
- except Exception as errInException:
416
- self.helper.connector_logger.debug(
417
- type(errInException).__name__, {"reason": str(errInException)}
502
+ try:
503
+ self.pika_connection.close()
504
+ except Exception as errInException:
505
+ self.helper.connector_logger.debug(
506
+ type(errInException).__name__,
507
+ {"reason": str(errInException)},
508
+ )
509
+ self.helper.connector_logger.error(
510
+ type(err).__name__, {"reason": str(err)}
418
511
  )
419
- self.helper.connector_logger.error(
420
- type(err).__name__, {"reason": str(err)}
421
- )
422
- # Wait some time and then retry ListenQueue again.
423
- time.sleep(10)
512
+ # Wait some time and then retry ListenQueue again.
513
+ time.sleep(10)
514
+ elif self.listen_protocol == "API":
515
+ self.helper.connector_logger.info("Starting Listen HTTP thread")
516
+ app.add_api_route(
517
+ self.listen_protocol_api_path,
518
+ self._http_process_callback,
519
+ methods=["POST"],
520
+ )
521
+ config = uvicorn.Config(
522
+ app,
523
+ host="0.0.0.0",
524
+ port=self.listen_protocol_api_port,
525
+ reload=False,
526
+ log_config=None,
527
+ log_level=None,
528
+ )
529
+ config.load() # Manually calling the .load() to trigger needed actions outside HTTPS
530
+ if self.listen_protocol_api_ssl:
531
+ ssl_ctx = create_callback_ssl_context(self.config)
532
+ config.ssl = ssl_ctx
533
+ server = uvicorn.Server(config)
534
+ server.run()
535
+
536
+ else:
537
+ raise ValueError("Unsupported listen protocol type")
424
538
 
425
539
  def stop(self):
426
540
  self.helper.connector_logger.info("Preparing ListenQueue for clean shutdown")
@@ -790,8 +904,39 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
790
904
  self.connect_id = get_config_variable(
791
905
  "CONNECTOR_ID", ["connector", "id"], config
792
906
  )
793
- self.queue_protocol = get_config_variable(
794
- "QUEUE_PROTOCOL", ["connector", "queue_protocol"], config, default="amqp"
907
+ self.listen_protocol = get_config_variable(
908
+ "CONNECTOR_LISTEN_PROTOCOL",
909
+ ["connector", "listen_protocol"],
910
+ config,
911
+ default="AMQP",
912
+ ).upper()
913
+ self.listen_protocol_api_port = get_config_variable(
914
+ "CONNECTOR_LISTEN_PROTOCOL_API_PORT",
915
+ ["connector", "listen_protocol_api_port"],
916
+ config,
917
+ default=7070,
918
+ )
919
+ self.listen_protocol_api_path = get_config_variable(
920
+ "CONNECTOR_LISTEN_PROTOCOL_API_PATH",
921
+ ["connector", "listen_protocol_api_path"],
922
+ config,
923
+ default="/api/callback",
924
+ )
925
+ self.listen_protocol_api_ssl = get_config_variable(
926
+ "CONNECTOR_LISTEN_PROTOCOL_API_SSL",
927
+ ["connector", "listen_protocol_api_ssl"],
928
+ config,
929
+ default=False,
930
+ )
931
+ self.listen_protocol_api_uri = get_config_variable(
932
+ "CONNECTOR_LISTEN_PROTOCOL_API_URI",
933
+ ["connector", "listen_protocol_api_uri"],
934
+ config,
935
+ default=(
936
+ "https://127.0.0.1:7070"
937
+ if self.listen_protocol_api_ssl
938
+ else "http://127.0.0.1:7070"
939
+ ),
795
940
  )
796
941
  self.connect_type = get_config_variable(
797
942
  "CONNECTOR_TYPE", ["connector", "type"], config
@@ -957,6 +1102,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
957
1102
  self.connect_auto,
958
1103
  self.connect_only_contextual,
959
1104
  playbook_compatible,
1105
+ self.listen_protocol_api_uri + self.listen_protocol_api_path,
960
1106
  )
961
1107
  connector_configuration = self.api.connector.register(self.connector)
962
1108
  self.connector_logger.info(
@@ -972,6 +1118,25 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
972
1118
  self.connector_state = connector_configuration["connector_state"]
973
1119
  self.connector_config = connector_configuration["config"]
974
1120
 
1121
+ # Configure the push information protocol
1122
+ self.queue_protocol = get_config_variable(
1123
+ env_var="CONNECTOR_QUEUE_PROTOCOL",
1124
+ yaml_path=["connector", "queue_protocol"],
1125
+ config=config,
1126
+ )
1127
+ if not self.queue_protocol: # for backwards compatibility
1128
+ self.queue_protocol = get_config_variable(
1129
+ env_var="QUEUE_PROTOCOL",
1130
+ yaml_path=["connector", "queue_protocol"],
1131
+ config=config,
1132
+ )
1133
+ if self.queue_protocol:
1134
+ self.connector_logger.error(
1135
+ "QUEUE_PROTOCOL is deprecated, please use CONNECTOR_QUEUE_PROTOCOL instead."
1136
+ )
1137
+ if not self.queue_protocol:
1138
+ self.queue_protocol = "amqp"
1139
+
975
1140
  # Overwrite connector config for RabbitMQ if given manually / in conf
976
1141
  self.connector_config["connection"]["host"] = get_config_variable(
977
1142
  "MQ_HOST",
@@ -1441,9 +1606,14 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1441
1606
 
1442
1607
  self.listen_queue = ListenQueue(
1443
1608
  self,
1609
+ self.opencti_token,
1444
1610
  self.config,
1445
1611
  self.connector_config,
1446
1612
  self.applicant_id,
1613
+ self.listen_protocol,
1614
+ self.listen_protocol_api_ssl,
1615
+ self.listen_protocol_api_path,
1616
+ self.listen_protocol_api_port,
1447
1617
  message_callback,
1448
1618
  )
1449
1619
  self.listen_queue.start()
@@ -1742,13 +1912,13 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1742
1912
  raise ValueError("Nothing to import")
1743
1913
 
1744
1914
  if bundle_send_to_queue:
1745
- if work_id:
1746
- self.api.work.add_expectations(work_id, expectations_number)
1747
- if draft_id:
1748
- self.api.work.add_draft_context(work_id, draft_id)
1915
+ if work_id and draft_id:
1916
+ self.api.work.add_draft_context(work_id, draft_id)
1749
1917
  if entities_types is None:
1750
1918
  entities_types = []
1751
1919
  if self.queue_protocol == "amqp":
1920
+ if work_id:
1921
+ self.api.work.add_expectations(work_id, expectations_number)
1752
1922
  pika_credentials = pika.PlainCredentials(
1753
1923
  self.connector_config["connection"]["user"],
1754
1924
  self.connector_config["connection"]["pass"],
@@ -1791,7 +1961,7 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1791
1961
  pika_connection.close()
1792
1962
  elif self.queue_protocol == "api":
1793
1963
  self.api.send_bundle_to_api(
1794
- connector_id=self.connector_id, bundle=bundle
1964
+ connector_id=self.connector_id, bundle=bundle, work_id=work_id
1795
1965
  )
1796
1966
  else:
1797
1967
  raise ValueError(
@@ -178,6 +178,7 @@ class ThreatActor:
178
178
  order_by = kwargs.get("orderBy", None)
179
179
  order_mode = kwargs.get("orderMode", None)
180
180
  custom_attributes = kwargs.get("customAttributes", None)
181
+ get_all = kwargs.get("getAll", False)
181
182
  with_pagination = kwargs.get("withPagination", False)
182
183
 
183
184
  self.opencti.app_logger.info(
@@ -216,9 +217,31 @@ class ThreatActor:
216
217
  "orderMode": order_mode,
217
218
  },
218
219
  )
219
- return self.opencti.process_multiple(
220
- result["data"]["threatActors"], with_pagination
221
- )
220
+ if get_all:
221
+ final_data = []
222
+ data = self.opencti.process_multiple(result["data"]["threatActors"])
223
+ final_data = final_data + data
224
+ while result["data"]["threatActors"]["pageInfo"]["hasNextPage"]:
225
+ after = result["data"]["threatActors"]["pageInfo"]["endCursor"]
226
+ self.opencti.app_logger.info("Listing threatActors", {"after": after})
227
+ result = self.opencti.query(
228
+ query,
229
+ {
230
+ "filters": filters,
231
+ "search": search,
232
+ "first": first,
233
+ "after": after,
234
+ "orderBy": order_by,
235
+ "orderMode": order_mode,
236
+ },
237
+ )
238
+ data = self.opencti.process_multiple(result["data"]["threatActors"])
239
+ final_data = final_data + data
240
+ return final_data
241
+ else:
242
+ return self.opencti.process_multiple(
243
+ result["data"]["threatActors"], with_pagination
244
+ )
222
245
 
223
246
  def read(self, **kwargs) -> Union[dict, None]:
224
247
  """Read a Threat-Actor object
@@ -171,6 +171,7 @@ class ThreatActorGroup:
171
171
  order_by = kwargs.get("orderBy", None)
172
172
  order_mode = kwargs.get("orderMode", None)
173
173
  custom_attributes = kwargs.get("customAttributes", None)
174
+ get_all = kwargs.get("getAll", False)
174
175
  with_pagination = kwargs.get("withPagination", False)
175
176
 
176
177
  self.opencti.app_logger.info(
@@ -209,9 +210,35 @@ class ThreatActorGroup:
209
210
  "orderMode": order_mode,
210
211
  },
211
212
  )
212
- return self.opencti.process_multiple(
213
- result["data"]["threatActorsGroup"], with_pagination
214
- )
213
+ if get_all:
214
+ final_data = []
215
+ data = self.opencti.process_multiple(result["data"]["threatActorsGroup"])
216
+ final_data = final_data + data
217
+ while result["data"]["threatActorsGroup"]["pageInfo"]["hasNextPage"]:
218
+ after = result["data"]["threatActorsGroup"]["pageInfo"]["endCursor"]
219
+ self.opencti.app_logger.info(
220
+ "Listing threatActorsGroup", {"after": after}
221
+ )
222
+ result = self.opencti.query(
223
+ query,
224
+ {
225
+ "filters": filters,
226
+ "search": search,
227
+ "first": first,
228
+ "after": after,
229
+ "orderBy": order_by,
230
+ "orderMode": order_mode,
231
+ },
232
+ )
233
+ data = self.opencti.process_multiple(
234
+ result["data"]["threatActorsGroup"]
235
+ )
236
+ final_data = final_data + data
237
+ return final_data
238
+ else:
239
+ return self.opencti.process_multiple(
240
+ result["data"]["threatActorsGroup"], with_pagination
241
+ )
215
242
 
216
243
  def read(self, **kwargs) -> Union[dict, None]:
217
244
  """Read a Threat-Actor-Group object
@@ -171,6 +171,7 @@ class ThreatActorIndividual:
171
171
  order_by = kwargs.get("orderBy", None)
172
172
  order_mode = kwargs.get("orderMode", None)
173
173
  custom_attributes = kwargs.get("customAttributes", None)
174
+ get_all = kwargs.get("getAll", False)
174
175
  with_pagination = kwargs.get("withPagination", False)
175
176
 
176
177
  self.opencti.app_logger.info(
@@ -210,9 +211,39 @@ class ThreatActorIndividual:
210
211
  "orderMode": order_mode,
211
212
  },
212
213
  )
213
- return self.opencti.process_multiple(
214
- result["data"]["threatActorsIndividuals"], with_pagination
215
- )
214
+ if get_all:
215
+ final_data = []
216
+ data = self.opencti.process_multiple(
217
+ result["data"]["threatActorsIndividuals"]
218
+ )
219
+ final_data = final_data + data
220
+ while result["data"]["threatActorsIndividuals"]["pageInfo"]["hasNextPage"]:
221
+ after = result["data"]["threatActorsIndividuals"]["pageInfo"][
222
+ "endCursor"
223
+ ]
224
+ self.opencti.app_logger.info(
225
+ "Listing threatActorsIndividuals", {"after": after}
226
+ )
227
+ result = self.opencti.query(
228
+ query,
229
+ {
230
+ "filters": filters,
231
+ "search": search,
232
+ "first": first,
233
+ "after": after,
234
+ "orderBy": order_by,
235
+ "orderMode": order_mode,
236
+ },
237
+ )
238
+ data = self.opencti.process_multiple(
239
+ result["data"]["threatActorsIndividuals"]
240
+ )
241
+ final_data = final_data + data
242
+ return final_data
243
+ else:
244
+ return self.opencti.process_multiple(
245
+ result["data"]["threatActorsIndividuals"], with_pagination
246
+ )
216
247
 
217
248
  def read(self, **kwargs) -> Union[dict, None]:
218
249
  """Read a Threat-Actor-Individual object
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pycti
3
- Version: 6.5.6
3
+ Version: 6.5.8
4
4
  Summary: Python API client for OpenCTI.
5
5
  Home-page: https://github.com/OpenCTI-Platform/client-python
6
6
  Author: Filigran
@@ -28,13 +28,15 @@ Requires-Dist: python-magic~=0.4.27; sys_platform == "linux" or sys_platform ==
28
28
  Requires-Dist: python-magic-bin~=0.4.14; sys_platform == "win32"
29
29
  Requires-Dist: python_json_logger~=2.0.4
30
30
  Requires-Dist: PyYAML~=6.0
31
- Requires-Dist: requests~=2.32.2
31
+ Requires-Dist: requests<=2.32.3,>=2.32.0
32
32
  Requires-Dist: setuptools~=71.1.0
33
33
  Requires-Dist: cachetools~=5.5.0
34
34
  Requires-Dist: prometheus-client~=0.21.1
35
35
  Requires-Dist: opentelemetry-api<=1.30.0,>=1.22.0
36
36
  Requires-Dist: opentelemetry-sdk<=1.30.0,>=1.22.0
37
37
  Requires-Dist: deprecation~=2.1.0
38
+ Requires-Dist: fastapi<0.116.0,>=0.115.8
39
+ Requires-Dist: uvicorn[standard]<0.35.0,>=0.33.0
38
40
  Requires-Dist: filigran-sseclient>=1.0.2
39
41
  Requires-Dist: stix2~=3.0.1
40
42
  Provides-Extra: dev
@@ -1,12 +1,12 @@
1
- pycti/__init__.py,sha256=8Qm7LDreYXpxsLc-IqTQcRdPomwsSoWCyd22fTZSa_s,5218
1
+ pycti/__init__.py,sha256=Jx64e7EmY0sso4XUf7Z80mh3mf64-Jmv6goncnzLrSM,5218
2
2
  pycti/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- pycti/api/opencti_api_client.py,sha256=6TKvtgAk0iYQL2RaLTUV6cxCBefEgwmlL_iVHgzf_ow,32745
4
- pycti/api/opencti_api_connector.py,sha256=ubM_zPjTD8L33TEugCQgf_YF9zugDFg_7FgNubGlwJw,5447
3
+ pycti/api/opencti_api_client.py,sha256=l-k8UclU4-yyc0rn_N3CZcRDiHUmD4-boOnQ6mngCO8,32848
4
+ pycti/api/opencti_api_connector.py,sha256=ZCatDnkwqGvNwtagd3f3MziG4nuplGj7BEw8xSXh47o,5491
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
- pycti/connector/opencti_connector.py,sha256=5oVvS27KWhzRiofJAeQPDtba-EP83FziSistyEd5l-U,2561
9
- pycti/connector/opencti_connector_helper.py,sha256=ee8Ej43Ox9W7G44PEfHNGZuU_NmBVNl7dE3V3BzE4sE,81286
8
+ pycti/connector/opencti_connector.py,sha256=8lCZFvcA9-S1x6vFl756hgWAlzKfrnq-C4AIdDJr-Kg,2715
9
+ pycti/connector/opencti_connector_helper.py,sha256=r8xu5frk0zD0HUBn5xG9aXH1H5QvpydXsC7fUzq_85k,87688
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=QXJaMMZlnVCxxHGZNGSKPLmHL3TgM08aUIS8SypmIek,22193
@@ -48,9 +48,9 @@ pycti/entities/opencti_stix_nested_ref_relationship.py,sha256=7USJlfTanPFY16aFIH
48
48
  pycti/entities/opencti_stix_object_or_stix_relationship.py,sha256=5qutzML6SyYzDhZ-QpI9Vh23hzLEs-xeFAAZOpGHZ2g,18049
49
49
  pycti/entities/opencti_stix_sighting_relationship.py,sha256=PO4RK3UBkA2b_xcqjiqWnLSKgvaQy291al_yunQ96h4,28736
50
50
  pycti/entities/opencti_task.py,sha256=rYfiUKtsSEq8A-Qa2wi7QBias1oiiHsaq3g_aLcWgl0,25290
51
- pycti/entities/opencti_threat_actor.py,sha256=Fk33LU8lsCP0SMMaA0SkT7fLZLmjddMi_-9PUJToDuM,10156
52
- pycti/entities/opencti_threat_actor_group.py,sha256=DuLT4DlAEtS7yQVbkFcAbPcyWsrdwYX5XBevsVuprxY,19515
53
- pycti/entities/opencti_threat_actor_individual.py,sha256=IhfsRBXvR73fwUQ5JYZ2GsRHuzVb92l6JaKvaqTdKp0,19767
51
+ pycti/entities/opencti_threat_actor.py,sha256=vFPeo0pOYSqHBKVlWc4o8RjuP2PP0A09KWU6rsYXnvA,11201
52
+ pycti/entities/opencti_threat_actor_group.py,sha256=ANvs1C_ugpYv_jNwW9mOwn4jXKTmkV7tL5wdPgt3PXA,20661
53
+ pycti/entities/opencti_threat_actor_individual.py,sha256=i41YIdC7Mc5qMzdYmzItI1qVdDqngqsA1kMWGngRDGo,21011
54
54
  pycti/entities/opencti_tool.py,sha256=YbOp0Ur5Do7ToLzfIKGX-MtlBQf-Dt9Qtgk1lI9Q7aU,15295
55
55
  pycti/entities/opencti_vocabulary.py,sha256=xupdHJ6TznCmvI3sVYU261SnfblSNc1nwg19MG9yrao,6499
56
56
  pycti/entities/opencti_vulnerability.py,sha256=ssMH7EB7WC--Nv2bq-D-_wLBGXMgP3ZLK-X8SslpVJQ,22614
@@ -67,8 +67,8 @@ pycti/utils/opencti_stix2_identifier.py,sha256=k8L1z4q1xdCBfxqUba4YS_kT-MmbJFxYh
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.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
71
- pycti-6.5.6.dist-info/METADATA,sha256=0Glf-tGlglFdyp3ZHGThkKn0koXL6ORGbnGAws8Ixdg,5443
72
- pycti-6.5.6.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
73
- pycti-6.5.6.dist-info/top_level.txt,sha256=cqEpxitAhHP4VgSA6xmrak6Yk9MeBkwoMTB6k7d2ZnE,6
74
- pycti-6.5.6.dist-info/RECORD,,
70
+ pycti-6.5.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
71
+ pycti-6.5.8.dist-info/METADATA,sha256=jKpN0aP7v8pSiR0pew5dv3jnb8C3JB9CPh6tf2qLn7g,5542
72
+ pycti-6.5.8.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
73
+ pycti-6.5.8.dist-info/top_level.txt,sha256=cqEpxitAhHP4VgSA6xmrak6Yk9MeBkwoMTB6k7d2ZnE,6
74
+ pycti-6.5.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (76.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
File without changes