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
pangea/services/authz.py CHANGED
@@ -20,10 +20,10 @@ class ItemOrder(str, enum.Enum):
20
20
 
21
21
 
22
22
  class TupleOrderBy(str, enum.Enum):
23
- RESOURCE_NAMESPACE = "resource_namespace"
23
+ RESOURCE_TYPE = "resource_type"
24
24
  RESOURCE_ID = "resource_id"
25
25
  RELATION = "relation"
26
- SUBJECT_NAMESPACE = "subject_namespace"
26
+ SUBJECT_TYPE = "subject_type"
27
27
  SUBJECT_ID = "subject_id"
28
28
  SUBJECT_ACTION = "subject_action"
29
29
 
@@ -35,12 +35,12 @@ class TupleOrderBy(str, enum.Enum):
35
35
 
36
36
 
37
37
  class Resource(PangeaResponseResult):
38
- namespace: str
38
+ type: str
39
39
  id: Optional[str] = None
40
40
 
41
41
 
42
42
  class Subject(PangeaResponseResult):
43
- namespace: str
43
+ type: str
44
44
  id: Optional[str] = None
45
45
  action: Optional[str] = None
46
46
 
@@ -60,18 +60,18 @@ class TupleCreateResult(PangeaResponseResult):
60
60
 
61
61
 
62
62
  class TupleListFilter(APIRequestModel):
63
- resource_namespace: Optional[str] = None
64
- resource_namespace__contains: Optional[List[str]] = None
65
- resource_namespace__in: Optional[List[str]] = None
63
+ resource_type: Optional[str] = None
64
+ resource_type__contains: Optional[List[str]] = None
65
+ resource_type__in: Optional[List[str]] = None
66
66
  resource_id: Optional[str] = None
67
67
  resource_id__contains: Optional[List[str]] = None
68
68
  resource_id__in: Optional[List[str]] = None
69
69
  relation: Optional[str] = None
70
70
  relation__contains: Optional[List[str]] = None
71
71
  relation__in: Optional[List[str]] = None
72
- subject_namespace: Optional[str] = None
73
- subject_namespace__contains: Optional[List[str]] = None
74
- subject_namespace__in: Optional[List[str]] = None
72
+ subject_type: Optional[str] = None
73
+ subject_type__contains: Optional[List[str]] = None
74
+ subject_type__in: Optional[List[str]] = None
75
75
  subject_id: Optional[str] = None
76
76
  subject_id__contains: Optional[List[str]] = None
77
77
  subject_id__in: Optional[List[str]] = None
@@ -111,9 +111,9 @@ class CheckRequest(APIRequestModel):
111
111
 
112
112
 
113
113
  class DebugPath(APIResponseModel):
114
- namespace: str
114
+ type: str
115
115
  id: str
116
- action: Optional[str]
116
+ action: Optional[str] = None
117
117
 
118
118
 
119
119
  class Debug(APIResponseModel):
@@ -129,7 +129,7 @@ class CheckResult(PangeaResponseResult):
129
129
 
130
130
 
131
131
  class ListResourcesRequest(APIRequestModel):
132
- namespace: str
132
+ type: str
133
133
  action: str
134
134
  subject: Subject
135
135
 
@@ -148,12 +148,11 @@ class ListSubjectsResult(PangeaResponseResult):
148
148
 
149
149
 
150
150
  class AuthZ(ServiceBase):
151
- """AuthZ service client. (Beta)
151
+ """AuthZ service client.
152
152
 
153
153
  Provides methods to interact with the Pangea AuthZ Service.
154
154
  Documentation for the AuthZ Service API can be found at
155
- <https://pangea.cloud/docs/api/authz>. Note that this service is in Beta and
156
- is subject to change.
155
+ <https://pangea.cloud/docs/api/authz>.
157
156
 
158
157
  Examples:
159
158
  import os
@@ -174,11 +173,10 @@ class AuthZ(ServiceBase):
174
173
  super().__init__(token, config, logger_name, config_id=config_id)
175
174
 
176
175
  def tuple_create(self, tuples: List[Tuple]) -> PangeaResponse[TupleCreateResult]:
177
- """Create tuples. (Beta)
176
+ """Create tuples.
178
177
 
179
178
  Create tuples in the AuthZ Service. The request will fail if there is no schema
180
179
  or the tuples do not validate against the schema.
181
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
182
180
 
183
181
  Args:
184
182
  tuples (List[Tuple]): List of tuples to be created.
@@ -189,22 +187,22 @@ class AuthZ(ServiceBase):
189
187
  Returns:
190
188
  Pangea Response with empty result.
191
189
  Available response fields can be found in our
192
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/tuple/create).
190
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/create).
193
191
 
194
192
  Examples:
195
193
  response = authz.tuple_create(
196
194
  tuples=[
197
195
  Tuple(
198
- resource=Resource(namespace="file", id="file_1"),
196
+ resource=Resource(type="file", id="file_1"),
199
197
  relation="owner",
200
- subject=Subject(namespace="user", id="user_1"),
198
+ subject=Subject(type="user", id="user_1"),
201
199
  )
202
200
  ]
203
201
  )
204
202
  """
205
203
 
206
204
  input_data = TupleCreateRequest(tuples=tuples)
207
- return self.request.post("v1beta/tuple/create", TupleCreateResult, data=input_data.dict(exclude_none=True))
205
+ return self.request.post("v1/tuple/create", TupleCreateResult, data=input_data.model_dump(exclude_none=True))
208
206
 
209
207
  def tuple_list(
210
208
  self,
@@ -214,12 +212,11 @@ class AuthZ(ServiceBase):
214
212
  order: Optional[ItemOrder] = None,
215
213
  order_by: Optional[TupleOrderBy] = None,
216
214
  ) -> PangeaResponse[TupleListResult]:
217
- """List tuples. (Beta)
215
+ """List tuples.
218
216
 
219
217
  Return a paginated list of filtered tuples. The filter is given in terms
220
218
  of a tuple. Fill out the fields that you want to filter. If the filter
221
219
  is empty it will return all the tuples.
222
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
223
220
 
224
221
  Args:
225
222
  filter (TupleListFilter): The filter for listing tuples.
@@ -234,21 +231,20 @@ class AuthZ(ServiceBase):
234
231
  Returns:
235
232
  Pangea Response with a list of tuples and the last token.
236
233
  Available response fields can be found in our
237
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/tuple/list).
234
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/list).
238
235
 
239
236
  Examples:
240
- authz.tuple_list(TupleListFilter(subject_namespace="user", subject_id="user_1"))
237
+ authz.tuple_list(TupleListFilter(subject_type="user", subject_id="user_1"))
241
238
  """
242
239
  input_data = TupleListRequest(
243
- filter=filter.dict(exclude_none=True), size=size, last=last, order=order, order_by=order_by
240
+ filter=filter.model_dump(exclude_none=True), size=size, last=last, order=order, order_by=order_by
244
241
  )
245
- return self.request.post("v1beta/tuple/list", TupleListResult, data=input_data.dict(exclude_none=True))
242
+ return self.request.post("v1/tuple/list", TupleListResult, data=input_data.model_dump(exclude_none=True))
246
243
 
247
244
  def tuple_delete(self, tuples: List[Tuple]) -> PangeaResponse[TupleDeleteResult]:
248
- """Delete tuples. (Beta)
245
+ """Delete tuples.
249
246
 
250
247
  Delete tuples in the AuthZ Service.
251
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
252
248
 
253
249
  Args:
254
250
  tuples (List[Tuple]): List of tuples to be deleted.
@@ -259,22 +255,22 @@ class AuthZ(ServiceBase):
259
255
  Returns:
260
256
  Pangea Response with empty result.
261
257
  Available response fields can be found in our
262
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/tuple/delete).
258
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/delete).
263
259
 
264
260
  Examples:
265
261
  response = authz.tuple_delete(
266
262
  tuples=[
267
263
  Tuple(
268
- resource=Resource(namespace="file", id="file_1"),
264
+ resource=Resource(type="file", id="file_1"),
269
265
  relation="owner",
270
- subject=Subject(namespace="user", id="user_1"),
266
+ subject=Subject(type="user", id="user_1"),
271
267
  )
272
268
  ]
273
269
  )
274
270
  """
275
271
 
276
272
  input_data = TupleDeleteRequest(tuples=tuples)
277
- return self.request.post("v1beta/tuple/delete", TupleDeleteResult, data=input_data.dict(exclude_none=True))
273
+ return self.request.post("v1/tuple/delete", TupleDeleteResult, data=input_data.model_dump(exclude_none=True))
278
274
 
279
275
  def check(
280
276
  self,
@@ -284,10 +280,9 @@ class AuthZ(ServiceBase):
284
280
  debug: Optional[bool] = None,
285
281
  attributes: Optional[Dict[str, Union[int, str]]] = None,
286
282
  ) -> PangeaResponse[CheckResult]:
287
- """Perform a check request. (Beta)
283
+ """Perform a check request.
288
284
 
289
285
  Check if a subject has permission to perform an action on the resource.
290
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
291
286
 
292
287
  Args:
293
288
  resource (Resource): The resource to check.
@@ -302,29 +297,28 @@ class AuthZ(ServiceBase):
302
297
  Returns:
303
298
  Pangea Response with the result of the check.
304
299
  Available response fields can be found in our
305
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/check).
300
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/check).
306
301
 
307
302
  Examples:
308
303
  response = authz.check(
309
- resource=Resource(namespace="file", id="file_1"),
304
+ resource=Resource(type="file", id="file_1"),
310
305
  action="update",
311
- subject=Subject(namespace="user", id="user_1"),
306
+ subject=Subject(type="user", id="user_1"),
312
307
  debug=True,
313
308
  )
314
309
  """
315
310
 
316
311
  input_data = CheckRequest(resource=resource, action=action, subject=subject, debug=debug, attributes=attributes)
317
- return self.request.post("v1beta/check", CheckResult, data=input_data.dict(exclude_none=True))
312
+ return self.request.post("v1/check", CheckResult, data=input_data.model_dump(exclude_none=True))
318
313
 
319
- def list_resources(self, namespace: str, action: str, subject: Subject) -> PangeaResponse[ListResourcesResult]:
320
- """List resources. (Beta)
314
+ def list_resources(self, type: str, action: str, subject: Subject) -> PangeaResponse[ListResourcesResult]:
315
+ """List resources.
321
316
 
322
- Given a namespace, action, and subject, list all the resources in the
323
- namespace that the subject has access to the action with.
324
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
317
+ Given a type, action, and subject, list all the resources in the
318
+ type that the subject has access to the action with.
325
319
 
326
320
  Args:
327
- namespace (str): The namespace to filter resources.
321
+ type (str): The type to filter resources.
328
322
  action (str): The action to filter resources.
329
323
  subject (Subject): The subject to filter resources.
330
324
 
@@ -334,25 +328,26 @@ class AuthZ(ServiceBase):
334
328
  Returns:
335
329
  Pangea Response with a list of resource IDs.
336
330
  Available response fields can be found in our
337
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/list-resources).
331
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-resources).
338
332
 
339
333
  Examples:
340
334
  authz.list_resources(
341
- namespace="file",
335
+ type="file",
342
336
  action="update",
343
- subject=Subject(namespace="user", id="user_1"),
337
+ subject=Subject(type="user", id="user_1"),
344
338
  )
345
339
  """
346
340
 
347
- input_data = ListResourcesRequest(namespace=namespace, action=action, subject=subject)
348
- return self.request.post("v1beta/list-resources", ListResourcesResult, data=input_data.dict(exclude_none=True))
341
+ input_data = ListResourcesRequest(type=type, action=action, subject=subject)
342
+ return self.request.post(
343
+ "v1/list-resources", ListResourcesResult, data=input_data.model_dump(exclude_none=True)
344
+ )
349
345
 
350
346
  def list_subjects(self, resource: Resource, action: str) -> PangeaResponse[ListSubjectsResult]:
351
- """List subjects. (Beta)
347
+ """List subjects.
352
348
 
353
349
  Given a resource and an action, return the list of subjects who have
354
350
  access to the action for the given resource.
355
- How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
356
351
 
357
352
  Args:
358
353
  resource (Resource): The resource to filter subjects.
@@ -364,14 +359,14 @@ class AuthZ(ServiceBase):
364
359
  Returns:
365
360
  Pangea Response with a list of subjects.
366
361
  Available response fields can be found in our
367
- [API Documentation](https://pangea.cloud/docs/api/authz#/v1beta/list-subjects).
362
+ [API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-subjects).
368
363
 
369
364
  Examples:
370
365
  response = authz.list_subjects(
371
- resource=Resource(namespace="file", id="file_1"),
366
+ resource=Resource(type="file", id="file_1"),
372
367
  action="update",
373
368
  )
374
369
  """
375
370
 
376
371
  input_data = ListSubjectsRequest(resource=resource, action=action)
377
- return self.request.post("v1beta/list-subjects", ListSubjectsResult, data=input_data.dict(exclude_none=True))
372
+ return self.request.post("v1/list-subjects", ListSubjectsResult, data=input_data.model_dump(exclude_none=True))
pangea/services/base.py CHANGED
@@ -1,23 +1,40 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
3
4
 
4
5
  import copy
5
6
  import logging
6
7
  from typing import Dict, Optional, Type, Union
7
8
 
9
+ from typing_extensions import TypeVar
10
+
8
11
  from pangea.asyncio.request import PangeaRequestAsync
9
12
  from pangea.config import PangeaConfig
10
13
  from pangea.exceptions import AcceptedRequestException
11
14
  from pangea.request import PangeaRequest
12
15
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
13
16
 
17
+ TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
18
+
14
19
 
15
20
  class ServiceBase(object):
16
21
  service_name: str = "base"
17
22
 
18
23
  def __init__(
19
- self, token, config: Optional[PangeaConfig] = None, logger_name: str = "pangea", config_id: Optional[str] = None
20
- ):
24
+ self,
25
+ token: str,
26
+ config: PangeaConfig | None = None,
27
+ logger_name: str = "pangea",
28
+ config_id: str | None = None,
29
+ ) -> None:
30
+ """
31
+ Initializes a new Pangea service client.
32
+
33
+ Args:
34
+ token: Pangea API token.
35
+ config: Configuration.
36
+ logger_name: Logger name.
37
+ """
21
38
  if not token:
22
39
  raise Exception("No token provided")
23
40
 
@@ -30,11 +47,11 @@ class ServiceBase(object):
30
47
  self.request.set_extra_headers(extra_headers)
31
48
 
32
49
  @property
33
- def token(self):
50
+ def token(self) -> str:
34
51
  return self._token
35
52
 
36
53
  @token.setter
37
- def token(self, value):
54
+ def token(self, value: str) -> None:
38
55
  self._token = value
39
56
 
40
57
  @property
@@ -55,8 +72,8 @@ class ServiceBase(object):
55
72
  exception: Optional[AcceptedRequestException] = None,
56
73
  response: Optional[PangeaResponse] = None,
57
74
  request_id: Optional[str] = None,
58
- result_class: Union[Type[PangeaResponseResult], Type[Dict]] = dict,
59
- ) -> PangeaResponse:
75
+ result_class: Type[TResult] = PangeaResponseResult, # type: ignore[assignment]
76
+ ) -> PangeaResponse[TResult]:
60
77
  """
61
78
  Poll result
62
79
 
@@ -103,7 +103,7 @@ class Embargo(ServiceBase):
103
103
  response = embargo.ip_check("190.6.64.94")
104
104
  """
105
105
  input = IPCheckRequest(ip=ip)
106
- return self.request.post("v1/ip/check", EmbargoResult, data=input.dict())
106
+ return self.request.post("v1/ip/check", EmbargoResult, data=input.model_dump())
107
107
 
108
108
  def iso_check(self, iso_code: str) -> PangeaResponse[EmbargoResult]:
109
109
  """
@@ -130,4 +130,4 @@ class Embargo(ServiceBase):
130
130
  response = embargo.iso_check("CU")
131
131
  """
132
132
  input = ISOCheckRequest(iso_code=iso_code)
133
- return self.request.post("v1/iso/check", result_class=EmbargoResult, data=input.dict())
133
+ return self.request.post("v1/iso/check", result_class=EmbargoResult, data=input.model_dump())
@@ -71,6 +71,7 @@ class FileScan(ServiceBase):
71
71
  """
72
72
 
73
73
  service_name = "file-scan"
74
+ version = "v1"
74
75
 
75
76
  def file_scan(
76
77
  self,
@@ -141,7 +142,7 @@ class FileScan(ServiceBase):
141
142
  transfer_method=transfer_method,
142
143
  source_url=source_url,
143
144
  )
144
- data = input.dict(exclude_none=True)
145
+ data = input.model_dump(exclude_none=True)
145
146
  return self.request.post("v1/scan", FileScanResult, data=data, files=files, poll_result=sync_call)
146
147
 
147
148
  def request_upload_url(
@@ -163,7 +164,7 @@ class FileScan(ServiceBase):
163
164
  input.sha256 = params.sha256_hex
164
165
  input.size = params.size
165
166
 
166
- data = input.dict(exclude_none=True)
167
+ data = input.model_dump(exclude_none=True)
167
168
  return self.request.request_presigned_url("v1/scan", FileScanResult, data=data)
168
169
 
169
170
 
pangea/services/intel.py CHANGED
@@ -524,7 +524,7 @@ class FileIntel(ServiceBase):
524
524
  )
525
525
  """
526
526
  input = FileReputationRequest(hash=hash, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider)
527
- return self.request.post("v1/reputation", FileReputationResult, data=input.dict(exclude_none=True))
527
+ return self.request.post("v1/reputation", FileReputationResult, data=input.model_dump(exclude_none=True))
528
528
 
529
529
  def hash_reputation_bulk(
530
530
  self,
@@ -563,7 +563,7 @@ class FileIntel(ServiceBase):
563
563
  input = FileReputationBulkRequest( # type: ignore[call-arg]
564
564
  hashes=hashes, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider
565
565
  )
566
- return self.request.post("v2/reputation", FileReputationBulkResult, data=input.dict(exclude_none=True))
566
+ return self.request.post("v2/reputation", FileReputationBulkResult, data=input.model_dump(exclude_none=True))
567
567
 
568
568
  def filepath_reputation(
569
569
  self,
@@ -708,7 +708,7 @@ class DomainIntel(ServiceBase):
708
708
  )
709
709
  """
710
710
  input = DomainReputationRequest(domain=domain, verbose=verbose, provider=provider, raw=raw)
711
- return self.request.post("v1/reputation", DomainReputationResult, data=input.dict(exclude_none=True))
711
+ return self.request.post("v1/reputation", DomainReputationResult, data=input.model_dump(exclude_none=True))
712
712
 
713
713
  def reputation_bulk(
714
714
  self,
@@ -744,7 +744,7 @@ class DomainIntel(ServiceBase):
744
744
  )
745
745
  """
746
746
  input = DomainReputationBulkRequest(domains=domains, verbose=verbose, provider=provider, raw=raw)
747
- return self.request.post("v2/reputation", DomainReputationBulkResult, data=input.dict(exclude_none=True))
747
+ return self.request.post("v2/reputation", DomainReputationBulkResult, data=input.model_dump(exclude_none=True))
748
748
 
749
749
  def who_is(
750
750
  self, domain: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -776,7 +776,7 @@ class DomainIntel(ServiceBase):
776
776
  )
777
777
  """
778
778
  input = DomainWhoIsRequest(domain=domain, verbose=verbose, provider=provider, raw=raw) # type: ignore[call-arg]
779
- return self.request.post("v1/whois", DomainWhoIsResult, data=input.dict(exclude_none=True))
779
+ return self.request.post("v1/whois", DomainWhoIsResult, data=input.model_dump(exclude_none=True))
780
780
 
781
781
 
782
782
  class IpIntel(ServiceBase):
@@ -835,11 +835,11 @@ class IpIntel(ServiceBase):
835
835
  )
836
836
  """
837
837
  input = IPReputationRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
838
- return self.request.post("v1/reputation", IPReputationResult, data=input.dict(exclude_none=True))
838
+ return self.request.post("v1/reputation", IPReputationResult, data=input.model_dump(exclude_none=True))
839
839
 
840
840
  def reputation_bulk(
841
841
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
842
- ) -> PangeaResponse[IPReputationResult]:
842
+ ) -> PangeaResponse[IPReputationBulkResult]:
843
843
  """
844
844
  Reputation V2
845
845
 
@@ -867,7 +867,7 @@ class IpIntel(ServiceBase):
867
867
  )
868
868
  """
869
869
  input = IPReputationBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
870
- return self.request.post("v2/reputation", IPReputationBulkResult, data=input.dict(exclude_none=True))
870
+ return self.request.post("v2/reputation", IPReputationBulkResult, data=input.model_dump(exclude_none=True))
871
871
 
872
872
  def geolocate(
873
873
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -899,7 +899,7 @@ class IpIntel(ServiceBase):
899
899
  )
900
900
  """
901
901
  input = IPGeolocateRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
902
- return self.request.post("v1/geolocate", IPGeolocateResult, data=input.dict(exclude_none=True))
902
+ return self.request.post("v1/geolocate", IPGeolocateResult, data=input.model_dump(exclude_none=True))
903
903
 
904
904
  def geolocate_bulk(
905
905
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -931,7 +931,7 @@ class IpIntel(ServiceBase):
931
931
  )
932
932
  """
933
933
  input = IPGeolocateBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
934
- return self.request.post("v2/geolocate", IPGeolocateBulkResult, data=input.dict(exclude_none=True))
934
+ return self.request.post("v2/geolocate", IPGeolocateBulkResult, data=input.model_dump(exclude_none=True))
935
935
 
936
936
  def get_domain(
937
937
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -963,7 +963,7 @@ class IpIntel(ServiceBase):
963
963
  )
964
964
  """
965
965
  input = IPDomainRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
966
- return self.request.post("v1/domain", IPDomainResult, data=input.dict(exclude_none=True))
966
+ return self.request.post("v1/domain", IPDomainResult, data=input.model_dump(exclude_none=True))
967
967
 
968
968
  def get_domain_bulk(
969
969
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -995,7 +995,7 @@ class IpIntel(ServiceBase):
995
995
  )
996
996
  """
997
997
  input = IPDomainBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
998
- return self.request.post("v2/domain", IPDomainBulkResult, data=input.dict(exclude_none=True))
998
+ return self.request.post("v2/domain", IPDomainBulkResult, data=input.model_dump(exclude_none=True))
999
999
 
1000
1000
  def is_vpn(
1001
1001
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1027,7 +1027,7 @@ class IpIntel(ServiceBase):
1027
1027
  )
1028
1028
  """
1029
1029
  input = IPVPNRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
1030
- return self.request.post("v1/vpn", IPVPNResult, data=input.dict(exclude_none=True))
1030
+ return self.request.post("v1/vpn", IPVPNResult, data=input.model_dump(exclude_none=True))
1031
1031
 
1032
1032
  def is_vpn_bulk(
1033
1033
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1059,7 +1059,7 @@ class IpIntel(ServiceBase):
1059
1059
  )
1060
1060
  """
1061
1061
  input = IPVPNBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1062
- return self.request.post("v2/vpn", IPVPNBulkResult, data=input.dict(exclude_none=True))
1062
+ return self.request.post("v2/vpn", IPVPNBulkResult, data=input.model_dump(exclude_none=True))
1063
1063
 
1064
1064
  def is_proxy(
1065
1065
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1091,7 +1091,7 @@ class IpIntel(ServiceBase):
1091
1091
  )
1092
1092
  """
1093
1093
  input = IPProxyRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
1094
- return self.request.post("v1/proxy", IPProxyResult, data=input.dict(exclude_none=True))
1094
+ return self.request.post("v1/proxy", IPProxyResult, data=input.model_dump(exclude_none=True))
1095
1095
 
1096
1096
  def is_proxy_bulk(
1097
1097
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1123,7 +1123,7 @@ class IpIntel(ServiceBase):
1123
1123
  )
1124
1124
  """
1125
1125
  input = IPProxyBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1126
- return self.request.post("v2/proxy", IPProxyBulkResult, data=input.dict(exclude_none=True))
1126
+ return self.request.post("v2/proxy", IPProxyBulkResult, data=input.model_dump(exclude_none=True))
1127
1127
 
1128
1128
 
1129
1129
  class UrlIntel(ServiceBase):
@@ -1187,7 +1187,7 @@ class UrlIntel(ServiceBase):
1187
1187
  """
1188
1188
 
1189
1189
  input = URLReputationRequest(url=url, provider=provider, verbose=verbose, raw=raw)
1190
- return self.request.post("v1/reputation", URLReputationResult, data=input.dict(exclude_none=True))
1190
+ return self.request.post("v1/reputation", URLReputationResult, data=input.model_dump(exclude_none=True))
1191
1191
 
1192
1192
  def reputation_bulk(
1193
1193
  self,
@@ -1195,7 +1195,7 @@ class UrlIntel(ServiceBase):
1195
1195
  verbose: Optional[bool] = None,
1196
1196
  raw: Optional[bool] = None,
1197
1197
  provider: Optional[str] = None,
1198
- ) -> PangeaResponse[URLReputationResult]:
1198
+ ) -> PangeaResponse[URLReputationBulkResult]:
1199
1199
  """
1200
1200
  Reputation V2
1201
1201
 
@@ -1224,7 +1224,7 @@ class UrlIntel(ServiceBase):
1224
1224
  """
1225
1225
 
1226
1226
  input = URLReputationBulkRequest(urls=urls, provider=provider, verbose=verbose, raw=raw)
1227
- return self.request.post("v2/reputation", URLReputationBulkResult, data=input.dict(exclude_none=True))
1227
+ return self.request.post("v2/reputation", URLReputationBulkResult, data=input.model_dump(exclude_none=True))
1228
1228
 
1229
1229
 
1230
1230
  class UserBreachedRequest(IntelCommonRequest):
@@ -1431,7 +1431,7 @@ class UserIntel(ServiceBase):
1431
1431
  verbose=verbose,
1432
1432
  raw=raw,
1433
1433
  )
1434
- return self.request.post("v1/user/breached", UserBreachedResult, data=input.dict(exclude_none=True))
1434
+ return self.request.post("v1/user/breached", UserBreachedResult, data=input.model_dump(exclude_none=True))
1435
1435
 
1436
1436
  def user_breached_bulk(
1437
1437
  self,
@@ -1490,7 +1490,7 @@ class UserIntel(ServiceBase):
1490
1490
  verbose=verbose,
1491
1491
  raw=raw,
1492
1492
  )
1493
- return self.request.post("v2/user/breached", UserBreachedBulkResult, data=input.dict(exclude_none=True))
1493
+ return self.request.post("v2/user/breached", UserBreachedBulkResult, data=input.model_dump(exclude_none=True))
1494
1494
 
1495
1495
  def password_breached(
1496
1496
  self,
@@ -1532,7 +1532,9 @@ class UserIntel(ServiceBase):
1532
1532
  input = UserPasswordBreachedRequest(
1533
1533
  hash_type=hash_type, hash_prefix=hash_prefix, provider=provider, verbose=verbose, raw=raw
1534
1534
  )
1535
- return self.request.post("v1/password/breached", UserPasswordBreachedResult, data=input.dict(exclude_none=True))
1535
+ return self.request.post(
1536
+ "v1/password/breached", UserPasswordBreachedResult, data=input.model_dump(exclude_none=True)
1537
+ )
1536
1538
 
1537
1539
  def password_breached_bulk(
1538
1540
  self,
@@ -1575,7 +1577,7 @@ class UserIntel(ServiceBase):
1575
1577
  hash_type=hash_type, hash_prefixes=hash_prefixes, provider=provider, verbose=verbose, raw=raw
1576
1578
  )
1577
1579
  return self.request.post(
1578
- "v2/password/breached", UserPasswordBreachedBulkResult, data=input.dict(exclude_none=True)
1580
+ "v2/password/breached", UserPasswordBreachedBulkResult, data=input.model_dump(exclude_none=True)
1579
1581
  )
1580
1582
 
1581
1583
  class PasswordStatus(enum.Enum):