pangea-sdk 3.8.0b1__py3-none-any.whl → 5.3.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.
Files changed (48) hide show
  1. pangea/__init__.py +1 -1
  2. pangea/asyncio/file_uploader.py +1 -1
  3. pangea/asyncio/request.py +49 -31
  4. pangea/asyncio/services/__init__.py +2 -0
  5. pangea/asyncio/services/audit.py +192 -31
  6. pangea/asyncio/services/authn.py +187 -109
  7. pangea/asyncio/services/authz.py +285 -0
  8. pangea/asyncio/services/base.py +21 -2
  9. pangea/asyncio/services/embargo.py +2 -2
  10. pangea/asyncio/services/file_scan.py +24 -9
  11. pangea/asyncio/services/intel.py +108 -34
  12. pangea/asyncio/services/redact.py +72 -4
  13. pangea/asyncio/services/sanitize.py +217 -0
  14. pangea/asyncio/services/share.py +246 -73
  15. pangea/asyncio/services/vault.py +1710 -750
  16. pangea/crypto/rsa.py +135 -0
  17. pangea/deep_verify.py +7 -1
  18. pangea/dump_audit.py +9 -8
  19. pangea/request.py +83 -59
  20. pangea/response.py +49 -31
  21. pangea/services/__init__.py +2 -0
  22. pangea/services/audit/audit.py +205 -42
  23. pangea/services/audit/models.py +56 -8
  24. pangea/services/audit/signing.py +6 -5
  25. pangea/services/audit/util.py +3 -3
  26. pangea/services/authn/authn.py +140 -70
  27. pangea/services/authn/models.py +167 -11
  28. pangea/services/authz.py +400 -0
  29. pangea/services/base.py +39 -8
  30. pangea/services/embargo.py +2 -2
  31. pangea/services/file_scan.py +32 -15
  32. pangea/services/intel.py +157 -32
  33. pangea/services/redact.py +152 -4
  34. pangea/services/sanitize.py +388 -0
  35. pangea/services/share/share.py +683 -107
  36. pangea/services/vault/models/asymmetric.py +120 -18
  37. pangea/services/vault/models/common.py +439 -141
  38. pangea/services/vault/models/keys.py +94 -0
  39. pangea/services/vault/models/secret.py +27 -3
  40. pangea/services/vault/models/symmetric.py +68 -22
  41. pangea/services/vault/vault.py +1690 -749
  42. pangea/tools.py +6 -7
  43. pangea/utils.py +16 -27
  44. pangea/verify_audit.py +270 -83
  45. {pangea_sdk-3.8.0b1.dist-info → pangea_sdk-5.3.0.dist-info}/METADATA +43 -35
  46. pangea_sdk-5.3.0.dist-info/RECORD +56 -0
  47. {pangea_sdk-3.8.0b1.dist-info → pangea_sdk-5.3.0.dist-info}/WHEEL +1 -1
  48. pangea_sdk-3.8.0b1.dist-info/RECORD +0 -50
pangea/services/base.py CHANGED
@@ -1,23 +1,40 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
3
4
 
4
5
  import copy
5
6
  import logging
6
7
  from typing import Dict, Optional, Type, Union
7
8
 
9
+ from typing_extensions import TypeVar
10
+
8
11
  from pangea.asyncio.request import PangeaRequestAsync
9
12
  from pangea.config import PangeaConfig
10
13
  from pangea.exceptions import AcceptedRequestException
11
14
  from pangea.request import PangeaRequest
12
15
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
13
16
 
17
+ TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
18
+
14
19
 
15
20
  class ServiceBase(object):
16
21
  service_name: str = "base"
17
22
 
18
23
  def __init__(
19
- self, token, config: Optional[PangeaConfig] = None, logger_name: str = "pangea", config_id: Optional[str] = None
20
- ):
24
+ self,
25
+ token: str,
26
+ config: PangeaConfig | None = None,
27
+ logger_name: str = "pangea",
28
+ config_id: str | None = None,
29
+ ) -> None:
30
+ """
31
+ Initializes a new Pangea service client.
32
+
33
+ Args:
34
+ token: Pangea API token.
35
+ config: Configuration.
36
+ logger_name: Logger name.
37
+ """
21
38
  if not token:
22
39
  raise Exception("No token provided")
23
40
 
@@ -30,11 +47,11 @@ class ServiceBase(object):
30
47
  self.request.set_extra_headers(extra_headers)
31
48
 
32
49
  @property
33
- def token(self):
50
+ def token(self) -> str:
34
51
  return self._token
35
52
 
36
53
  @token.setter
37
- def token(self, value):
54
+ def token(self, value: str) -> None:
38
55
  self._token = value
39
56
 
40
57
  @property
@@ -55,15 +72,16 @@ class ServiceBase(object):
55
72
  exception: Optional[AcceptedRequestException] = None,
56
73
  response: Optional[PangeaResponse] = None,
57
74
  request_id: Optional[str] = None,
58
- result_class: Union[Type[PangeaResponseResult], Type[Dict]] = dict,
59
- ) -> PangeaResponse:
75
+ result_class: Type[TResult] = PangeaResponseResult, # type: ignore[assignment]
76
+ ) -> PangeaResponse[TResult]:
60
77
  """
61
78
  Poll result
62
79
 
63
80
  Returns request's result that has been accepted by the server
64
81
 
65
82
  Args:
66
- exception (AcceptedRequestException): Exception raise by SDK on the call that is been processed.
83
+ exception: Exception that was previously raised by the SDK on a call
84
+ that is being processed.
67
85
 
68
86
  Returns:
69
87
  PangeaResponse
@@ -83,5 +101,18 @@ class ServiceBase(object):
83
101
  else:
84
102
  raise AttributeError("Need to set exception, response or request_id")
85
103
 
86
- def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile:
104
+ def download_file(self, url: str, filename: str | None = None) -> AttachedFile:
105
+ """
106
+ Download file
107
+
108
+ Download a file from the specified URL and save it with the given
109
+ filename.
110
+
111
+ Args:
112
+ url: URL of the file to download
113
+ filename: Name to save the downloaded file as. If not provided, the
114
+ filename will be determined from the Content-Disposition header or
115
+ the URL.
116
+ """
117
+
87
118
  return self.request.download_file(url=url, filename=filename)
@@ -103,7 +103,7 @@ class Embargo(ServiceBase):
103
103
  response = embargo.ip_check("190.6.64.94")
104
104
  """
105
105
  input = IPCheckRequest(ip=ip)
106
- return self.request.post("v1/ip/check", EmbargoResult, data=input.dict())
106
+ return self.request.post("v1/ip/check", EmbargoResult, data=input.model_dump())
107
107
 
108
108
  def iso_check(self, iso_code: str) -> PangeaResponse[EmbargoResult]:
109
109
  """
@@ -130,4 +130,4 @@ class Embargo(ServiceBase):
130
130
  response = embargo.iso_check("CU")
131
131
  """
132
132
  input = ISOCheckRequest(iso_code=iso_code)
133
- return self.request.post("v1/iso/check", result_class=EmbargoResult, data=input.dict())
133
+ return self.request.post("v1/iso/check", result_class=EmbargoResult, data=input.model_dump())
@@ -11,22 +11,25 @@ from pangea.utils import FileUploadParams, get_file_upload_params
11
11
 
12
12
 
13
13
  class FileScanRequest(APIRequestModel):
14
- """
15
- File Scan request data
16
-
17
- provider (str, optional): Provider of the information. Default provider defined by the configuration.
18
- verbose (bool, optional): Echo back the parameters of the API in the response
19
- raw (bool, optional): Return additional details from the provider.
20
- """
14
+ """File Scan request data."""
21
15
 
22
16
  verbose: Optional[bool] = None
17
+ """Echo back the parameters of the API in the response."""
18
+
23
19
  raw: Optional[bool] = None
20
+ """Return additional details from the provider."""
21
+
24
22
  provider: Optional[str] = None
23
+ """Provider of the information. Default provider defined by the configuration."""
24
+
25
25
  size: Optional[int] = None
26
26
  crc32c: Optional[str] = None
27
27
  sha256: Optional[str] = None
28
28
  source_url: Optional[str] = None
29
+ """A URL where the file to be scanned can be downloaded."""
30
+
29
31
  transfer_method: TransferMethod = TransferMethod.POST_URL
32
+ """The transfer method used to upload the file data."""
30
33
 
31
34
 
32
35
  class FileScanData(PangeaResponseResult):
@@ -71,7 +74,6 @@ class FileScan(ServiceBase):
71
74
  """
72
75
 
73
76
  service_name = "file-scan"
74
- version = "v1"
75
77
 
76
78
  def file_scan(
77
79
  self,
@@ -92,12 +94,14 @@ class FileScan(ServiceBase):
92
94
  OperationId: file_scan_post_v1_scan
93
95
 
94
96
  Args:
95
- file (io.BufferedReader, optional): file to be scanned (should be opened with read permissions and in binary format)
96
97
  file_path (str, optional): filepath to be opened and scanned
98
+ file (io.BufferedReader, optional): file to be scanned (should be opened with read permissions and in binary format)
97
99
  verbose (bool, optional): Echo the API parameters in the response
98
100
  raw (bool, optional): Include raw data from this provider
99
101
  provider (str, optional): Scan file using this provider
100
102
  sync_call (bool, optional): True to wait until server returns a result, False to return immediately and retrieve result asynchronously
103
+ transfer_method (TransferMethod, optional): Transfer method used to upload the file data.
104
+ source_url (str, optional): A URL where the Pangea APIs can fetch the contents of the input file.
101
105
 
102
106
  Raises:
103
107
  PangeaAPIException: If an API Error happens
@@ -118,6 +122,15 @@ class FileScan(ServiceBase):
118
122
  print(f"\\t{err.detail} \\n")
119
123
  """
120
124
 
125
+ if transfer_method == TransferMethod.SOURCE_URL and source_url is None:
126
+ raise ValueError("`source_url` argument is required when using `TransferMethod.SOURCE_URL`.")
127
+
128
+ if source_url is not None and transfer_method != TransferMethod.SOURCE_URL:
129
+ raise ValueError(
130
+ "`transfer_method` should be `TransferMethod.SOURCE_URL` when using the `source_url` argument."
131
+ )
132
+
133
+ files: Optional[List[Tuple]] = None
121
134
  if file or file_path:
122
135
  if file_path:
123
136
  file = open(file_path, "rb")
@@ -128,9 +141,9 @@ class FileScan(ServiceBase):
128
141
  size = params.size
129
142
  else:
130
143
  crc, sha, size = None, None, None
131
- files: List[Tuple] = [("upload", ("filename", file, "application/octet-stream"))]
132
- else:
133
- raise ValueError("Need to set file_path or file arguments")
144
+ files = [("upload", ("filename", file, "application/octet-stream"))]
145
+ elif source_url is None:
146
+ raise ValueError("Need to set one of `file_path`, `file`, or `source_url` arguments.")
134
147
 
135
148
  input = FileScanRequest(
136
149
  verbose=verbose,
@@ -142,8 +155,12 @@ class FileScan(ServiceBase):
142
155
  transfer_method=transfer_method,
143
156
  source_url=source_url,
144
157
  )
145
- data = input.dict(exclude_none=True)
146
- return self.request.post("v1/scan", FileScanResult, data=data, files=files, poll_result=sync_call)
158
+ data = input.model_dump(exclude_none=True)
159
+ try:
160
+ return self.request.post("v1/scan", FileScanResult, data=data, files=files, poll_result=sync_call)
161
+ finally:
162
+ if file_path and file:
163
+ file.close()
147
164
 
148
165
  def request_upload_url(
149
166
  self,
@@ -164,7 +181,7 @@ class FileScan(ServiceBase):
164
181
  input.sha256 = params.sha256_hex
165
182
  input.size = params.size
166
183
 
167
- data = input.dict(exclude_none=True)
184
+ data = input.model_dump(exclude_none=True)
168
185
  return self.request.request_presigned_url("v1/scan", FileScanResult, data=data)
169
186
 
170
187