pangea-sdk 3.8.0__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 (51) hide show
  1. pangea/__init__.py +2 -1
  2. pangea/asyncio/__init__.py +1 -0
  3. pangea/asyncio/file_uploader.py +39 -0
  4. pangea/asyncio/request.py +46 -23
  5. pangea/asyncio/services/__init__.py +2 -0
  6. pangea/asyncio/services/audit.py +46 -20
  7. pangea/asyncio/services/authn.py +123 -61
  8. pangea/asyncio/services/authz.py +57 -31
  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 +104 -30
  13. pangea/asyncio/services/redact.py +52 -3
  14. pangea/asyncio/services/sanitize.py +217 -0
  15. pangea/asyncio/services/share.py +733 -0
  16. pangea/asyncio/services/vault.py +1709 -766
  17. pangea/crypto/rsa.py +135 -0
  18. pangea/deep_verify.py +7 -1
  19. pangea/dump_audit.py +9 -8
  20. pangea/file_uploader.py +35 -0
  21. pangea/request.py +70 -49
  22. pangea/response.py +36 -17
  23. pangea/services/__init__.py +2 -0
  24. pangea/services/audit/audit.py +57 -29
  25. pangea/services/audit/models.py +12 -3
  26. pangea/services/audit/signing.py +6 -5
  27. pangea/services/audit/util.py +3 -3
  28. pangea/services/authn/authn.py +120 -66
  29. pangea/services/authn/models.py +167 -11
  30. pangea/services/authz.py +53 -30
  31. pangea/services/base.py +16 -2
  32. pangea/services/embargo.py +2 -2
  33. pangea/services/file_scan.py +32 -15
  34. pangea/services/intel.py +155 -30
  35. pangea/services/redact.py +132 -3
  36. pangea/services/sanitize.py +388 -0
  37. pangea/services/share/file_format.py +170 -0
  38. pangea/services/share/share.py +1440 -0
  39. pangea/services/vault/models/asymmetric.py +120 -18
  40. pangea/services/vault/models/common.py +439 -141
  41. pangea/services/vault/models/keys.py +94 -0
  42. pangea/services/vault/models/secret.py +27 -3
  43. pangea/services/vault/models/symmetric.py +68 -22
  44. pangea/services/vault/vault.py +1690 -766
  45. pangea/tools.py +6 -7
  46. pangea/utils.py +94 -33
  47. pangea/verify_audit.py +270 -83
  48. {pangea_sdk-3.8.0.dist-info → pangea_sdk-5.3.0.dist-info}/METADATA +21 -29
  49. pangea_sdk-5.3.0.dist-info/RECORD +56 -0
  50. {pangea_sdk-3.8.0.dist-info → pangea_sdk-5.3.0.dist-info}/WHEEL +1 -1
  51. pangea_sdk-3.8.0.dist-info/RECORD +0 -46
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,7 +837,7 @@ 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
@@ -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,
@@ -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
 
pangea/services/redact.py CHANGED
@@ -17,6 +17,44 @@ class RedactFormat(str, enum.Enum):
17
17
  """JSON format."""
18
18
 
19
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
+
20
58
  class RedactRequest(APIRequestModel):
21
59
  """
22
60
  Input class to make a redact request
@@ -27,6 +65,18 @@ class RedactRequest(APIRequestModel):
27
65
  rules: Optional[List[str]] = None
28
66
  rulesets: Optional[List[str]] = None
29
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."""
30
80
 
31
81
 
32
82
  class RecognizerResult(APIResponseModel):
@@ -69,11 +119,13 @@ class RedactResult(PangeaResponseResult):
69
119
  redact_text: Redacted text result
70
120
  count: Number of redactions present in the text
71
121
  report: Describes the decision process for redactions
122
+ fpe_context: FPE context used to encrypt and redact data
72
123
  """
73
124
 
74
125
  redacted_text: Optional[str] = None
75
126
  count: int
76
127
  report: Optional[DebugReport] = None
128
+ fpe_context: Optional[str] = None
77
129
 
78
130
 
79
131
  class StructuredRequest(APIRequestModel):
@@ -94,6 +146,10 @@ class StructuredRequest(APIRequestModel):
94
146
  rules: Optional[List[str]] = None
95
147
  rulesets: Optional[List[str]] = None
96
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?"""
97
153
 
98
154
 
99
155
  class StructuredResult(PangeaResponseResult):
@@ -107,6 +163,32 @@ class StructuredResult(PangeaResponseResult):
107
163
  report: Optional[DebugReport] = None
108
164
 
109
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
+
110
192
  class Redact(ServiceBase):
111
193
  """Redact service client.
112
194
 
@@ -161,6 +243,9 @@ class Redact(ServiceBase):
161
243
  rules: Optional[List[str]] = None,
162
244
  rulesets: Optional[List[str]] = None,
163
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,
164
249
  ) -> PangeaResponse[RedactResult]:
165
250
  """
166
251
  Redact
@@ -176,6 +261,9 @@ class Redact(ServiceBase):
176
261
  rules (list[str], optional): An array of redact rule short names
177
262
  rulesets (list[str], optional): An array of redact rulesets short names
178
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
179
267
 
180
268
  Raises:
181
269
  PangeaAPIException: If an API Error happens
@@ -189,8 +277,17 @@ class Redact(ServiceBase):
189
277
  response = redact.redact(text="Jenny Jenny... 555-867-5309")
190
278
  """
191
279
 
192
- input = RedactRequest(text=text, debug=debug, rules=rules, rulesets=rulesets, return_result=return_result)
193
- 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))
194
291
 
195
292
  def redact_structured(
196
293
  self,
@@ -201,6 +298,9 @@ class Redact(ServiceBase):
201
298
  rules: Optional[List[str]] = None,
202
299
  rulesets: Optional[List[str]] = None,
203
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,
204
304
  ) -> PangeaResponse[StructuredResult]:
205
305
  """
206
306
  Redact structured
@@ -220,6 +320,9 @@ class Redact(ServiceBase):
220
320
  rules (list[str], optional): An array of redact rule short names
221
321
  rulesets (list[str], optional): An array of redact rulesets short names
222
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
223
326
 
224
327
  Raises:
225
328
  PangeaAPIException: If an API Error happens
@@ -246,5 +349,31 @@ class Redact(ServiceBase):
246
349
  rules=rules,
247
350
  rulesets=rulesets,
248
351
  return_result=return_result,
352
+ redaction_method_overrides=redaction_method_overrides,
353
+ llm_request=llm_request,
354
+ vault_parameters=vault_parameters,
249
355
  )
250
- 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))