pangea-sdk 3.8.0b1__py3-none-any.whl → 5.4.0b1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. pangea/__init__.py +1 -1
  2. pangea/asyncio/file_uploader.py +1 -1
  3. pangea/asyncio/request.py +56 -34
  4. pangea/asyncio/services/__init__.py +4 -0
  5. pangea/asyncio/services/ai_guard.py +75 -0
  6. pangea/asyncio/services/audit.py +192 -31
  7. pangea/asyncio/services/authn.py +187 -109
  8. pangea/asyncio/services/authz.py +285 -0
  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 +108 -34
  13. pangea/asyncio/services/prompt_guard.py +73 -0
  14. pangea/asyncio/services/redact.py +72 -4
  15. pangea/asyncio/services/sanitize.py +217 -0
  16. pangea/asyncio/services/share.py +246 -73
  17. pangea/asyncio/services/vault.py +1710 -750
  18. pangea/crypto/rsa.py +135 -0
  19. pangea/deep_verify.py +7 -1
  20. pangea/dump_audit.py +9 -8
  21. pangea/request.py +87 -59
  22. pangea/response.py +49 -31
  23. pangea/services/__init__.py +4 -0
  24. pangea/services/ai_guard.py +128 -0
  25. pangea/services/audit/audit.py +205 -42
  26. pangea/services/audit/models.py +56 -8
  27. pangea/services/audit/signing.py +6 -5
  28. pangea/services/audit/util.py +3 -3
  29. pangea/services/authn/authn.py +140 -70
  30. pangea/services/authn/models.py +167 -11
  31. pangea/services/authz.py +400 -0
  32. pangea/services/base.py +39 -8
  33. pangea/services/embargo.py +2 -2
  34. pangea/services/file_scan.py +32 -15
  35. pangea/services/intel.py +157 -32
  36. pangea/services/prompt_guard.py +83 -0
  37. pangea/services/redact.py +152 -4
  38. pangea/services/sanitize.py +371 -0
  39. pangea/services/share/share.py +683 -107
  40. pangea/services/vault/models/asymmetric.py +120 -18
  41. pangea/services/vault/models/common.py +439 -141
  42. pangea/services/vault/models/keys.py +94 -0
  43. pangea/services/vault/models/secret.py +27 -3
  44. pangea/services/vault/models/symmetric.py +68 -22
  45. pangea/services/vault/vault.py +1690 -749
  46. pangea/tools.py +6 -7
  47. pangea/utils.py +16 -27
  48. pangea/verify_audit.py +270 -83
  49. {pangea_sdk-3.8.0b1.dist-info → pangea_sdk-5.4.0b1.dist-info}/METADATA +43 -35
  50. pangea_sdk-5.4.0b1.dist-info/RECORD +60 -0
  51. {pangea_sdk-3.8.0b1.dist-info → pangea_sdk-5.4.0b1.dist-info}/WHEEL +1 -1
  52. pangea_sdk-3.8.0b1.dist-info/RECORD +0 -50
pangea/services/redact.py CHANGED
@@ -1,9 +1,11 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
3
4
 
4
5
  import enum
5
6
  from typing import Dict, List, Optional, Union
6
7
 
8
+ from pangea.config import PangeaConfig
7
9
  from pangea.response import APIRequestModel, APIResponseModel, PangeaResponse, PangeaResponseResult
8
10
  from pangea.services.base import ServiceBase
9
11
 
@@ -15,6 +17,44 @@ class RedactFormat(str, enum.Enum):
15
17
  """JSON format."""
16
18
 
17
19
 
20
+ class RedactType(str, enum.Enum):
21
+ MASK = "mask"
22
+ PARTIAL_MASKING = "partial_masking"
23
+ REPLACEMENT = "replacement"
24
+ DETECT_ONLY = "detect_only"
25
+ HASH = "hash"
26
+ FPE = "fpe"
27
+
28
+
29
+ class FPEAlphabet(str, enum.Enum):
30
+ NUMERIC = "numeric"
31
+ ALPHANUMERICLOWER = "alphanumericlower"
32
+ ALPHANUMERIC = "alphanumeric"
33
+
34
+
35
+ class MaskingType(str, enum.Enum):
36
+ MASK = "mask"
37
+ UNMASK = "unmask"
38
+
39
+
40
+ class PartialMasking(APIRequestModel):
41
+ masking_type: Optional[MaskingType] = None
42
+ unmasked_from_left: Optional[int] = None
43
+ unmasked_from_right: Optional[int] = None
44
+ masked_from_left: Optional[int] = None
45
+ masked_from_right: Optional[int] = None
46
+ chars_to_ignore: Optional[List[str]] = None
47
+ masking_char: Optional[List[str]] = None
48
+
49
+
50
+ class RedactionMethodOverrides(APIRequestModel):
51
+ redaction_type: RedactType
52
+ hash: Optional[Dict] = None
53
+ fpe_alphabet: Optional[FPEAlphabet] = None
54
+ partial_masking: Optional[PartialMasking] = None
55
+ redaction_value: Optional[str] = None
56
+
57
+
18
58
  class RedactRequest(APIRequestModel):
19
59
  """
20
60
  Input class to make a redact request
@@ -25,6 +65,18 @@ class RedactRequest(APIRequestModel):
25
65
  rules: Optional[List[str]] = None
26
66
  rulesets: Optional[List[str]] = None
27
67
  return_result: Optional[bool] = None
68
+ redaction_method_overrides: Optional[RedactionMethodOverrides] = None
69
+ vault_parameters: Optional[VaultParameters] = None
70
+ llm_request: Optional[bool] = None
71
+ """Is this redact call going to be used in an LLM request?"""
72
+
73
+
74
+ class VaultParameters(APIRequestModel):
75
+ fpe_key_id: Optional[str] = None
76
+ """A vault key ID of an exportable key used to redact with FPE instead of using the service config default."""
77
+
78
+ salt_secret_id: Optional[str] = None
79
+ """A vault secret ID of a secret used to salt a hash instead of using the service config default."""
28
80
 
29
81
 
30
82
  class RecognizerResult(APIResponseModel):
@@ -67,11 +119,13 @@ class RedactResult(PangeaResponseResult):
67
119
  redact_text: Redacted text result
68
120
  count: Number of redactions present in the text
69
121
  report: Describes the decision process for redactions
122
+ fpe_context: FPE context used to encrypt and redact data
70
123
  """
71
124
 
72
125
  redacted_text: Optional[str] = None
73
126
  count: int
74
127
  report: Optional[DebugReport] = None
128
+ fpe_context: Optional[str] = None
75
129
 
76
130
 
77
131
  class StructuredRequest(APIRequestModel):
@@ -92,6 +146,10 @@ class StructuredRequest(APIRequestModel):
92
146
  rules: Optional[List[str]] = None
93
147
  rulesets: Optional[List[str]] = None
94
148
  return_result: Optional[bool] = None
149
+ redaction_method_overrides: Optional[RedactionMethodOverrides] = None
150
+ vault_parameters: Optional[VaultParameters] = None
151
+ llm_request: Optional[bool] = None
152
+ """Is this redact call going to be used in an LLM request?"""
95
153
 
96
154
 
97
155
  class StructuredResult(PangeaResponseResult):
@@ -105,6 +163,32 @@ class StructuredResult(PangeaResponseResult):
105
163
  report: Optional[DebugReport] = None
106
164
 
107
165
 
166
+ class UnredactRequest(APIRequestModel):
167
+ """
168
+ Class input to unredact data request
169
+
170
+ Arguments:
171
+ redacted_data: Data to unredact
172
+ fpe_context (base64): FPE context used to decrypt and unredact data
173
+
174
+ """
175
+
176
+ redacted_data: RedactedData
177
+ fpe_context: str
178
+
179
+
180
+ RedactedData = Union[str, Dict]
181
+
182
+
183
+ class UnredactResult(PangeaResponseResult):
184
+ """
185
+ Result class after an unredact request
186
+
187
+ """
188
+
189
+ data: RedactedData
190
+
191
+
108
192
  class Redact(ServiceBase):
109
193
  """Redact service client.
110
194
 
@@ -132,7 +216,24 @@ class Redact(ServiceBase):
132
216
 
133
217
  service_name = "redact"
134
218
 
135
- def __init__(self, token, config=None, logger_name="pangea", config_id: Optional[str] = None):
219
+ def __init__(
220
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
221
+ ) -> None:
222
+ """
223
+ Redact client
224
+
225
+ Initializes a new Redact client.
226
+
227
+ Args:
228
+ token: Pangea API token.
229
+ config: Configuration.
230
+ logger_name: Logger name.
231
+ config_id: Configuration ID.
232
+
233
+ Examples:
234
+ config = PangeaConfig(domain="pangea_domain")
235
+ redact = Redact(token="pangea_token", config=config)
236
+ """
136
237
  super().__init__(token, config, logger_name, config_id=config_id)
137
238
 
138
239
  def redact(
@@ -142,6 +243,9 @@ class Redact(ServiceBase):
142
243
  rules: Optional[List[str]] = None,
143
244
  rulesets: Optional[List[str]] = None,
144
245
  return_result: Optional[bool] = None,
246
+ redaction_method_overrides: Optional[RedactionMethodOverrides] = None,
247
+ llm_request: Optional[bool] = None,
248
+ vault_parameters: Optional[VaultParameters] = None,
145
249
  ) -> PangeaResponse[RedactResult]:
146
250
  """
147
251
  Redact
@@ -157,6 +261,9 @@ class Redact(ServiceBase):
157
261
  rules (list[str], optional): An array of redact rule short names
158
262
  rulesets (list[str], optional): An array of redact rulesets short names
159
263
  return_result(bool, optional): Setting this value to false will omit the redacted result only returning count
264
+ redaction_method_overrides: A set of redaction method overrides for any enabled rule. These methods override the config declared methods
265
+ llm_request: Boolean flag to enable FPE redaction for LLM requests
266
+ vault_parameters: A set of vault parameters to use for redaction
160
267
 
161
268
  Raises:
162
269
  PangeaAPIException: If an API Error happens
@@ -170,8 +277,17 @@ class Redact(ServiceBase):
170
277
  response = redact.redact(text="Jenny Jenny... 555-867-5309")
171
278
  """
172
279
 
173
- input = RedactRequest(text=text, debug=debug, rules=rules, rulesets=rulesets, return_result=return_result)
174
- return self.request.post("v1/redact", RedactResult, data=input.dict(exclude_none=True))
280
+ input = RedactRequest(
281
+ text=text,
282
+ debug=debug,
283
+ rules=rules,
284
+ rulesets=rulesets,
285
+ return_result=return_result,
286
+ redaction_method_overrides=redaction_method_overrides,
287
+ llm_request=llm_request,
288
+ vault_parameters=vault_parameters,
289
+ )
290
+ return self.request.post("v1/redact", RedactResult, data=input.model_dump(exclude_none=True))
175
291
 
176
292
  def redact_structured(
177
293
  self,
@@ -182,6 +298,9 @@ class Redact(ServiceBase):
182
298
  rules: Optional[List[str]] = None,
183
299
  rulesets: Optional[List[str]] = None,
184
300
  return_result: Optional[bool] = None,
301
+ redaction_method_overrides: Optional[RedactionMethodOverrides] = None,
302
+ llm_request: Optional[bool] = None,
303
+ vault_parameters: Optional[VaultParameters] = None,
185
304
  ) -> PangeaResponse[StructuredResult]:
186
305
  """
187
306
  Redact structured
@@ -201,6 +320,9 @@ class Redact(ServiceBase):
201
320
  rules (list[str], optional): An array of redact rule short names
202
321
  rulesets (list[str], optional): An array of redact rulesets short names
203
322
  return_result(bool, optional): Setting this value to false will omit the redacted result only returning count
323
+ redaction_method_overrides: A set of redaction method overrides for any enabled rule. These methods override the config declared methods
324
+ llm_request: Boolean flag to enable FPE redaction for LLM requests
325
+ vault_parameters: A set of vault parameters to use for redaction
204
326
 
205
327
  Raises:
206
328
  PangeaAPIException: If an API Error happens
@@ -227,5 +349,31 @@ class Redact(ServiceBase):
227
349
  rules=rules,
228
350
  rulesets=rulesets,
229
351
  return_result=return_result,
352
+ redaction_method_overrides=redaction_method_overrides,
353
+ llm_request=llm_request,
354
+ vault_parameters=vault_parameters,
230
355
  )
231
- return self.request.post("v1/redact_structured", StructuredResult, data=input.dict(exclude_none=True))
356
+ return self.request.post("v1/redact_structured", StructuredResult, data=input.model_dump(exclude_none=True))
357
+
358
+ def unredact(self, redacted_data: RedactedData, fpe_context: str) -> PangeaResponse[UnredactResult]:
359
+ """
360
+ Unredact
361
+
362
+ Decrypt or unredact fpe redactions
363
+
364
+ OperationId: redact_post_v1_unredact
365
+
366
+ Args:
367
+ redacted_data: Data to unredact
368
+ fpe_context (base64): FPE context used to decrypt and unredact data
369
+
370
+ Raises:
371
+ PangeaAPIException: If an API Error happens
372
+
373
+ Returns:
374
+ Pangea Response with redacted data in the response.result field,
375
+ available response fields can be found in our
376
+ [API Documentation](https://pangea.cloud/docs/api/redact#unredact)
377
+ """
378
+ input = UnredactRequest(redacted_data=redacted_data, fpe_context=fpe_context)
379
+ return self.request.post("v1/unredact", UnredactResult, data=input.model_dump(exclude_none=True))
@@ -0,0 +1,371 @@
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
+
50
+ class SanitizeShareOutput(APIRequestModel):
51
+ enabled: Optional[bool] = None
52
+ """Store Sanitized files to Pangea Secure Share."""
53
+
54
+ output_folder: Optional[str] = None
55
+ """
56
+ Store Sanitized files to this Secure Share folder (will be auto-created if
57
+ it does not exist)
58
+ """
59
+
60
+
61
+ class SanitizeRequest(APIRequestModel):
62
+ transfer_method: TransferMethod = TransferMethod.POST_URL
63
+ """The transfer method used to upload the file data."""
64
+
65
+ source_url: Optional[str] = None
66
+ """A URL where the file to be sanitized can be downloaded."""
67
+
68
+ share_id: Optional[str] = None
69
+ """A Pangea Secure Share ID where the file to be Sanitized is stored."""
70
+
71
+ file: Optional[SanitizeFile] = None
72
+ """File."""
73
+
74
+ content: Optional[SanitizeContent] = None
75
+ """Content."""
76
+
77
+ share_output: Optional[SanitizeShareOutput] = None
78
+ """Share output."""
79
+
80
+ size: Optional[int] = None
81
+ """The size (in bytes) of the file. If the upload doesn't match, the call will fail."""
82
+
83
+ crc32c: Optional[str] = None
84
+ """The CRC32C hash of the file data, which will be verified by the server if provided."""
85
+
86
+ sha256: Optional[str] = None
87
+ """The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided."""
88
+
89
+ uploaded_file_name: Optional[str] = None
90
+ """Name of the user-uploaded file, required for transfer-method 'put-url' and 'post-url'."""
91
+
92
+
93
+ class DefangData(PangeaResponseResult):
94
+ external_urls_count: Optional[int] = None
95
+ """Number of external links found."""
96
+
97
+ external_domains_count: Optional[int] = None
98
+ """Number of external domains found."""
99
+
100
+ defanged_count: Optional[int] = None
101
+ """Number of items defanged per provided rules and detections."""
102
+
103
+ url_intel_summary: Optional[str] = None
104
+ """Processed N URLs: X are malicious, Y are suspicious, Z are unknown."""
105
+
106
+ domain_intel_summary: Optional[str] = None
107
+ """Processed N Domains: X are malicious, Y are suspicious, Z are unknown."""
108
+
109
+
110
+ class RedactRecognizerResult(PangeaResponseResult):
111
+ field_type: str
112
+ """The entity name."""
113
+
114
+ score: float
115
+ """The certainty score that the entity matches this specific snippet."""
116
+
117
+ text: str
118
+ """The text snippet that matched."""
119
+
120
+ start: int
121
+ """The starting index of a snippet."""
122
+
123
+ end: int
124
+ """The ending index of a snippet."""
125
+
126
+ redacted: bool
127
+ """Indicates if this rule was used to anonymize a text snippet."""
128
+
129
+
130
+ class RedactData(PangeaResponseResult):
131
+ redaction_count: int
132
+ """Number of items redacted"""
133
+
134
+ summary_counts: Dict[str, int] = Field(default_factory=dict)
135
+ """Summary counts."""
136
+
137
+ recognizer_results: Optional[List[RedactRecognizerResult]] = None
138
+ """The scoring result of a set of rules."""
139
+
140
+
141
+ class SanitizeData(PangeaResponseResult):
142
+ defang: Optional[DefangData] = None
143
+ """Defang."""
144
+
145
+ redact: Optional[RedactData] = None
146
+ """Redact."""
147
+
148
+ malicious_file: Optional[bool] = None
149
+ """If the file scanned was malicious."""
150
+
151
+
152
+ class SanitizeResult(PangeaResponseResult):
153
+ dest_url: Optional[str] = None
154
+ """A URL where the Sanitized file can be downloaded."""
155
+
156
+ dest_share_id: Optional[str] = None
157
+ """Pangea Secure Share ID of the Sanitized file."""
158
+
159
+ data: SanitizeData
160
+ """Sanitize data."""
161
+
162
+ parameters: Dict = {}
163
+ """The parameters, which were passed in the request, echoed back."""
164
+
165
+
166
+ class Sanitize(ServiceBase):
167
+ """Sanitize service client.
168
+
169
+ Examples:
170
+ import os
171
+
172
+ # Pangea SDK
173
+ from pangea.config import PangeaConfig
174
+ from pangea.services import Sanitize
175
+
176
+ PANGEA_SANITIZE_TOKEN = os.getenv("PANGEA_SANITIZE_TOKEN")
177
+ config = PangeaConfig(domain="pangea.cloud")
178
+
179
+ sanitize = Sanitize(token=PANGEA_SANITIZE_TOKEN, config=config)
180
+ """
181
+
182
+ service_name = "sanitize"
183
+
184
+ def __init__(
185
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
186
+ ) -> None:
187
+ """
188
+ Sanitize client
189
+
190
+ Initializes a new Sanitize client.
191
+
192
+ Args:
193
+ token: Pangea API token.
194
+ config: Configuration.
195
+ logger_name: Logger name.
196
+ config_id: Configuration ID.
197
+
198
+ Examples:
199
+ config = PangeaConfig(domain="aws.us.pangea.cloud")
200
+ authz = Sanitize(token="pangea_token", config=config)
201
+ """
202
+
203
+ super().__init__(token, config, logger_name, config_id=config_id)
204
+
205
+ def sanitize(
206
+ self,
207
+ transfer_method: TransferMethod = TransferMethod.POST_URL,
208
+ file_path: Optional[str] = None,
209
+ file: Optional[io.BufferedReader] = None,
210
+ source_url: Optional[str] = None,
211
+ share_id: Optional[str] = None,
212
+ file_scan: Optional[SanitizeFile] = None,
213
+ content: Optional[SanitizeContent] = None,
214
+ share_output: Optional[SanitizeShareOutput] = None,
215
+ size: Optional[int] = None,
216
+ crc32c: Optional[str] = None,
217
+ sha256: Optional[str] = None,
218
+ uploaded_file_name: Optional[str] = None,
219
+ sync_call: bool = True,
220
+ ) -> PangeaResponse[SanitizeResult]:
221
+ """
222
+ Sanitize
223
+
224
+ Apply file sanitization actions according to specified rules.
225
+
226
+ OperationId: sanitize_post_v1_sanitize
227
+
228
+ Args:
229
+ transfer_method: The transfer method used to upload the file data.
230
+ file_path: Path to file to sanitize.
231
+ file: File to sanitize.
232
+ source_url: A URL where the file to be sanitized can be downloaded.
233
+ share_id: A Pangea Secure Share ID where the file to be sanitized is stored.
234
+ file_scan: Options for File Scan.
235
+ content: Options for how the file should be sanitized.
236
+ share_output: Integration with Secure Share.
237
+ size: The size (in bytes) of the file. If the upload doesn't match, the call will fail.
238
+ crc32c: The CRC32C hash of the file data, which will be verified by the server if provided.
239
+ sha256: The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided.
240
+ uploaded_file_name: Name of the user-uploaded file, required for `TransferMethod.PUT_URL` and `TransferMethod.POST_URL`.
241
+ sync_call: Whether or not to poll on HTTP/202.
242
+
243
+ Raises:
244
+ PangeaAPIException: If an API error happens.
245
+
246
+ Returns:
247
+ The sanitized file and information on the sanitization that was
248
+ performed.
249
+
250
+ Examples:
251
+ with open("/path/to/file.txt", "rb") as f:
252
+ response = sanitize.sanitize(
253
+ file=f,
254
+ transfer_method=TransferMethod.POST_URL,
255
+ uploaded_file_name="uploaded_file",
256
+ )
257
+ """
258
+
259
+ if transfer_method == TransferMethod.SOURCE_URL and source_url is None:
260
+ raise ValueError("`source_url` argument is required when using `TransferMethod.SOURCE_URL`.")
261
+
262
+ if source_url is not None and transfer_method != TransferMethod.SOURCE_URL:
263
+ raise ValueError(
264
+ "`transfer_method` should be `TransferMethod.SOURCE_URL` when using the `source_url` argument."
265
+ )
266
+
267
+ files: Optional[List[Tuple]] = None
268
+ if file or file_path:
269
+ if file_path:
270
+ file = open(file_path, "rb")
271
+ if (
272
+ transfer_method == TransferMethod.POST_URL
273
+ and file
274
+ and (sha256 is None or crc32c is None or size is None)
275
+ ):
276
+ params = get_file_upload_params(file)
277
+ crc32c = params.crc_hex if crc32c is None else crc32c
278
+ sha256 = params.sha256_hex if sha256 is None else sha256
279
+ size = params.size if size is None else size
280
+ else:
281
+ crc32c, sha256, size = None, None, None
282
+ files = [("upload", ("filename", file, "application/octet-stream"))]
283
+ elif source_url is None:
284
+ raise ValueError("Need to set one of `file_path`, `file`, or `source_url` arguments.")
285
+
286
+ input = SanitizeRequest(
287
+ transfer_method=transfer_method,
288
+ source_url=source_url,
289
+ share_id=share_id,
290
+ file=file_scan,
291
+ content=content,
292
+ share_output=share_output,
293
+ crc32c=crc32c,
294
+ sha256=sha256,
295
+ size=size,
296
+ uploaded_file_name=uploaded_file_name,
297
+ )
298
+ data = input.model_dump(exclude_none=True)
299
+ try:
300
+ response = self.request.post("v1/sanitize", SanitizeResult, data=data, files=files, poll_result=sync_call)
301
+ finally:
302
+ if file_path and file is not None:
303
+ file.close()
304
+ return response
305
+
306
+ def request_upload_url(
307
+ self,
308
+ transfer_method: TransferMethod = TransferMethod.PUT_URL,
309
+ params: Optional[FileUploadParams] = None,
310
+ file_scan: Optional[SanitizeFile] = None,
311
+ content: Optional[SanitizeContent] = None,
312
+ share_output: Optional[SanitizeShareOutput] = None,
313
+ size: Optional[int] = None,
314
+ crc32c: Optional[str] = None,
315
+ sha256: Optional[str] = None,
316
+ uploaded_file_name: Optional[str] = None,
317
+ ) -> PangeaResponse[SanitizeResult]:
318
+ """
319
+ Sanitize via presigned URL
320
+
321
+ Apply file sanitization actions according to specified rules via a
322
+ [presigned URL](https://pangea.cloud/docs/api/transfer-methods).
323
+
324
+ OperationId: sanitize_post_v1_sanitize 2
325
+
326
+ Args:
327
+ transfer_method: The transfer method used to upload the file data.
328
+ params: File upload parameters.
329
+ file_scan: Options for File Scan.
330
+ content: Options for how the file should be sanitized.
331
+ share_output: Integration with Secure Share.
332
+ size: The size (in bytes) of the file. If the upload doesn't match, the call will fail.
333
+ crc32c: The CRC32C hash of the file data, which will be verified by the server if provided.
334
+ sha256: The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided.
335
+ uploaded_file_name: Name of the user-uploaded file, required for `TransferMethod.PUT_URL` and `TransferMethod.POST_URL`.
336
+
337
+ Raises:
338
+ PangeaAPIException: If an API error happens.
339
+
340
+ Returns:
341
+ A presigned URL.
342
+
343
+ Examples:
344
+ presignedUrl = sanitize.request_upload_url(
345
+ transfer_method=TransferMethod.PUT_URL,
346
+ uploaded_file_name="uploaded_file",
347
+ )
348
+
349
+ # Upload file to `presignedUrl.accepted_result.put_url`.
350
+
351
+ # Poll for Sanitize's result.
352
+ response: PangeaResponse[SanitizeResult] = sanitize.poll_result(response=presignedUrl)
353
+ """
354
+
355
+ input = SanitizeRequest(
356
+ transfer_method=transfer_method,
357
+ file=file_scan,
358
+ content=content,
359
+ share_output=share_output,
360
+ crc32c=crc32c,
361
+ sha256=sha256,
362
+ size=size,
363
+ uploaded_file_name=uploaded_file_name,
364
+ )
365
+ if params is not None and (transfer_method == TransferMethod.POST_URL):
366
+ input.crc32c = params.crc_hex
367
+ input.sha256 = params.sha256_hex
368
+ input.size = params.size
369
+
370
+ data = input.model_dump(exclude_none=True)
371
+ return self.request.request_presigned_url("v1/sanitize", SanitizeResult, data=data)