pangea-sdk 3.8.0b1__py3-none-any.whl → 5.4.0b1__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 (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)