pangea-sdk 3.8.0b4__py3-none-any.whl → 4.0.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 (43) hide show
  1. pangea/__init__.py +1 -2
  2. pangea/asyncio/request.py +17 -22
  3. pangea/asyncio/services/__init__.py +0 -2
  4. pangea/asyncio/services/audit.py +188 -23
  5. pangea/asyncio/services/authn.py +167 -108
  6. pangea/asyncio/services/authz.py +36 -45
  7. pangea/asyncio/services/embargo.py +2 -2
  8. pangea/asyncio/services/file_scan.py +3 -3
  9. pangea/asyncio/services/intel.py +44 -26
  10. pangea/asyncio/services/redact.py +60 -4
  11. pangea/asyncio/services/vault.py +145 -30
  12. pangea/dump_audit.py +1 -1
  13. pangea/request.py +30 -24
  14. pangea/response.py +34 -42
  15. pangea/services/__init__.py +0 -2
  16. pangea/services/audit/audit.py +202 -34
  17. pangea/services/audit/models.py +56 -8
  18. pangea/services/audit/util.py +3 -3
  19. pangea/services/authn/authn.py +116 -65
  20. pangea/services/authn/models.py +88 -4
  21. pangea/services/authz.py +51 -56
  22. pangea/services/base.py +23 -6
  23. pangea/services/embargo.py +2 -2
  24. pangea/services/file_scan.py +3 -2
  25. pangea/services/intel.py +25 -23
  26. pangea/services/redact.py +124 -4
  27. pangea/services/vault/models/common.py +121 -6
  28. pangea/services/vault/models/symmetric.py +2 -2
  29. pangea/services/vault/vault.py +143 -32
  30. pangea/utils.py +20 -109
  31. pangea/verify_audit.py +267 -83
  32. {pangea_sdk-3.8.0b4.dist-info → pangea_sdk-4.0.0.dist-info}/METADATA +12 -20
  33. pangea_sdk-4.0.0.dist-info/RECORD +46 -0
  34. {pangea_sdk-3.8.0b4.dist-info → pangea_sdk-4.0.0.dist-info}/WHEEL +1 -1
  35. pangea/asyncio/__init__.py +0 -1
  36. pangea/asyncio/file_uploader.py +0 -39
  37. pangea/asyncio/services/sanitize.py +0 -185
  38. pangea/asyncio/services/share.py +0 -573
  39. pangea/file_uploader.py +0 -35
  40. pangea/services/sanitize.py +0 -275
  41. pangea/services/share/file_format.py +0 -170
  42. pangea/services/share/share.py +0 -877
  43. pangea_sdk-3.8.0b4.dist-info/RECORD +0 -54
@@ -28,12 +28,11 @@ from pangea.services.authz import (
28
28
 
29
29
 
30
30
  class AuthZAsync(ServiceBaseAsync):
31
- """AuthZ service client. (Beta)
31
+ """AuthZ service client.
32
32
 
33
33
  Provides methods to interact with the Pangea AuthZ Service.
34
34
  Documentation for the AuthZ Service API can be found at
35
- <https://pangea.cloud/docs/api/authz>. Note that this service is in Beta and
36
- is subject to change.
35
+ <https://pangea.cloud/docs/api/authz>.
37
36
 
38
37
  Examples:
39
38
  import os
@@ -54,11 +53,10 @@ class AuthZAsync(ServiceBaseAsync):
54
53
  super().__init__(token, config, logger_name, config_id=config_id)
55
54
 
56
55
  async def tuple_create(self, tuples: List[Tuple]) -> PangeaResponse[TupleCreateResult]:
57
- """Create tuples. (Beta)
56
+ """Create tuples.
58
57
 
59
58
  Create tuples in the AuthZ Service. The request will fail if there is no schema
60
59
  or the tuples do not validate against the schema.
61
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
62
60
 
63
61
  Args:
64
62
  tuples (List[Tuple]): List of tuples to be created.
@@ -69,15 +67,15 @@ class AuthZAsync(ServiceBaseAsync):
69
67
  Returns:
70
68
  Pangea Response with empty result.
71
69
  Available response fields can be found in our
72
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/tuple/create).
70
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/create).
73
71
 
74
72
  Examples:
75
73
  await authz.tuple_create(
76
74
  tuples=[
77
75
  Tuple(
78
- resource=Resource(namespace="file", id="file_1"),
76
+ resource=Resource(type="file", id="file_1"),
79
77
  relation="owner",
80
- subject=Subject(namespace="user", id="user_1"),
78
+ subject=Subject(type="user", id="user_1"),
81
79
  )
82
80
  ]
83
81
  )
@@ -85,7 +83,7 @@ class AuthZAsync(ServiceBaseAsync):
85
83
 
86
84
  input_data = TupleCreateRequest(tuples=tuples)
87
85
  return await self.request.post(
88
- "v1beta/tuple/create", TupleCreateResult, data=input_data.dict(exclude_none=True)
86
+ "v1/tuple/create", TupleCreateResult, data=input_data.model_dump(exclude_none=True)
89
87
  )
90
88
 
91
89
  async def tuple_list(
@@ -96,12 +94,11 @@ class AuthZAsync(ServiceBaseAsync):
96
94
  order: Optional[ItemOrder] = None,
97
95
  order_by: Optional[TupleOrderBy] = None,
98
96
  ) -> PangeaResponse[TupleListResult]:
99
- """List tuples. (Beta)
97
+ """List tuples.
100
98
 
101
99
  Return a paginated list of filtered tuples. The filter is given in terms
102
100
  of a tuple. Fill out the fields that you want to filter. If the filter
103
101
  is empty it will return all the tuples.
104
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
105
102
 
106
103
  Args:
107
104
  filter (TupleListFilter): The filter for listing tuples.
@@ -116,21 +113,20 @@ class AuthZAsync(ServiceBaseAsync):
116
113
  Returns:
117
114
  Pangea Response with a list of tuples and the last token.
118
115
  Available response fields can be found in our
119
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/tuple/list).
116
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/list).
120
117
 
121
118
  Examples:
122
- await authz.tuple_list(TupleListFilter(subject_namespace="user", subject_id="user_1"))
119
+ await authz.tuple_list(TupleListFilter(subject_type="user", subject_id="user_1"))
123
120
  """
124
121
  input_data = TupleListRequest(
125
- filter=filter.dict(exclude_none=True), size=size, last=last, order=order, order_by=order_by
122
+ filter=filter.model_dump(exclude_none=True), size=size, last=last, order=order, order_by=order_by
126
123
  )
127
- return await self.request.post("v1beta/tuple/list", TupleListResult, data=input_data.dict(exclude_none=True))
124
+ return await self.request.post("v1/tuple/list", TupleListResult, data=input_data.model_dump(exclude_none=True))
128
125
 
129
126
  async def tuple_delete(self, tuples: List[Tuple]) -> PangeaResponse[TupleDeleteResult]:
130
- """Delete tuples. (Beta)
127
+ """Delete tuples.
131
128
 
132
129
  Delete tuples in the AuthZ Service.
133
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
134
130
 
135
131
  Args:
136
132
  tuples (List[Tuple]): List of tuples to be deleted.
@@ -141,15 +137,15 @@ class AuthZAsync(ServiceBaseAsync):
141
137
  Returns:
142
138
  Pangea Response with empty result.
143
139
  Available response fields can be found in our
144
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/tuple/delete).
140
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/delete).
145
141
 
146
142
  Examples:
147
143
  await authz.tuple_delete(
148
144
  tuples=[
149
145
  Tuple(
150
- resource=Resource(namespace="file", id="file_1"),
146
+ resource=Resource(type="file", id="file_1"),
151
147
  relation="owner",
152
- subject=Subject(namespace="user", id="user_1"),
148
+ subject=Subject(type="user", id="user_1"),
153
149
  )
154
150
  ]
155
151
  )
@@ -157,7 +153,7 @@ class AuthZAsync(ServiceBaseAsync):
157
153
 
158
154
  input_data = TupleDeleteRequest(tuples=tuples)
159
155
  return await self.request.post(
160
- "v1beta/tuple/delete", TupleDeleteResult, data=input_data.dict(exclude_none=True)
156
+ "v1/tuple/delete", TupleDeleteResult, data=input_data.model_dump(exclude_none=True)
161
157
  )
162
158
 
163
159
  async def check(
@@ -168,10 +164,9 @@ class AuthZAsync(ServiceBaseAsync):
168
164
  debug: Optional[bool] = None,
169
165
  attributes: Optional[Dict[str, Union[int, str]]] = None,
170
166
  ) -> PangeaResponse[CheckResult]:
171
- """Perform a check request. (Beta)
167
+ """Perform a check request.
172
168
 
173
169
  Check if a subject has permission to perform an action on the resource.
174
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
175
170
 
176
171
  Args:
177
172
  resource (Resource): The resource to check.
@@ -186,31 +181,28 @@ class AuthZAsync(ServiceBaseAsync):
186
181
  Returns:
187
182
  Pangea Response with the result of the check.
188
183
  Available response fields can be found in our
189
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/check).
184
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/check).
190
185
 
191
186
  Examples:
192
187
  await authz.check(
193
- resource=Resource(namespace="file", id="file_1"),
188
+ resource=Resource(type="file", id="file_1"),
194
189
  action="update",
195
- subject=Subject(namespace="user", id="user_1"),
190
+ subject=Subject(type="user", id="user_1"),
196
191
  debug=True,
197
192
  )
198
193
  """
199
194
 
200
195
  input_data = CheckRequest(resource=resource, action=action, subject=subject, debug=debug, attributes=attributes)
201
- return await self.request.post("v1beta/check", CheckResult, data=input_data.dict(exclude_none=True))
196
+ return await self.request.post("v1/check", CheckResult, data=input_data.model_dump(exclude_none=True))
202
197
 
203
- async def list_resources(
204
- self, namespace: str, action: str, subject: Subject
205
- ) -> PangeaResponse[ListResourcesResult]:
206
- """List resources. (Beta)
198
+ async def list_resources(self, type: str, action: str, subject: Subject) -> PangeaResponse[ListResourcesResult]:
199
+ """List resources.
207
200
 
208
- Given a namespace, action, and subject, list all the resources in the
209
- namespace that the subject has access to the action with.
210
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
201
+ Given a type, action, and subject, list all the resources in the
202
+ type that the subject has access to the action with.
211
203
 
212
204
  Args:
213
- namespace (str): The namespace to filter resources.
205
+ type (str): The type to filter resources.
214
206
  action (str): The action to filter resources.
215
207
  subject (Subject): The subject to filter resources.
216
208
 
@@ -220,27 +212,26 @@ class AuthZAsync(ServiceBaseAsync):
220
212
  Returns:
221
213
  Pangea Response with a list of resource IDs.
222
214
  Available response fields can be found in our
223
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/list-resources).
215
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-resources).
224
216
 
225
217
  Examples:
226
218
  await authz.list_resources(
227
- namespace="file",
219
+ type="file",
228
220
  action="update",
229
- subject=Subject(namespace="user", id="user_1"),
221
+ subject=Subject(type="user", id="user_1"),
230
222
  )
231
223
  """
232
224
 
233
- input_data = ListResourcesRequest(namespace=namespace, action=action, subject=subject)
225
+ input_data = ListResourcesRequest(type=type, action=action, subject=subject)
234
226
  return await self.request.post(
235
- "v1beta/list-resources", ListResourcesResult, data=input_data.dict(exclude_none=True)
227
+ "v1/list-resources", ListResourcesResult, data=input_data.model_dump(exclude_none=True)
236
228
  )
237
229
 
238
230
  async def list_subjects(self, resource: Resource, action: str) -> PangeaResponse[ListSubjectsResult]:
239
- """List subjects. (Beta)
231
+ """List subjects.
240
232
 
241
233
  Given a resource and an action, return the list of subjects who have
242
234
  access to the action for the given resource.
243
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
244
235
 
245
236
  Args:
246
237
  resource (Resource): The resource to filter subjects.
@@ -252,16 +243,16 @@ class AuthZAsync(ServiceBaseAsync):
252
243
  Returns:
253
244
  Pangea Response with a list of subjects.
254
245
  Available response fields can be found in our
255
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/list-subjects).
246
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-subjects).
256
247
 
257
248
  Examples:
258
249
  await authz.list_subjects(
259
- resource=Resource(namespace="file", id="file_1"),
250
+ resource=Resource(type="file", id="file_1"),
260
251
  action="update",
261
252
  )
262
253
  """
263
254
 
264
255
  input_data = ListSubjectsRequest(resource=resource, action=action)
265
256
  return await self.request.post(
266
- "v1beta/list-subjects", ListSubjectsResult, data=input_data.dict(exclude_none=True)
257
+ "v1/list-subjects", ListSubjectsResult, data=input_data.model_dump(exclude_none=True)
267
258
  )
@@ -57,7 +57,7 @@ class EmbargoAsync(ServiceBaseAsync):
57
57
  response = embargo.ip_check("190.6.64.94")
58
58
  """
59
59
  input = e.IPCheckRequest(ip=ip)
60
- return await self.request.post("v1/ip/check", e.EmbargoResult, data=input.dict())
60
+ return await self.request.post("v1/ip/check", e.EmbargoResult, data=input.model_dump())
61
61
 
62
62
  async def iso_check(self, iso_code: str) -> PangeaResponse[e.EmbargoResult]:
63
63
  """
@@ -84,4 +84,4 @@ class EmbargoAsync(ServiceBaseAsync):
84
84
  response = embargo.iso_check("CU")
85
85
  """
86
86
  input = e.ISOCheckRequest(iso_code=iso_code)
87
- return await self.request.post("v1/iso/check", result_class=e.EmbargoResult, data=input.dict())
87
+ return await self.request.post("v1/iso/check", result_class=e.EmbargoResult, data=input.model_dump())
@@ -109,7 +109,7 @@ class FileScanAsync(ServiceBaseAsync):
109
109
  transfer_method=transfer_method,
110
110
  source_url=source_url,
111
111
  )
112
- data = input.dict(exclude_none=True)
112
+ data = input.model_dump(exclude_none=True)
113
113
  return await self.request.post("v1/scan", m.FileScanResult, data=data, files=files, poll_result=sync_call)
114
114
 
115
115
  async def request_upload_url(
@@ -131,7 +131,7 @@ class FileScanAsync(ServiceBaseAsync):
131
131
  input.sha256 = params.sha256_hex
132
132
  input.size = params.size
133
133
 
134
- data = input.dict(exclude_none=True)
134
+ data = input.model_dump(exclude_none=True)
135
135
  return await self.request.request_presigned_url("v1/scan", m.FileScanResult, data=data)
136
136
 
137
137
 
@@ -154,7 +154,7 @@ class FileUploaderAsync:
154
154
  ) -> None:
155
155
  if transfer_method == TransferMethod.PUT_URL:
156
156
  files = [("file", ("filename", file, "application/octet-stream"))]
157
- await self._request.put_presigned_url(url=url, files=files) # type: ignore[arg-type]
157
+ await self._request.put_presigned_url(url=url, files=files)
158
158
  elif transfer_method == TransferMethod.POST_URL:
159
159
  files = [("file", ("filename", file, "application/octet-stream"))]
160
160
  await self._request.post_presigned_url(url=url, data=file_details, files=files) # type: ignore[arg-type]
@@ -67,7 +67,9 @@ class FileIntelAsync(ServiceBaseAsync):
67
67
 
68
68
  """
69
69
  input = m.FileReputationRequest(hash=hash, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider)
70
- return await self.request.post("v1/reputation", m.FileReputationResult, data=input.dict(exclude_none=True))
70
+ return await self.request.post(
71
+ "v1/reputation", m.FileReputationResult, data=input.model_dump(exclude_none=True)
72
+ )
71
73
 
72
74
  async def hash_reputation_bulk(
73
75
  self,
@@ -76,7 +78,7 @@ class FileIntelAsync(ServiceBaseAsync):
76
78
  provider: Optional[str] = None,
77
79
  verbose: Optional[bool] = None,
78
80
  raw: Optional[bool] = None,
79
- ) -> PangeaResponse[m.FileReputationResult]:
81
+ ) -> PangeaResponse[m.FileReputationBulkResult]:
80
82
  """
81
83
  Reputation check
82
84
 
@@ -103,7 +105,9 @@ class FileIntelAsync(ServiceBaseAsync):
103
105
  input = m.FileReputationBulkRequest( # type: ignore[call-arg]
104
106
  hashes=hashes, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider
105
107
  )
106
- return await self.request.post("v2/reputation", m.FileReputationBulkResult, data=input.dict(exclude_none=True))
108
+ return await self.request.post(
109
+ "v2/reputation", m.FileReputationBulkResult, data=input.model_dump(exclude_none=True)
110
+ )
107
111
 
108
112
  async def filepath_reputation(
109
113
  self,
@@ -144,7 +148,9 @@ class FileIntelAsync(ServiceBaseAsync):
144
148
  hash = hashlib.sha256(data.read()).hexdigest()
145
149
 
146
150
  input = m.FileReputationRequest(hash=hash, hash_type="sha256", verbose=verbose, raw=raw, provider=provider)
147
- return await self.request.post("v1/reputation", m.FileReputationResult, data=input.dict(exclude_none=True))
151
+ return await self.request.post(
152
+ "v1/reputation", m.FileReputationResult, data=input.model_dump(exclude_none=True)
153
+ )
148
154
 
149
155
  async def filepath_reputation_bulk(
150
156
  self,
@@ -182,7 +188,7 @@ class FileIntelAsync(ServiceBaseAsync):
182
188
  hash = hash_256_filepath(filepath)
183
189
  hashes.append(hash)
184
190
 
185
- return await self.hash_reputation_bulk( # type: ignore[return-value]
191
+ return await self.hash_reputation_bulk(
186
192
  hashes=hashes, hash_type="sha256", verbose=verbose, raw=raw, provider=provider
187
193
  )
188
194
 
@@ -243,7 +249,9 @@ class DomainIntelAsync(ServiceBaseAsync):
243
249
  )
244
250
  """
245
251
  input = m.DomainReputationRequest(domain=domain, verbose=verbose, provider=provider, raw=raw)
246
- return await self.request.post("v1/reputation", m.DomainReputationResult, data=input.dict(exclude_none=True))
252
+ return await self.request.post(
253
+ "v1/reputation", m.DomainReputationResult, data=input.model_dump(exclude_none=True)
254
+ )
247
255
 
248
256
  async def reputation_bulk(
249
257
  self,
@@ -251,7 +259,7 @@ class DomainIntelAsync(ServiceBaseAsync):
251
259
  verbose: Optional[bool] = None,
252
260
  raw: Optional[bool] = None,
253
261
  provider: Optional[str] = None,
254
- ) -> PangeaResponse[m.DomainReputationResult]:
262
+ ) -> PangeaResponse[m.DomainReputationBulkResult]:
255
263
  """
256
264
  Reputation
257
265
 
@@ -277,7 +285,7 @@ class DomainIntelAsync(ServiceBaseAsync):
277
285
  """
278
286
  input = m.DomainReputationBulkRequest(domains=domains, verbose=verbose, provider=provider, raw=raw)
279
287
  return await self.request.post(
280
- "v2/reputation", m.DomainReputationBulkResult, data=input.dict(exclude_none=True)
288
+ "v2/reputation", m.DomainReputationBulkResult, data=input.model_dump(exclude_none=True)
281
289
  )
282
290
 
283
291
  async def who_is(
@@ -310,7 +318,7 @@ class DomainIntelAsync(ServiceBaseAsync):
310
318
  )
311
319
  """
312
320
  input = m.DomainWhoIsRequest(domain=domain, verbose=verbose, provider=provider, raw=raw) # type: ignore[call-arg]
313
- return await self.request.post("v1/whois", m.DomainWhoIsResult, data=input.dict(exclude_none=True))
321
+ return await self.request.post("v1/whois", m.DomainWhoIsResult, data=input.model_dump(exclude_none=True))
314
322
 
315
323
 
316
324
  class IpIntelAsync(ServiceBaseAsync):
@@ -369,11 +377,11 @@ class IpIntelAsync(ServiceBaseAsync):
369
377
  )
370
378
  """
371
379
  input = m.IPReputationRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
372
- return await self.request.post("v1/reputation", m.IPReputationResult, data=input.dict(exclude_none=True))
380
+ return await self.request.post("v1/reputation", m.IPReputationResult, data=input.model_dump(exclude_none=True))
373
381
 
374
382
  async def reputation_bulk(
375
383
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
376
- ) -> PangeaResponse[m.IPReputationResult]:
384
+ ) -> PangeaResponse[m.IPReputationBulkResult]:
377
385
  """
378
386
  Reputation
379
387
 
@@ -398,7 +406,9 @@ class IpIntelAsync(ServiceBaseAsync):
398
406
  FIXME:
399
407
  """
400
408
  input = m.IPReputationBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
401
- return await self.request.post("v2/reputation", m.IPReputationBulkResult, data=input.dict(exclude_none=True))
409
+ return await self.request.post(
410
+ "v2/reputation", m.IPReputationBulkResult, data=input.model_dump(exclude_none=True)
411
+ )
402
412
 
403
413
  async def geolocate(
404
414
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -430,7 +440,7 @@ class IpIntelAsync(ServiceBaseAsync):
430
440
  )
431
441
  """
432
442
  input = m.IPGeolocateRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
433
- return await self.request.post("v1/geolocate", m.IPGeolocateResult, data=input.dict(exclude_none=True))
443
+ return await self.request.post("v1/geolocate", m.IPGeolocateResult, data=input.model_dump(exclude_none=True))
434
444
 
435
445
  async def geolocate_bulk(
436
446
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -459,7 +469,9 @@ class IpIntelAsync(ServiceBaseAsync):
459
469
  FIXME:
460
470
  """
461
471
  input = m.IPGeolocateBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
462
- return await self.request.post("v2/geolocate", m.IPGeolocateBulkResult, data=input.dict(exclude_none=True))
472
+ return await self.request.post(
473
+ "v2/geolocate", m.IPGeolocateBulkResult, data=input.model_dump(exclude_none=True)
474
+ )
463
475
 
464
476
  async def get_domain(
465
477
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -491,7 +503,7 @@ class IpIntelAsync(ServiceBaseAsync):
491
503
  )
492
504
  """
493
505
  input = m.IPDomainRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
494
- return await self.request.post("v1/domain", m.IPDomainResult, data=input.dict(exclude_none=True))
506
+ return await self.request.post("v1/domain", m.IPDomainResult, data=input.model_dump(exclude_none=True))
495
507
 
496
508
  async def get_domain_bulk(
497
509
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -520,7 +532,7 @@ class IpIntelAsync(ServiceBaseAsync):
520
532
  FIXME:
521
533
  """
522
534
  input = m.IPDomainBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
523
- return await self.request.post("v2/domain", m.IPDomainBulkResult, data=input.dict(exclude_none=True))
535
+ return await self.request.post("v2/domain", m.IPDomainBulkResult, data=input.model_dump(exclude_none=True))
524
536
 
525
537
  async def is_vpn(
526
538
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -552,7 +564,7 @@ class IpIntelAsync(ServiceBaseAsync):
552
564
  )
553
565
  """
554
566
  input = m.IPVPNRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
555
- return await self.request.post("v1/vpn", m.IPVPNResult, data=input.dict(exclude_none=True))
567
+ return await self.request.post("v1/vpn", m.IPVPNResult, data=input.model_dump(exclude_none=True))
556
568
 
557
569
  async def is_vpn_bulk(
558
570
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -581,7 +593,7 @@ class IpIntelAsync(ServiceBaseAsync):
581
593
  FIXME:
582
594
  """
583
595
  input = m.IPVPNBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
584
- return await self.request.post("v2/vpn", m.IPVPNBulkResult, data=input.dict(exclude_none=True))
596
+ return await self.request.post("v2/vpn", m.IPVPNBulkResult, data=input.model_dump(exclude_none=True))
585
597
 
586
598
  async def is_proxy(
587
599
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -613,7 +625,7 @@ class IpIntelAsync(ServiceBaseAsync):
613
625
  )
614
626
  """
615
627
  input = m.IPProxyRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
616
- return await self.request.post("v1/proxy", m.IPProxyResult, data=input.dict(exclude_none=True))
628
+ return await self.request.post("v1/proxy", m.IPProxyResult, data=input.model_dump(exclude_none=True))
617
629
 
618
630
  async def is_proxy_bulk(
619
631
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -642,7 +654,7 @@ class IpIntelAsync(ServiceBaseAsync):
642
654
  FIXME:
643
655
  """
644
656
  input = m.IPProxyBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
645
- return await self.request.post("v2/proxy", m.IPProxyBulkResult, data=input.dict(exclude_none=True))
657
+ return await self.request.post("v2/proxy", m.IPProxyBulkResult, data=input.model_dump(exclude_none=True))
646
658
 
647
659
 
648
660
  class UrlIntelAsync(ServiceBaseAsync):
@@ -702,7 +714,7 @@ class UrlIntelAsync(ServiceBaseAsync):
702
714
  """
703
715
 
704
716
  input = m.URLReputationRequest(url=url, provider=provider, verbose=verbose, raw=raw)
705
- return await self.request.post("v1/reputation", m.URLReputationResult, data=input.dict(exclude_none=True))
717
+ return await self.request.post("v1/reputation", m.URLReputationResult, data=input.model_dump(exclude_none=True))
706
718
 
707
719
  async def reputation_bulk(
708
720
  self,
@@ -736,7 +748,9 @@ class UrlIntelAsync(ServiceBaseAsync):
736
748
  """
737
749
 
738
750
  input = m.URLReputationBulkRequest(urls=urls, provider=provider, verbose=verbose, raw=raw)
739
- return await self.request.post("v2/reputation", m.URLReputationBulkResult, data=input.dict(exclude_none=True))
751
+ return await self.request.post(
752
+ "v2/reputation", m.URLReputationBulkResult, data=input.model_dump(exclude_none=True)
753
+ )
740
754
 
741
755
 
742
756
  class UserIntelAsync(ServiceBaseAsync):
@@ -822,7 +836,9 @@ class UserIntelAsync(ServiceBaseAsync):
822
836
  verbose=verbose,
823
837
  raw=raw,
824
838
  )
825
- return await self.request.post("v1/user/breached", m.UserBreachedResult, data=input.dict(exclude_none=True))
839
+ return await self.request.post(
840
+ "v1/user/breached", m.UserBreachedResult, data=input.model_dump(exclude_none=True)
841
+ )
826
842
 
827
843
  async def user_breached_bulk(
828
844
  self,
@@ -876,7 +892,9 @@ class UserIntelAsync(ServiceBaseAsync):
876
892
  verbose=verbose,
877
893
  raw=raw,
878
894
  )
879
- return await self.request.post("v2/user/breached", m.UserBreachedBulkResult, data=input.dict(exclude_none=True))
895
+ return await self.request.post(
896
+ "v2/user/breached", m.UserBreachedBulkResult, data=input.model_dump(exclude_none=True)
897
+ )
880
898
 
881
899
  async def password_breached(
882
900
  self,
@@ -919,7 +937,7 @@ class UserIntelAsync(ServiceBaseAsync):
919
937
  hash_type=hash_type, hash_prefix=hash_prefix, provider=provider, verbose=verbose, raw=raw
920
938
  )
921
939
  return await self.request.post(
922
- "v1/password/breached", m.UserPasswordBreachedResult, data=input.dict(exclude_none=True)
940
+ "v1/password/breached", m.UserPasswordBreachedResult, data=input.model_dump(exclude_none=True)
923
941
  )
924
942
 
925
943
  async def password_breached_bulk(
@@ -959,5 +977,5 @@ class UserIntelAsync(ServiceBaseAsync):
959
977
  hash_type=hash_type, hash_prefixes=hash_prefixes, provider=provider, verbose=verbose, raw=raw
960
978
  )
961
979
  return await self.request.post(
962
- "v2/password/breached", m.UserPasswordBreachedBulkResult, data=input.dict(exclude_none=True)
980
+ "v2/password/breached", m.UserPasswordBreachedBulkResult, data=input.model_dump(exclude_none=True)
963
981
  )
@@ -1,10 +1,12 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
3
4
 
4
5
  from typing import Dict, List, Optional, Union
5
6
 
6
7
  import pangea.services.redact as m
7
8
  from pangea.asyncio.services.base import ServiceBaseAsync
9
+ from pangea.config import PangeaConfig
8
10
  from pangea.response import PangeaResponse
9
11
 
10
12
 
@@ -35,7 +37,24 @@ class RedactAsync(ServiceBaseAsync):
35
37
 
36
38
  service_name = "redact"
37
39
 
38
- def __init__(self, token, config=None, logger_name="pangea", config_id: Optional[str] = None):
40
+ def __init__(
41
+ self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
42
+ ) -> None:
43
+ """
44
+ Redact client
45
+
46
+ Initializes a new Redact client.
47
+
48
+ Args:
49
+ token: Pangea API token.
50
+ config: Configuration.
51
+ logger_name: Logger name.
52
+
53
+ Examples:
54
+ config = PangeaConfig(domain="pangea_domain")
55
+ redact = RedactAsync(token="pangea_token", config=config)
56
+ """
57
+
39
58
  super().__init__(token, config, logger_name, config_id=config_id)
40
59
 
41
60
  async def redact(
@@ -45,6 +64,7 @@ class RedactAsync(ServiceBaseAsync):
45
64
  rules: Optional[List[str]] = None,
46
65
  rulesets: Optional[List[str]] = None,
47
66
  return_result: Optional[bool] = None,
67
+ redaction_method_overrides: Optional[m.RedactionMethodOverrides] = None,
48
68
  ) -> PangeaResponse[m.RedactResult]:
49
69
  """
50
70
  Redact
@@ -60,6 +80,7 @@ class RedactAsync(ServiceBaseAsync):
60
80
  rules (list[str], optional): An array of redact rule short names
61
81
  rulesets (list[str], optional): An array of redact rulesets short names
62
82
  return_result(bool, optional): Setting this value to false will omit the redacted result only returning count
83
+ redaction_method_overrides: A set of redaction method overrides for any enabled rule. These methods override the config declared methods
63
84
 
64
85
  Raises:
65
86
  PangeaAPIException: If an API Error happens
@@ -73,8 +94,15 @@ class RedactAsync(ServiceBaseAsync):
73
94
  response = redact.redact(text="Jenny Jenny... 555-867-5309")
74
95
  """
75
96
 
76
- input = m.RedactRequest(text=text, debug=debug, rules=rules, rulesets=rulesets, return_result=return_result)
77
- return await self.request.post("v1/redact", m.RedactResult, data=input.dict(exclude_none=True))
97
+ input = m.RedactRequest(
98
+ text=text,
99
+ debug=debug,
100
+ rules=rules,
101
+ rulesets=rulesets,
102
+ return_result=return_result,
103
+ redaction_method_overrides=redaction_method_overrides,
104
+ )
105
+ return await self.request.post("v1/redact", m.RedactResult, data=input.model_dump(exclude_none=True))
78
106
 
79
107
  async def redact_structured(
80
108
  self,
@@ -85,6 +113,7 @@ class RedactAsync(ServiceBaseAsync):
85
113
  rules: Optional[List[str]] = None,
86
114
  rulesets: Optional[List[str]] = None,
87
115
  return_result: Optional[bool] = None,
116
+ redaction_method_overrides: Optional[m.RedactionMethodOverrides] = None,
88
117
  ) -> PangeaResponse[m.StructuredResult]:
89
118
  """
90
119
  Redact structured
@@ -104,6 +133,7 @@ class RedactAsync(ServiceBaseAsync):
104
133
  rules (list[str], optional): An array of redact rule short names
105
134
  rulesets (list[str], optional): An array of redact rulesets short names
106
135
  return_result(bool, optional): Setting this value to false will omit the redacted result only returning count
136
+ redaction_method_overrides: A set of redaction method overrides for any enabled rule. These methods override the config declared methods
107
137
 
108
138
  Raises:
109
139
  PangeaAPIException: If an API Error happens
@@ -130,5 +160,31 @@ class RedactAsync(ServiceBaseAsync):
130
160
  rules=rules,
131
161
  rulesets=rulesets,
132
162
  return_result=return_result,
163
+ redaction_method_overrides=redaction_method_overrides,
164
+ )
165
+ return await self.request.post(
166
+ "v1/redact_structured", m.StructuredResult, data=input.model_dump(exclude_none=True)
133
167
  )
134
- return await self.request.post("v1/redact_structured", m.StructuredResult, data=input.dict(exclude_none=True))
168
+
169
+ async def unredact(self, redacted_data: m.RedactedData, fpe_context: str) -> PangeaResponse[m.UnredactResult]:
170
+ """
171
+ Unredact
172
+
173
+ Decrypt or unredact fpe redactions
174
+
175
+ OperationId: redact_post_v1_unredact
176
+
177
+ Args:
178
+ redacted_data: Data to unredact
179
+ fpe_context (base64): FPE context used to decrypt and unredact data
180
+
181
+ Raises:
182
+ PangeaAPIException: If an API Error happens
183
+
184
+ Returns:
185
+ Pangea Response with redacted data in the response.result field,
186
+ available response fields can be found in our
187
+ [API Documentation](https://pangea.cloud/docs/api/redact#unredact)
188
+ """
189
+ input = m.UnredactRequest(redacted_data=redacted_data, fpe_context=fpe_context)
190
+ return await self.request.post("v1/unredact", m.UnredactResult, data=input.model_dump(exclude_none=True))