pangea-sdk 3.8.0__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 (51) hide show
  1. pangea/__init__.py +2 -1
  2. pangea/asyncio/__init__.py +1 -0
  3. pangea/asyncio/file_uploader.py +39 -0
  4. pangea/asyncio/request.py +46 -23
  5. pangea/asyncio/services/__init__.py +2 -0
  6. pangea/asyncio/services/audit.py +46 -20
  7. pangea/asyncio/services/authn.py +123 -61
  8. pangea/asyncio/services/authz.py +57 -31
  9. pangea/asyncio/services/base.py +21 -2
  10. pangea/asyncio/services/embargo.py +2 -2
  11. pangea/asyncio/services/file_scan.py +24 -9
  12. pangea/asyncio/services/intel.py +104 -30
  13. pangea/asyncio/services/redact.py +52 -3
  14. pangea/asyncio/services/sanitize.py +217 -0
  15. pangea/asyncio/services/share.py +733 -0
  16. pangea/asyncio/services/vault.py +1709 -766
  17. pangea/crypto/rsa.py +135 -0
  18. pangea/deep_verify.py +7 -1
  19. pangea/dump_audit.py +9 -8
  20. pangea/file_uploader.py +35 -0
  21. pangea/request.py +70 -49
  22. pangea/response.py +36 -17
  23. pangea/services/__init__.py +2 -0
  24. pangea/services/audit/audit.py +57 -29
  25. pangea/services/audit/models.py +12 -3
  26. pangea/services/audit/signing.py +6 -5
  27. pangea/services/audit/util.py +3 -3
  28. pangea/services/authn/authn.py +120 -66
  29. pangea/services/authn/models.py +167 -11
  30. pangea/services/authz.py +53 -30
  31. pangea/services/base.py +16 -2
  32. pangea/services/embargo.py +2 -2
  33. pangea/services/file_scan.py +32 -15
  34. pangea/services/intel.py +155 -30
  35. pangea/services/redact.py +132 -3
  36. pangea/services/sanitize.py +388 -0
  37. pangea/services/share/file_format.py +170 -0
  38. pangea/services/share/share.py +1440 -0
  39. pangea/services/vault/models/asymmetric.py +120 -18
  40. pangea/services/vault/models/common.py +439 -141
  41. pangea/services/vault/models/keys.py +94 -0
  42. pangea/services/vault/models/secret.py +27 -3
  43. pangea/services/vault/models/symmetric.py +68 -22
  44. pangea/services/vault/vault.py +1690 -766
  45. pangea/tools.py +6 -7
  46. pangea/utils.py +94 -33
  47. pangea/verify_audit.py +270 -83
  48. {pangea_sdk-3.8.0.dist-info → pangea_sdk-5.3.0.dist-info}/METADATA +21 -29
  49. pangea_sdk-5.3.0.dist-info/RECORD +56 -0
  50. {pangea_sdk-3.8.0.dist-info → pangea_sdk-5.3.0.dist-info}/WHEEL +1 -1
  51. pangea_sdk-3.8.0.dist-info/RECORD +0 -46
@@ -0,0 +1,388 @@
1
+ # Copyright 2022 Pangea Cyber Corporation
2
+ # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
4
+
5
+ import io
6
+ from typing import Dict, List, Optional, Tuple
7
+
8
+ from pydantic import Field
9
+
10
+ from pangea.config import PangeaConfig
11
+ from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult, TransferMethod
12
+ from pangea.services.base import ServiceBase
13
+ from pangea.utils import FileUploadParams, get_file_upload_params
14
+
15
+
16
+ class SanitizeFile(APIRequestModel):
17
+ scan_provider: Optional[str] = None
18
+ """Provider to use for File Scan."""
19
+
20
+
21
+ class SanitizeContent(APIRequestModel):
22
+ url_intel: Optional[bool] = None
23
+ """Perform URL Intel lookup."""
24
+
25
+ url_intel_provider: Optional[str] = None
26
+ """Provider to use for URL Intel."""
27
+
28
+ domain_intel: Optional[bool] = None
29
+ """Perform Domain Intel lookup."""
30
+
31
+ domain_intel_provider: Optional[str] = None
32
+ """Provider to use for Domain Intel lookup."""
33
+
34
+ defang: Optional[bool] = None
35
+ """Defang external links."""
36
+
37
+ defang_threshold: Optional[int] = None
38
+ """Defang risk threshold."""
39
+
40
+ redact: Optional[bool] = None
41
+ """Redact sensitive content."""
42
+
43
+ redact_detect_only: Optional[bool] = None
44
+ """
45
+ If redact is enabled, avoids redacting the file and instead returns the PII
46
+ analysis engine results. Only works if redact is enabled.
47
+ """
48
+
49
+ remove_attachments: Optional[bool] = None
50
+ """Remove file attachments (PDF only)."""
51
+
52
+ remove_interactive: Optional[bool] = None
53
+ """Remove interactive content (PDF only)."""
54
+
55
+
56
+ class SanitizeShareOutput(APIRequestModel):
57
+ enabled: Optional[bool] = None
58
+ """Store Sanitized files to Pangea Secure Share."""
59
+
60
+ output_folder: Optional[str] = None
61
+ """
62
+ Store Sanitized files to this Secure Share folder (will be auto-created if
63
+ it does not exist)
64
+ """
65
+
66
+
67
+ class SanitizeRequest(APIRequestModel):
68
+ transfer_method: TransferMethod = TransferMethod.POST_URL
69
+ """The transfer method used to upload the file data."""
70
+
71
+ source_url: Optional[str] = None
72
+ """A URL where the file to be sanitized can be downloaded."""
73
+
74
+ share_id: Optional[str] = None
75
+ """A Pangea Secure Share ID where the file to be Sanitized is stored."""
76
+
77
+ file: Optional[SanitizeFile] = None
78
+ """File."""
79
+
80
+ content: Optional[SanitizeContent] = None
81
+ """Content."""
82
+
83
+ share_output: Optional[SanitizeShareOutput] = None
84
+ """Share output."""
85
+
86
+ size: Optional[int] = None
87
+ """The size (in bytes) of the file. If the upload doesn't match, the call will fail."""
88
+
89
+ crc32c: Optional[str] = None
90
+ """The CRC32C hash of the file data, which will be verified by the server if provided."""
91
+
92
+ sha256: Optional[str] = None
93
+ """The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided."""
94
+
95
+ uploaded_file_name: Optional[str] = None
96
+ """Name of the user-uploaded file, required for transfer-method 'put-url' and 'post-url'."""
97
+
98
+
99
+ class DefangData(PangeaResponseResult):
100
+ external_urls_count: Optional[int] = None
101
+ """Number of external links found."""
102
+
103
+ external_domains_count: Optional[int] = None
104
+ """Number of external domains found."""
105
+
106
+ defanged_count: Optional[int] = None
107
+ """Number of items defanged per provided rules and detections."""
108
+
109
+ url_intel_summary: Optional[str] = None
110
+ """Processed N URLs: X are malicious, Y are suspicious, Z are unknown."""
111
+
112
+ domain_intel_summary: Optional[str] = None
113
+ """Processed N Domains: X are malicious, Y are suspicious, Z are unknown."""
114
+
115
+
116
+ class RedactRecognizerResult(PangeaResponseResult):
117
+ field_type: str
118
+ """The entity name."""
119
+
120
+ score: float
121
+ """The certainty score that the entity matches this specific snippet."""
122
+
123
+ text: str
124
+ """The text snippet that matched."""
125
+
126
+ start: int
127
+ """The starting index of a snippet."""
128
+
129
+ end: int
130
+ """The ending index of a snippet."""
131
+
132
+ redacted: bool
133
+ """Indicates if this rule was used to anonymize a text snippet."""
134
+
135
+
136
+ class RedactData(PangeaResponseResult):
137
+ redaction_count: int
138
+ """Number of items redacted"""
139
+
140
+ summary_counts: Dict[str, int] = Field(default_factory=dict)
141
+ """Summary counts."""
142
+
143
+ recognizer_results: Optional[List[RedactRecognizerResult]] = None
144
+ """The scoring result of a set of rules."""
145
+
146
+
147
+ class CDR(PangeaResponseResult):
148
+ file_attachments_removed: Optional[int] = None
149
+ """Number of file attachments removed."""
150
+
151
+ interactive_contents_removed: Optional[int] = None
152
+ """Number of interactive content items removed."""
153
+
154
+
155
+ class SanitizeData(PangeaResponseResult):
156
+ defang: Optional[DefangData] = None
157
+ """Defang."""
158
+
159
+ redact: Optional[RedactData] = None
160
+ """Redact."""
161
+
162
+ malicious_file: Optional[bool] = None
163
+ """If the file scanned was malicious."""
164
+
165
+ cdr: Optional[CDR] = None
166
+ """Content Disarm and Reconstruction."""
167
+
168
+
169
+ class SanitizeResult(PangeaResponseResult):
170
+ dest_url: Optional[str] = None
171
+ """A URL where the Sanitized file can be downloaded."""
172
+
173
+ dest_share_id: Optional[str] = None
174
+ """Pangea Secure Share ID of the Sanitized file."""
175
+
176
+ data: SanitizeData
177
+ """Sanitize data."""
178
+
179
+ parameters: Dict = {}
180
+ """The parameters, which were passed in the request, echoed back."""
181
+
182
+
183
+ class Sanitize(ServiceBase):
184
+ """Sanitize service client.
185
+
186
+ Examples:
187
+ import os
188
+
189
+ # Pangea SDK
190
+ from pangea.config import PangeaConfig
191
+ from pangea.services import Sanitize
192
+
193
+ PANGEA_SANITIZE_TOKEN = os.getenv("PANGEA_SANITIZE_TOKEN")
194
+ config = PangeaConfig(domain="pangea.cloud")
195
+
196
+ sanitize = Sanitize(token=PANGEA_SANITIZE_TOKEN, config=config)
197
+ """
198
+
199
+ service_name = "sanitize"
200
+
201
+ def __init__(
202
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
203
+ ) -> None:
204
+ """
205
+ Sanitize client
206
+
207
+ Initializes a new Sanitize client.
208
+
209
+ Args:
210
+ token: Pangea API token.
211
+ config: Configuration.
212
+ logger_name: Logger name.
213
+ config_id: Configuration ID.
214
+
215
+ Examples:
216
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
217
+ authz = Sanitize(token="pangea_token", config=config)
218
+ """
219
+
220
+ super().__init__(token, config, logger_name, config_id=config_id)
221
+
222
+ def sanitize(
223
+ self,
224
+ transfer_method: TransferMethod = TransferMethod.POST_URL,
225
+ file_path: Optional[str] = None,
226
+ file: Optional[io.BufferedReader] = None,
227
+ source_url: Optional[str] = None,
228
+ share_id: Optional[str] = None,
229
+ file_scan: Optional[SanitizeFile] = None,
230
+ content: Optional[SanitizeContent] = None,
231
+ share_output: Optional[SanitizeShareOutput] = None,
232
+ size: Optional[int] = None,
233
+ crc32c: Optional[str] = None,
234
+ sha256: Optional[str] = None,
235
+ uploaded_file_name: Optional[str] = None,
236
+ sync_call: bool = True,
237
+ ) -> PangeaResponse[SanitizeResult]:
238
+ """
239
+ Sanitize
240
+
241
+ Apply file sanitization actions according to specified rules.
242
+
243
+ OperationId: sanitize_post_v1_sanitize
244
+
245
+ Args:
246
+ transfer_method: The transfer method used to upload the file data.
247
+ file_path: Path to file to sanitize.
248
+ file: File to sanitize.
249
+ source_url: A URL where the file to be sanitized can be downloaded.
250
+ share_id: A Pangea Secure Share ID where the file to be sanitized is stored.
251
+ file_scan: Options for File Scan.
252
+ content: Options for how the file should be sanitized.
253
+ share_output: Integration with Secure Share.
254
+ size: The size (in bytes) of the file. If the upload doesn't match, the call will fail.
255
+ crc32c: The CRC32C hash of the file data, which will be verified by the server if provided.
256
+ sha256: The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided.
257
+ uploaded_file_name: Name of the user-uploaded file, required for `TransferMethod.PUT_URL` and `TransferMethod.POST_URL`.
258
+ sync_call: Whether or not to poll on HTTP/202.
259
+
260
+ Raises:
261
+ PangeaAPIException: If an API error happens.
262
+
263
+ Returns:
264
+ The sanitized file and information on the sanitization that was
265
+ performed.
266
+
267
+ Examples:
268
+ with open("/path/to/file.pdf", "rb") as f:
269
+ response = sanitize.sanitize(
270
+ file=f,
271
+ transfer_method=TransferMethod.POST_URL,
272
+ uploaded_file_name="uploaded_file",
273
+ )
274
+ """
275
+
276
+ if transfer_method == TransferMethod.SOURCE_URL and source_url is None:
277
+ raise ValueError("`source_url` argument is required when using `TransferMethod.SOURCE_URL`.")
278
+
279
+ if source_url is not None and transfer_method != TransferMethod.SOURCE_URL:
280
+ raise ValueError(
281
+ "`transfer_method` should be `TransferMethod.SOURCE_URL` when using the `source_url` argument."
282
+ )
283
+
284
+ files: Optional[List[Tuple]] = None
285
+ if file or file_path:
286
+ if file_path:
287
+ file = open(file_path, "rb")
288
+ if (
289
+ transfer_method == TransferMethod.POST_URL
290
+ and file
291
+ and (sha256 is None or crc32c is None or size is None)
292
+ ):
293
+ params = get_file_upload_params(file)
294
+ crc32c = params.crc_hex if crc32c is None else crc32c
295
+ sha256 = params.sha256_hex if sha256 is None else sha256
296
+ size = params.size if size is None else size
297
+ else:
298
+ crc32c, sha256, size = None, None, None
299
+ files = [("upload", ("filename", file, "application/octet-stream"))]
300
+ elif source_url is None:
301
+ raise ValueError("Need to set one of `file_path`, `file`, or `source_url` arguments.")
302
+
303
+ input = SanitizeRequest(
304
+ transfer_method=transfer_method,
305
+ source_url=source_url,
306
+ share_id=share_id,
307
+ file=file_scan,
308
+ content=content,
309
+ share_output=share_output,
310
+ crc32c=crc32c,
311
+ sha256=sha256,
312
+ size=size,
313
+ uploaded_file_name=uploaded_file_name,
314
+ )
315
+ data = input.model_dump(exclude_none=True)
316
+ try:
317
+ response = self.request.post("v1/sanitize", SanitizeResult, data=data, files=files, poll_result=sync_call)
318
+ finally:
319
+ if file_path and file is not None:
320
+ file.close()
321
+ return response
322
+
323
+ def request_upload_url(
324
+ self,
325
+ transfer_method: TransferMethod = TransferMethod.PUT_URL,
326
+ params: Optional[FileUploadParams] = None,
327
+ file_scan: Optional[SanitizeFile] = None,
328
+ content: Optional[SanitizeContent] = None,
329
+ share_output: Optional[SanitizeShareOutput] = None,
330
+ size: Optional[int] = None,
331
+ crc32c: Optional[str] = None,
332
+ sha256: Optional[str] = None,
333
+ uploaded_file_name: Optional[str] = None,
334
+ ) -> PangeaResponse[SanitizeResult]:
335
+ """
336
+ Sanitize via presigned URL
337
+
338
+ Apply file sanitization actions according to specified rules via a
339
+ [presigned URL](https://pangea.cloud/docs/api/transfer-methods).
340
+
341
+ OperationId: sanitize_post_v1_sanitize 2
342
+
343
+ Args:
344
+ transfer_method: The transfer method used to upload the file data.
345
+ params: File upload parameters.
346
+ file_scan: Options for File Scan.
347
+ content: Options for how the file should be sanitized.
348
+ share_output: Integration with Secure Share.
349
+ size: The size (in bytes) of the file. If the upload doesn't match, the call will fail.
350
+ crc32c: The CRC32C hash of the file data, which will be verified by the server if provided.
351
+ sha256: The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided.
352
+ uploaded_file_name: Name of the user-uploaded file, required for `TransferMethod.PUT_URL` and `TransferMethod.POST_URL`.
353
+
354
+ Raises:
355
+ PangeaAPIException: If an API error happens.
356
+
357
+ Returns:
358
+ A presigned URL.
359
+
360
+ Examples:
361
+ presignedUrl = sanitize.request_upload_url(
362
+ transfer_method=TransferMethod.PUT_URL,
363
+ uploaded_file_name="uploaded_file",
364
+ )
365
+
366
+ # Upload file to `presignedUrl.accepted_result.put_url`.
367
+
368
+ # Poll for Sanitize's result.
369
+ response: PangeaResponse[SanitizeResult] = sanitize.poll_result(response=presignedUrl)
370
+ """
371
+
372
+ input = SanitizeRequest(
373
+ transfer_method=transfer_method,
374
+ file=file_scan,
375
+ content=content,
376
+ share_output=share_output,
377
+ crc32c=crc32c,
378
+ sha256=sha256,
379
+ size=size,
380
+ uploaded_file_name=uploaded_file_name,
381
+ )
382
+ if params is not None and (transfer_method == TransferMethod.POST_URL):
383
+ input.crc32c = params.crc_hex
384
+ input.sha256 = params.sha256_hex
385
+ input.size = params.size
386
+
387
+ data = input.model_dump(exclude_none=True)
388
+ return self.request.request_presigned_url("v1/sanitize", SanitizeResult, data=data)
@@ -0,0 +1,170 @@
1
+ import enum
2
+
3
+
4
+ class FileFormat(str, enum.Enum):
5
+ F3G2 = "3G2"
6
+ F3GP = "3GP"
7
+ F3MF = "3MF"
8
+ F7Z = "7Z"
9
+ A = "A"
10
+ AAC = "AAC"
11
+ ACCDB = "ACCDB"
12
+ AIFF = "AIFF"
13
+ AMF = "AMF"
14
+ AMR = "AMR"
15
+ APE = "APE"
16
+ ASF = "ASF"
17
+ ATOM = "ATOM"
18
+ AU = "AU"
19
+ AVI = "AVI"
20
+ AVIF = "AVIF"
21
+ BIN = "BIN"
22
+ BMP = "BMP"
23
+ BPG = "BPG"
24
+ BZ2 = "BZ2"
25
+ CAB = "CAB"
26
+ CLASS = "CLASS"
27
+ CPIO = "CPIO"
28
+ CRX = "CRX"
29
+ CSV = "CSV"
30
+ DAE = "DAE"
31
+ DBF = "DBF"
32
+ DCM = "DCM"
33
+ DEB = "DEB"
34
+ DJVU = "DJVU"
35
+ DLL = "DLL"
36
+ DOC = "DOC"
37
+ DOCX = "DOCX"
38
+ DWG = "DWG"
39
+ EOT = "EOT"
40
+ EPUB = "EPUB"
41
+ EXE = "EXE"
42
+ FDF = "FDF"
43
+ FITS = "FITS"
44
+ FLAC = "FLAC"
45
+ FLV = "FLV"
46
+ GBR = "GBR"
47
+ GEOJSON = "GEOJSON"
48
+ GIF = "GIF"
49
+ GLB = "GLB"
50
+ GML = "GML"
51
+ GPX = "GPX"
52
+ GZ = "GZ"
53
+ HAR = "HAR"
54
+ HDR = "HDR"
55
+ HEIC = "HEIC"
56
+ HEIF = "HEIF"
57
+ HTML = "HTML"
58
+ ICNS = "ICNS"
59
+ ICO = "ICO"
60
+ ICS = "ICS"
61
+ ISO = "ISO"
62
+ JAR = "JAR"
63
+ JP2 = "JP2"
64
+ JPF = "JPF"
65
+ JPG = "JPG"
66
+ JPM = "JPM"
67
+ JS = "JS"
68
+ JSON = "JSON"
69
+ JXL = "JXL"
70
+ JXR = "JXR"
71
+ KML = "KML"
72
+ LIT = "LIT"
73
+ LNK = "LNK"
74
+ LUA = "LUA"
75
+ LZ = "LZ"
76
+ M3U = "M3U"
77
+ M4A = "M4A"
78
+ MACHO = "MACHO"
79
+ MDB = "MDB"
80
+ MIDI = "MIDI"
81
+ MKV = "MKV"
82
+ MOBI = "MOBI"
83
+ MOV = "MOV"
84
+ MP3 = "MP3"
85
+ MP4 = "MP4"
86
+ MPC = "MPC"
87
+ MPEG = "MPEG"
88
+ MQV = "MQV"
89
+ MRC = "MRC"
90
+ MSG = "MSG"
91
+ MSI = "MSI"
92
+ NDJSON = "NDJSON"
93
+ NES = "NES"
94
+ ODC = "ODC"
95
+ ODF = "ODF"
96
+ ODG = "ODG"
97
+ ODP = "ODP"
98
+ ODS = "ODS"
99
+ ODT = "ODT"
100
+ OGA = "OGA"
101
+ OGV = "OGV"
102
+ OTF = "OTF"
103
+ OTG = "OTG"
104
+ OTP = "OTP"
105
+ OTS = "OTS"
106
+ OTT = "OTT"
107
+ OWL = "OWL"
108
+ P7S = "P7S"
109
+ PAT = "PAT"
110
+ PDF = "PDF"
111
+ PHP = "PHP"
112
+ PL = "PL"
113
+ PNG = "PNG"
114
+ PPT = "PPT"
115
+ PPTX = "PPTX"
116
+ PS = "PS"
117
+ PSD = "PSD"
118
+ PUB = "PUB"
119
+ PY = "PY"
120
+ QCP = "QCP"
121
+ RAR = "RAR"
122
+ RMVB = "RMVB"
123
+ RPM = "RPM"
124
+ RSS = "RSS"
125
+ RTF = "RTF"
126
+ SHP = "SHP"
127
+ SHX = "SHX"
128
+ SO = "SO"
129
+ SQLITE = "SQLITE"
130
+ SRT = "SRT"
131
+ SVG = "SVG"
132
+ SWF = "SWF"
133
+ SXC = "SXC"
134
+ TAR = "TAR"
135
+ TCL = "TCL"
136
+ TCX = "TCX"
137
+ TIFF = "TIFF"
138
+ TORRENT = "TORRENT"
139
+ TSV = "TSV"
140
+ TTC = "TTC"
141
+ TTF = "TTF"
142
+ TXT = "TXT"
143
+ VCF = "VCF"
144
+ VOC = "VOC"
145
+ VTT = "VTT"
146
+ WARC = "WARC"
147
+ WASM = "WASM"
148
+ WAV = "WAV"
149
+ WEBM = "WEBM"
150
+ WEBP = "WEBP"
151
+ WOFF = "WOFF"
152
+ WOFF2 = "WOFF2"
153
+ X3D = "X3D"
154
+ XAR = "XAR"
155
+ XCF = "XCF"
156
+ XFDF = "XFDF"
157
+ XLF = "XLF"
158
+ XLS = "XLS"
159
+ XLSX = "XLSX"
160
+ XML = "XML"
161
+ XPM = "XPM"
162
+ XZ = "XZ"
163
+ ZIP = "ZIP"
164
+ ZST = "ZST"
165
+
166
+ def __str__(self):
167
+ return str(self.value)
168
+
169
+ def __repr__(self):
170
+ return str(self.value)