pangea-sdk 3.8.0__py3-none-any.whl → 5.3.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.
- pangea/__init__.py +2 -1
- pangea/asyncio/__init__.py +1 -0
- pangea/asyncio/file_uploader.py +39 -0
- pangea/asyncio/request.py +46 -23
- pangea/asyncio/services/__init__.py +2 -0
- pangea/asyncio/services/audit.py +46 -20
- pangea/asyncio/services/authn.py +123 -61
- pangea/asyncio/services/authz.py +57 -31
- pangea/asyncio/services/base.py +21 -2
- pangea/asyncio/services/embargo.py +2 -2
- pangea/asyncio/services/file_scan.py +24 -9
- pangea/asyncio/services/intel.py +104 -30
- pangea/asyncio/services/redact.py +52 -3
- pangea/asyncio/services/sanitize.py +217 -0
- pangea/asyncio/services/share.py +733 -0
- pangea/asyncio/services/vault.py +1709 -766
- pangea/crypto/rsa.py +135 -0
- pangea/deep_verify.py +7 -1
- pangea/dump_audit.py +9 -8
- pangea/file_uploader.py +35 -0
- pangea/request.py +70 -49
- pangea/response.py +36 -17
- pangea/services/__init__.py +2 -0
- pangea/services/audit/audit.py +57 -29
- pangea/services/audit/models.py +12 -3
- pangea/services/audit/signing.py +6 -5
- pangea/services/audit/util.py +3 -3
- pangea/services/authn/authn.py +120 -66
- pangea/services/authn/models.py +167 -11
- pangea/services/authz.py +53 -30
- pangea/services/base.py +16 -2
- pangea/services/embargo.py +2 -2
- pangea/services/file_scan.py +32 -15
- pangea/services/intel.py +155 -30
- pangea/services/redact.py +132 -3
- pangea/services/sanitize.py +388 -0
- pangea/services/share/file_format.py +170 -0
- pangea/services/share/share.py +1440 -0
- pangea/services/vault/models/asymmetric.py +120 -18
- pangea/services/vault/models/common.py +439 -141
- pangea/services/vault/models/keys.py +94 -0
- pangea/services/vault/models/secret.py +27 -3
- pangea/services/vault/models/symmetric.py +68 -22
- pangea/services/vault/vault.py +1690 -766
- pangea/tools.py +6 -7
- pangea/utils.py +94 -33
- pangea/verify_audit.py +270 -83
- {pangea_sdk-3.8.0.dist-info → pangea_sdk-5.3.0.dist-info}/METADATA +21 -29
- pangea_sdk-5.3.0.dist-info/RECORD +56 -0
- {pangea_sdk-3.8.0.dist-info → pangea_sdk-5.3.0.dist-info}/WHEEL +1 -1
- 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.
|
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.
|
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.
|
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.
|
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.
|
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
|
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.
|
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
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
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.
|
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
|
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.
|
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
|
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
|
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.
|
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
|
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.
|
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
|
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(
|
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
|
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.
|
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(
|
193
|
-
|
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.
|
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))
|