pangea-sdk 3.8.0b1__py3-none-any.whl → 5.3.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. pangea/__init__.py +1 -1
  2. pangea/asyncio/file_uploader.py +1 -1
  3. pangea/asyncio/request.py +49 -31
  4. pangea/asyncio/services/__init__.py +2 -0
  5. pangea/asyncio/services/audit.py +192 -31
  6. pangea/asyncio/services/authn.py +187 -109
  7. pangea/asyncio/services/authz.py +285 -0
  8. pangea/asyncio/services/base.py +21 -2
  9. pangea/asyncio/services/embargo.py +2 -2
  10. pangea/asyncio/services/file_scan.py +24 -9
  11. pangea/asyncio/services/intel.py +108 -34
  12. pangea/asyncio/services/redact.py +72 -4
  13. pangea/asyncio/services/sanitize.py +217 -0
  14. pangea/asyncio/services/share.py +246 -73
  15. pangea/asyncio/services/vault.py +1710 -750
  16. pangea/crypto/rsa.py +135 -0
  17. pangea/deep_verify.py +7 -1
  18. pangea/dump_audit.py +9 -8
  19. pangea/request.py +83 -59
  20. pangea/response.py +49 -31
  21. pangea/services/__init__.py +2 -0
  22. pangea/services/audit/audit.py +205 -42
  23. pangea/services/audit/models.py +56 -8
  24. pangea/services/audit/signing.py +6 -5
  25. pangea/services/audit/util.py +3 -3
  26. pangea/services/authn/authn.py +140 -70
  27. pangea/services/authn/models.py +167 -11
  28. pangea/services/authz.py +400 -0
  29. pangea/services/base.py +39 -8
  30. pangea/services/embargo.py +2 -2
  31. pangea/services/file_scan.py +32 -15
  32. pangea/services/intel.py +157 -32
  33. pangea/services/redact.py +152 -4
  34. pangea/services/sanitize.py +388 -0
  35. pangea/services/share/share.py +683 -107
  36. pangea/services/vault/models/asymmetric.py +120 -18
  37. pangea/services/vault/models/common.py +439 -141
  38. pangea/services/vault/models/keys.py +94 -0
  39. pangea/services/vault/models/secret.py +27 -3
  40. pangea/services/vault/models/symmetric.py +68 -22
  41. pangea/services/vault/vault.py +1690 -749
  42. pangea/tools.py +6 -7
  43. pangea/utils.py +16 -27
  44. pangea/verify_audit.py +270 -83
  45. {pangea_sdk-3.8.0b1.dist-info → pangea_sdk-5.3.0.dist-info}/METADATA +43 -35
  46. pangea_sdk-5.3.0.dist-info/RECORD +56 -0
  47. {pangea_sdk-3.8.0b1.dist-info → pangea_sdk-5.3.0.dist-info}/WHEEL +1 -1
  48. pangea_sdk-3.8.0b1.dist-info/RECORD +0 -50
pangea/services/intel.py CHANGED
@@ -1,5 +1,7 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
+ from __future__ import annotations
4
+
3
5
  import enum
4
6
  import hashlib
5
7
  from typing import Dict, List, Optional
@@ -524,7 +526,7 @@ class FileIntel(ServiceBase):
524
526
  )
525
527
  """
526
528
  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))
529
+ return self.request.post("v1/reputation", FileReputationResult, data=input.model_dump(exclude_none=True))
528
530
 
529
531
  def hash_reputation_bulk(
530
532
  self,
@@ -563,7 +565,7 @@ class FileIntel(ServiceBase):
563
565
  input = FileReputationBulkRequest( # type: ignore[call-arg]
564
566
  hashes=hashes, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider
565
567
  )
566
- return self.request.post("v2/reputation", FileReputationBulkResult, data=input.dict(exclude_none=True))
568
+ return self.request.post("v2/reputation", FileReputationBulkResult, data=input.model_dump(exclude_none=True))
567
569
 
568
570
  def filepath_reputation(
569
571
  self,
@@ -708,7 +710,7 @@ class DomainIntel(ServiceBase):
708
710
  )
709
711
  """
710
712
  input = DomainReputationRequest(domain=domain, verbose=verbose, provider=provider, raw=raw)
711
- return self.request.post("v1/reputation", DomainReputationResult, data=input.dict(exclude_none=True))
713
+ return self.request.post("v1/reputation", DomainReputationResult, data=input.model_dump(exclude_none=True))
712
714
 
713
715
  def reputation_bulk(
714
716
  self,
@@ -744,7 +746,7 @@ class DomainIntel(ServiceBase):
744
746
  )
745
747
  """
746
748
  input = DomainReputationBulkRequest(domains=domains, verbose=verbose, provider=provider, raw=raw)
747
- return self.request.post("v2/reputation", DomainReputationBulkResult, data=input.dict(exclude_none=True))
749
+ return self.request.post("v2/reputation", DomainReputationBulkResult, data=input.model_dump(exclude_none=True))
748
750
 
749
751
  def who_is(
750
752
  self, domain: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -776,7 +778,7 @@ class DomainIntel(ServiceBase):
776
778
  )
777
779
  """
778
780
  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))
781
+ return self.request.post("v1/whois", DomainWhoIsResult, data=input.model_dump(exclude_none=True))
780
782
 
781
783
 
782
784
  class IpIntel(ServiceBase):
@@ -819,7 +821,7 @@ class IpIntel(ServiceBase):
819
821
  ip (str): The IP to be looked up
820
822
  verbose (bool, optional): Echo the API parameters in the response
821
823
  raw (bool, optional): Include raw data from this provider
822
- provider (str, optional): Use reputation data from this provider: "crowdstrike"
824
+ provider (str, optional): Use reputation data from this provider
823
825
 
824
826
  Raises:
825
827
  PangeaAPIException: If an API Error happens
@@ -835,11 +837,11 @@ class IpIntel(ServiceBase):
835
837
  )
836
838
  """
837
839
  input = IPReputationRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
838
- return self.request.post("v1/reputation", IPReputationResult, data=input.dict(exclude_none=True))
840
+ return self.request.post("v1/reputation", IPReputationResult, data=input.model_dump(exclude_none=True))
839
841
 
840
842
  def reputation_bulk(
841
843
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
842
- ) -> PangeaResponse[IPReputationResult]:
844
+ ) -> PangeaResponse[IPReputationBulkResult]:
843
845
  """
844
846
  Reputation V2
845
847
 
@@ -851,7 +853,7 @@ class IpIntel(ServiceBase):
851
853
  ips (List[str]): The IP list to be looked up
852
854
  verbose (bool, optional): Echo the API parameters in the response
853
855
  raw (bool, optional): Include raw data from this provider
854
- provider (str, optional): Use reputation data from this provider: "crowdstrike"
856
+ provider (str, optional): Use reputation data from this provider
855
857
 
856
858
  Raises:
857
859
  PangeaAPIException: If an API Error happens
@@ -867,7 +869,7 @@ class IpIntel(ServiceBase):
867
869
  )
868
870
  """
869
871
  input = IPReputationBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
870
- return self.request.post("v2/reputation", IPReputationBulkResult, data=input.dict(exclude_none=True))
872
+ return self.request.post("v2/reputation", IPReputationBulkResult, data=input.model_dump(exclude_none=True))
871
873
 
872
874
  def geolocate(
873
875
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -899,7 +901,7 @@ class IpIntel(ServiceBase):
899
901
  )
900
902
  """
901
903
  input = IPGeolocateRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
902
- return self.request.post("v1/geolocate", IPGeolocateResult, data=input.dict(exclude_none=True))
904
+ return self.request.post("v1/geolocate", IPGeolocateResult, data=input.model_dump(exclude_none=True))
903
905
 
904
906
  def geolocate_bulk(
905
907
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -931,7 +933,7 @@ class IpIntel(ServiceBase):
931
933
  )
932
934
  """
933
935
  input = IPGeolocateBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
934
- return self.request.post("v2/geolocate", IPGeolocateBulkResult, data=input.dict(exclude_none=True))
936
+ return self.request.post("v2/geolocate", IPGeolocateBulkResult, data=input.model_dump(exclude_none=True))
935
937
 
936
938
  def get_domain(
937
939
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -963,7 +965,7 @@ class IpIntel(ServiceBase):
963
965
  )
964
966
  """
965
967
  input = IPDomainRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
966
- return self.request.post("v1/domain", IPDomainResult, data=input.dict(exclude_none=True))
968
+ return self.request.post("v1/domain", IPDomainResult, data=input.model_dump(exclude_none=True))
967
969
 
968
970
  def get_domain_bulk(
969
971
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -995,7 +997,7 @@ class IpIntel(ServiceBase):
995
997
  )
996
998
  """
997
999
  input = IPDomainBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
998
- return self.request.post("v2/domain", IPDomainBulkResult, data=input.dict(exclude_none=True))
1000
+ return self.request.post("v2/domain", IPDomainBulkResult, data=input.model_dump(exclude_none=True))
999
1001
 
1000
1002
  def is_vpn(
1001
1003
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1027,7 +1029,7 @@ class IpIntel(ServiceBase):
1027
1029
  )
1028
1030
  """
1029
1031
  input = IPVPNRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
1030
- return self.request.post("v1/vpn", IPVPNResult, data=input.dict(exclude_none=True))
1032
+ return self.request.post("v1/vpn", IPVPNResult, data=input.model_dump(exclude_none=True))
1031
1033
 
1032
1034
  def is_vpn_bulk(
1033
1035
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1059,7 +1061,7 @@ class IpIntel(ServiceBase):
1059
1061
  )
1060
1062
  """
1061
1063
  input = IPVPNBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1062
- return self.request.post("v2/vpn", IPVPNBulkResult, data=input.dict(exclude_none=True))
1064
+ return self.request.post("v2/vpn", IPVPNBulkResult, data=input.model_dump(exclude_none=True))
1063
1065
 
1064
1066
  def is_proxy(
1065
1067
  self, ip: str, verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1091,7 +1093,7 @@ class IpIntel(ServiceBase):
1091
1093
  )
1092
1094
  """
1093
1095
  input = IPProxyRequest(ip=ip, verbose=verbose, raw=raw, provider=provider)
1094
- return self.request.post("v1/proxy", IPProxyResult, data=input.dict(exclude_none=True))
1096
+ return self.request.post("v1/proxy", IPProxyResult, data=input.model_dump(exclude_none=True))
1095
1097
 
1096
1098
  def is_proxy_bulk(
1097
1099
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
@@ -1123,7 +1125,7 @@ class IpIntel(ServiceBase):
1123
1125
  )
1124
1126
  """
1125
1127
  input = IPProxyBulkRequest(ips=ips, verbose=verbose, raw=raw, provider=provider)
1126
- return self.request.post("v2/proxy", IPProxyBulkResult, data=input.dict(exclude_none=True))
1128
+ return self.request.post("v2/proxy", IPProxyBulkResult, data=input.model_dump(exclude_none=True))
1127
1129
 
1128
1130
 
1129
1131
  class UrlIntel(ServiceBase):
@@ -1170,7 +1172,7 @@ class UrlIntel(ServiceBase):
1170
1172
  url (str): The URL to be looked up
1171
1173
  verbose (bool, optional): Echo the API parameters in the response
1172
1174
  raw (bool, optional): Include raw data from this provider
1173
- provider (str, optional): Use reputation data from this provider: "crowdstrike"
1175
+ provider (str, optional): Use reputation data from this provider
1174
1176
 
1175
1177
  Raises:
1176
1178
  PangeaAPIException: If an API Error happens
@@ -1187,7 +1189,7 @@ class UrlIntel(ServiceBase):
1187
1189
  """
1188
1190
 
1189
1191
  input = URLReputationRequest(url=url, provider=provider, verbose=verbose, raw=raw)
1190
- return self.request.post("v1/reputation", URLReputationResult, data=input.dict(exclude_none=True))
1192
+ return self.request.post("v1/reputation", URLReputationResult, data=input.model_dump(exclude_none=True))
1191
1193
 
1192
1194
  def reputation_bulk(
1193
1195
  self,
@@ -1195,7 +1197,7 @@ class UrlIntel(ServiceBase):
1195
1197
  verbose: Optional[bool] = None,
1196
1198
  raw: Optional[bool] = None,
1197
1199
  provider: Optional[str] = None,
1198
- ) -> PangeaResponse[URLReputationResult]:
1200
+ ) -> PangeaResponse[URLReputationBulkResult]:
1199
1201
  """
1200
1202
  Reputation V2
1201
1203
 
@@ -1207,7 +1209,7 @@ class UrlIntel(ServiceBase):
1207
1209
  urls (List[str]): The URL list to be looked up
1208
1210
  verbose (bool, optional): Echo the API parameters in the response
1209
1211
  raw (bool, optional): Include raw data from this provider
1210
- provider (str, optional): Use reputation data from this provider: "crowdstrike"
1212
+ provider (str, optional): Use reputation data from this provider
1211
1213
 
1212
1214
  Raises:
1213
1215
  PangeaAPIException: If an API Error happens
@@ -1224,7 +1226,7 @@ class UrlIntel(ServiceBase):
1224
1226
  """
1225
1227
 
1226
1228
  input = URLReputationBulkRequest(urls=urls, provider=provider, verbose=verbose, raw=raw)
1227
- return self.request.post("v2/reputation", URLReputationBulkResult, data=input.dict(exclude_none=True))
1229
+ return self.request.post("v2/reputation", URLReputationBulkResult, data=input.model_dump(exclude_none=True))
1228
1230
 
1229
1231
 
1230
1232
  class UserBreachedRequest(IntelCommonRequest):
@@ -1237,6 +1239,7 @@ class UserBreachedRequest(IntelCommonRequest):
1237
1239
  phone_number (str): A phone number to search for. minLength: 7, maxLength: 15.
1238
1240
  start (str): Earliest date for search
1239
1241
  end (str): Latest date for search
1242
+ cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
1240
1243
  """
1241
1244
 
1242
1245
  email: Optional[str] = None
@@ -1245,6 +1248,10 @@ class UserBreachedRequest(IntelCommonRequest):
1245
1248
  phone_number: Optional[str] = None
1246
1249
  start: Optional[str] = None
1247
1250
  end: Optional[str] = None
1251
+ cursor: Optional[str] = None
1252
+
1253
+ severity: Optional[List[int]] = None
1254
+ """Filter for records that match one of the given severities"""
1248
1255
 
1249
1256
 
1250
1257
  class UserBreachedBulkRequest(IntelCommonRequest):
@@ -1255,6 +1262,7 @@ class UserBreachedBulkRequest(IntelCommonRequest):
1255
1262
  usernames (List[str]): An username' list to search for
1256
1263
  ips (List[str]): An ip's list to search for
1257
1264
  phone_numbers (List[str]): A phone number's list to search for. minLength: 7, maxLength: 15.
1265
+ domains (List[str]): Search for user under these domains.
1258
1266
  start (str): Earliest date for search
1259
1267
  end (str): Latest date for search
1260
1268
  """
@@ -1263,9 +1271,13 @@ class UserBreachedBulkRequest(IntelCommonRequest):
1263
1271
  usernames: Optional[List[str]] = None
1264
1272
  ips: Optional[List[str]] = None
1265
1273
  phone_numbers: Optional[List[str]] = None
1274
+ domains: Optional[List[str]] = None
1266
1275
  start: Optional[str] = None
1267
1276
  end: Optional[str] = None
1268
1277
 
1278
+ severity: Optional[List[int]] = None
1279
+ """Filter for records that match one of the given severities"""
1280
+
1269
1281
 
1270
1282
  class UserBreachedCommonData(PangeaResponseResult):
1271
1283
  """
@@ -1314,7 +1326,7 @@ class UserPasswordBreachedRequest(IntelCommonRequest):
1314
1326
 
1315
1327
  class UserPasswordBreachedBulkRequest(IntelCommonRequest):
1316
1328
  """
1317
- User password breached common request data
1329
+ User password breached bulk request data
1318
1330
 
1319
1331
  hash_type (str): Hash type to be looked up
1320
1332
  hash_prefixes (List[str]): The list of prefixes of the hashes to be looked up.
@@ -1348,6 +1360,44 @@ class UserPasswordBreachedBulkResult(IntelCommonResult):
1348
1360
  data: Dict[str, UserPasswordBreachedData]
1349
1361
 
1350
1362
 
1363
+ class BreachRequest(APIRequestModel):
1364
+ """Breach request data"""
1365
+
1366
+ breach_id: Optional[str] = None
1367
+ """The ID of a breach returned by a provider."""
1368
+
1369
+ verbose: Optional[bool] = None
1370
+ """Echo back the parameters of the API in the response."""
1371
+
1372
+ provider: Optional[str] = None
1373
+ """Provider of the information. Default provider defined by the configuration."""
1374
+
1375
+ severity: Optional[List[int]] = None
1376
+ """Filter for records that match one of the given severities"""
1377
+
1378
+ start: Optional[str] = None
1379
+ """This parameter allows you to define the starting point for a date range query on the spycloud_publish_date field."""
1380
+
1381
+ end: Optional[str] = None
1382
+ """This parameter allows you to define the ending point for a date range query on the spycloud_publish_date field."""
1383
+
1384
+ cursor: Optional[str] = None
1385
+ """A token given in the raw response from SpyCloud. Post this back to paginate results"""
1386
+
1387
+
1388
+ class BreachResult(PangeaResponseResult):
1389
+ """Breach result"""
1390
+
1391
+ found: bool
1392
+ """A flag indicating if the lookup was successful."""
1393
+
1394
+ data: Optional[Dict] = None
1395
+ """Breach details given by the provider."""
1396
+
1397
+ parameters: Optional[Dict] = None
1398
+ """The parameters, which were passed in the request, echoed back."""
1399
+
1400
+
1351
1401
  class UserIntel(ServiceBase):
1352
1402
  """User Intel service client.
1353
1403
 
@@ -1385,6 +1435,8 @@ class UserIntel(ServiceBase):
1385
1435
  verbose: Optional[bool] = None,
1386
1436
  raw: Optional[bool] = None,
1387
1437
  provider: Optional[str] = None,
1438
+ cursor: Optional[str] = None,
1439
+ severity: Optional[List[int]] = None,
1388
1440
  ) -> PangeaResponse[UserBreachedResult]:
1389
1441
  """
1390
1442
  Look up breached users
@@ -1402,7 +1454,9 @@ class UserIntel(ServiceBase):
1402
1454
  end (str): Latest date for search
1403
1455
  verbose (bool, optional): Echo the API parameters in the response
1404
1456
  raw (bool, optional): Include raw data from this provider
1405
- provider (str, optional): Use reputation data from this provider: "spycloud"
1457
+ provider (str, optional): Use reputation data from this provider
1458
+ cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
1459
+ severity (List[int], optional): Filter for records that match one of the given severities
1406
1460
 
1407
1461
  Raises:
1408
1462
  PangeaAPIException: If an API Error happens
@@ -1430,8 +1484,10 @@ class UserIntel(ServiceBase):
1430
1484
  end=end,
1431
1485
  verbose=verbose,
1432
1486
  raw=raw,
1487
+ cursor=cursor,
1488
+ severity=severity,
1433
1489
  )
1434
- return self.request.post("v1/user/breached", UserBreachedResult, data=input.dict(exclude_none=True))
1490
+ return self.request.post("v1/user/breached", UserBreachedResult, data=input.model_dump(exclude_none=True))
1435
1491
 
1436
1492
  def user_breached_bulk(
1437
1493
  self,
@@ -1439,11 +1495,13 @@ class UserIntel(ServiceBase):
1439
1495
  usernames: Optional[List[str]] = None,
1440
1496
  ips: Optional[List[str]] = None,
1441
1497
  phone_numbers: Optional[List[str]] = None,
1498
+ domains: Optional[List[str]] = None,
1442
1499
  start: Optional[str] = None,
1443
1500
  end: Optional[str] = None,
1444
1501
  verbose: Optional[bool] = None,
1445
1502
  raw: Optional[bool] = None,
1446
1503
  provider: Optional[str] = None,
1504
+ severity: Optional[List[int]] = None,
1447
1505
  ) -> PangeaResponse[UserBreachedBulkResult]:
1448
1506
  """
1449
1507
  Look up breached users V2
@@ -1457,11 +1515,13 @@ class UserIntel(ServiceBase):
1457
1515
  usernames (List[str]): A list of usernames to search for
1458
1516
  ips (List[str]): A list of ips to search for
1459
1517
  phone_numbers (List[str]): A list of phone numbers to search for. minLength: 7, maxLength: 15.
1518
+ domains (List[str]): Search for user under these domains.
1460
1519
  start (str): Earliest date for search
1461
1520
  end (str): Latest date for search
1462
1521
  verbose (bool, optional): Echo the API parameters in the response
1463
1522
  raw (bool, optional): Include raw data from this provider
1464
- provider (str, optional): Use reputation data from this provider: "spycloud"
1523
+ provider (str, optional): Use reputation data from this provider
1524
+ severity (List[int], optional): Filter for records that match one of the given severities
1465
1525
 
1466
1526
  Raises:
1467
1527
  PangeaAPIException: If an API Error happens
@@ -1484,13 +1544,15 @@ class UserIntel(ServiceBase):
1484
1544
  phone_numbers=phone_numbers,
1485
1545
  usernames=usernames,
1486
1546
  ips=ips,
1547
+ domains=domains,
1487
1548
  provider=provider,
1488
1549
  start=start,
1489
1550
  end=end,
1490
1551
  verbose=verbose,
1491
1552
  raw=raw,
1553
+ severity=severity,
1492
1554
  )
1493
- return self.request.post("v2/user/breached", UserBreachedBulkResult, data=input.dict(exclude_none=True))
1555
+ return self.request.post("v2/user/breached", UserBreachedBulkResult, data=input.model_dump(exclude_none=True))
1494
1556
 
1495
1557
  def password_breached(
1496
1558
  self,
@@ -1512,7 +1574,7 @@ class UserIntel(ServiceBase):
1512
1574
  hash_prefix (str): The prefix of the hash to be looked up.
1513
1575
  verbose (bool, optional): Echo the API parameters in the response
1514
1576
  raw (bool, optional): Include raw data from this provider
1515
- provider (str, optional): Use reputation data from this provider: "crowdstrike"
1577
+ provider (str, optional): Use reputation data from this provider
1516
1578
 
1517
1579
  Raises:
1518
1580
  PangeaAPIException: If an API Error happens
@@ -1532,7 +1594,9 @@ class UserIntel(ServiceBase):
1532
1594
  input = UserPasswordBreachedRequest(
1533
1595
  hash_type=hash_type, hash_prefix=hash_prefix, provider=provider, verbose=verbose, raw=raw
1534
1596
  )
1535
- return self.request.post("v1/password/breached", UserPasswordBreachedResult, data=input.dict(exclude_none=True))
1597
+ return self.request.post(
1598
+ "v1/password/breached", UserPasswordBreachedResult, data=input.model_dump(exclude_none=True)
1599
+ )
1536
1600
 
1537
1601
  def password_breached_bulk(
1538
1602
  self,
@@ -1554,7 +1618,7 @@ class UserIntel(ServiceBase):
1554
1618
  hash_prefixes (List[str]): The list of prefixes of the hashes to be looked up.
1555
1619
  verbose (bool, optional): Echo the API parameters in the response
1556
1620
  raw (bool, optional): Include raw data from this provider
1557
- provider (str, optional): Use reputation data from this provider: "crowdstrike"
1621
+ provider (str, optional): Use reputation data from this provider
1558
1622
 
1559
1623
  Raises:
1560
1624
  PangeaAPIException: If an API Error happens
@@ -1575,9 +1639,59 @@ class UserIntel(ServiceBase):
1575
1639
  hash_type=hash_type, hash_prefixes=hash_prefixes, provider=provider, verbose=verbose, raw=raw
1576
1640
  )
1577
1641
  return self.request.post(
1578
- "v2/password/breached", UserPasswordBreachedBulkResult, data=input.dict(exclude_none=True)
1642
+ "v2/password/breached", UserPasswordBreachedBulkResult, data=input.model_dump(exclude_none=True)
1579
1643
  )
1580
1644
 
1645
+ def breach(
1646
+ self,
1647
+ breach_id: Optional[str] = None,
1648
+ verbose: Optional[bool] = None,
1649
+ provider: Optional[str] = None,
1650
+ cursor: Optional[str] = None,
1651
+ start: Optional[str] = None,
1652
+ end: Optional[str] = None,
1653
+ severity: Optional[List[int]] = None,
1654
+ ) -> PangeaResponse[BreachResult]:
1655
+ """
1656
+ Look up information about a specific breach
1657
+
1658
+ Given a provider specific breach ID, find details about the breach.
1659
+
1660
+ OperationId: user_intel_post_v1_breach
1661
+
1662
+ Args:
1663
+ breach_id (str, optional): The ID of a breach returned by a provider
1664
+ verbose (bool, optional): Echo the API parameters in the response
1665
+ provider (str, optional): Use reputation data from this provider
1666
+ cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
1667
+ start (str, optional): This parameter allows you to define the starting point for a date range query on the spycloud_publish_date field
1668
+ end (str, optional): This parameter allows you to define the ending point for a date range query on the spycloud_publish_date field
1669
+ severity (List[int], optional): Filter for records that match one of the given severities
1670
+
1671
+ Raises:
1672
+ PangeaAPIException: If an API Error happens
1673
+
1674
+ Returns:
1675
+ A PangeaResponse where the breach details are in the
1676
+ response.result field. Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/user-intel)
1677
+
1678
+ Examples:
1679
+ response = user_intel.breach(
1680
+ breach_id="66111",
1681
+ )
1682
+ """
1683
+
1684
+ input = BreachRequest(
1685
+ breach_id=breach_id,
1686
+ provider=provider,
1687
+ verbose=verbose,
1688
+ cursor=cursor,
1689
+ start=start,
1690
+ end=end,
1691
+ severity=severity,
1692
+ )
1693
+ return self.request.post("v1/breach", BreachResult, data=input.model_dump(exclude_none=True))
1694
+
1581
1695
  class PasswordStatus(enum.Enum):
1582
1696
  BREACHED = 0
1583
1697
  UNBREACHED = 1
@@ -1585,6 +1699,17 @@ class UserIntel(ServiceBase):
1585
1699
 
1586
1700
  @staticmethod
1587
1701
  def is_password_breached(response: PangeaResponse[UserBreachedResult], hash: str) -> PasswordStatus:
1702
+ """
1703
+ Check if a password was breached
1704
+
1705
+ Helper function that simplifies searching the response's raw data for
1706
+ the full hash.
1707
+
1708
+ Args:
1709
+ response: API response from an earlier request
1710
+ hash: Password hash
1711
+ """
1712
+
1588
1713
  if response.result.raw_data is None: # type: ignore[union-attr]
1589
1714
  raise PangeaException("Need raw data to check if hash is breached. Send request with raw=true")
1590
1715