pangea-sdk 3.8.0b4__py3-none-any.whl → 4.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pangea/__init__.py +1 -2
- pangea/asyncio/request.py +17 -22
- pangea/asyncio/services/__init__.py +0 -2
- pangea/asyncio/services/audit.py +188 -23
- pangea/asyncio/services/authn.py +167 -108
- pangea/asyncio/services/authz.py +36 -45
- pangea/asyncio/services/embargo.py +2 -2
- pangea/asyncio/services/file_scan.py +3 -3
- pangea/asyncio/services/intel.py +44 -26
- pangea/asyncio/services/redact.py +60 -4
- pangea/asyncio/services/vault.py +145 -30
- pangea/dump_audit.py +1 -1
- pangea/request.py +30 -24
- pangea/response.py +34 -42
- pangea/services/__init__.py +0 -2
- pangea/services/audit/audit.py +202 -34
- pangea/services/audit/models.py +56 -8
- pangea/services/audit/util.py +3 -3
- pangea/services/authn/authn.py +116 -65
- pangea/services/authn/models.py +88 -4
- pangea/services/authz.py +51 -56
- pangea/services/base.py +23 -6
- pangea/services/embargo.py +2 -2
- pangea/services/file_scan.py +3 -2
- pangea/services/intel.py +25 -23
- pangea/services/redact.py +124 -4
- pangea/services/vault/models/common.py +121 -6
- pangea/services/vault/models/symmetric.py +2 -2
- pangea/services/vault/vault.py +143 -32
- pangea/utils.py +20 -109
- pangea/verify_audit.py +267 -83
- {pangea_sdk-3.8.0b4.dist-info → pangea_sdk-4.0.0.dist-info}/METADATA +12 -20
- pangea_sdk-4.0.0.dist-info/RECORD +46 -0
- {pangea_sdk-3.8.0b4.dist-info → pangea_sdk-4.0.0.dist-info}/WHEEL +1 -1
- pangea/asyncio/__init__.py +0 -1
- pangea/asyncio/file_uploader.py +0 -39
- pangea/asyncio/services/sanitize.py +0 -185
- pangea/asyncio/services/share.py +0 -573
- pangea/file_uploader.py +0 -35
- pangea/services/sanitize.py +0 -275
- pangea/services/share/file_format.py +0 -170
- pangea/services/share/share.py +0 -877
- pangea_sdk-3.8.0b4.dist-info/RECORD +0 -54
pangea/services/vault/vault.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
from __future__ import annotations
|
4
|
+
|
3
5
|
import datetime
|
4
6
|
from typing import Dict, Optional, Union
|
5
7
|
|
8
|
+
from pangea.config import PangeaConfig
|
6
9
|
from pangea.response import PangeaResponse
|
7
10
|
from pangea.services.base import ServiceBase
|
8
11
|
from pangea.services.vault.models.asymmetric import (
|
@@ -17,6 +20,8 @@ from pangea.services.vault.models.asymmetric import (
|
|
17
20
|
)
|
18
21
|
from pangea.services.vault.models.common import (
|
19
22
|
AsymmetricAlgorithm,
|
23
|
+
DecryptTransformRequest,
|
24
|
+
DecryptTransformResult,
|
20
25
|
DeleteRequest,
|
21
26
|
DeleteResult,
|
22
27
|
EncodedPrivateKey,
|
@@ -24,6 +29,8 @@ from pangea.services.vault.models.common import (
|
|
24
29
|
EncodedSymmetricKey,
|
25
30
|
EncryptStructuredRequest,
|
26
31
|
EncryptStructuredResult,
|
32
|
+
EncryptTransformRequest,
|
33
|
+
EncryptTransformResult,
|
27
34
|
FolderCreateRequest,
|
28
35
|
FolderCreateResult,
|
29
36
|
GetRequest,
|
@@ -50,6 +57,7 @@ from pangea.services.vault.models.common import (
|
|
50
57
|
SymmetricAlgorithm,
|
51
58
|
Tags,
|
52
59
|
TDict,
|
60
|
+
TransformAlphabet,
|
53
61
|
UpdateRequest,
|
54
62
|
UpdateResult,
|
55
63
|
)
|
@@ -98,10 +106,24 @@ class Vault(ServiceBase):
|
|
98
106
|
|
99
107
|
def __init__(
|
100
108
|
self,
|
101
|
-
token,
|
102
|
-
config=None,
|
103
|
-
logger_name="pangea",
|
104
|
-
):
|
109
|
+
token: str,
|
110
|
+
config: PangeaConfig | None = None,
|
111
|
+
logger_name: str = "pangea",
|
112
|
+
) -> None:
|
113
|
+
"""
|
114
|
+
Vault client
|
115
|
+
|
116
|
+
Initializes a new Vault client.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
token: Pangea API token.
|
120
|
+
config: Configuration.
|
121
|
+
logger_name: Logger name.
|
122
|
+
|
123
|
+
Examples:
|
124
|
+
config = PangeaConfig(domain="pangea_domain")
|
125
|
+
vault = Vault(token="pangea_token", config=config)
|
126
|
+
"""
|
105
127
|
super().__init__(token, config, logger_name)
|
106
128
|
|
107
129
|
# Delete endpoint
|
@@ -129,7 +151,7 @@ class Vault(ServiceBase):
|
|
129
151
|
input = DeleteRequest(
|
130
152
|
id=id,
|
131
153
|
)
|
132
|
-
return self.request.post("v1/delete", DeleteResult, data=input.
|
154
|
+
return self.request.post("v1/delete", DeleteResult, data=input.model_dump(exclude_none=True))
|
133
155
|
|
134
156
|
# Get endpoint
|
135
157
|
def get(
|
@@ -176,7 +198,7 @@ class Vault(ServiceBase):
|
|
176
198
|
verbose=verbose,
|
177
199
|
version_state=version_state,
|
178
200
|
)
|
179
|
-
return self.request.post("v1/get", GetResult, data=input.
|
201
|
+
return self.request.post("v1/get", GetResult, data=input.model_dump(exclude_none=True))
|
180
202
|
|
181
203
|
# List endpoint
|
182
204
|
def list(
|
@@ -232,7 +254,7 @@ class Vault(ServiceBase):
|
|
232
254
|
)
|
233
255
|
"""
|
234
256
|
input = ListRequest(filter=filter, last=last, order=order, order_by=order_by, size=size)
|
235
|
-
return self.request.post("v1/list", ListResult, data=input.
|
257
|
+
return self.request.post("v1/list", ListResult, data=input.model_dump(exclude_none=True))
|
236
258
|
|
237
259
|
# Update endpoint
|
238
260
|
def update(
|
@@ -313,7 +335,7 @@ class Vault(ServiceBase):
|
|
313
335
|
expiration=expiration,
|
314
336
|
item_state=item_state,
|
315
337
|
)
|
316
|
-
return self.request.post("v1/update", UpdateResult, data=input.
|
338
|
+
return self.request.post("v1/update", UpdateResult, data=input.model_dump(exclude_none=True))
|
317
339
|
|
318
340
|
def secret_store(
|
319
341
|
self,
|
@@ -383,7 +405,7 @@ class Vault(ServiceBase):
|
|
383
405
|
rotation_state=rotation_state,
|
384
406
|
expiration=expiration,
|
385
407
|
)
|
386
|
-
return self.request.post("v1/secret/store", SecretStoreResult, data=input.
|
408
|
+
return self.request.post("v1/secret/store", SecretStoreResult, data=input.model_dump(exclude_none=True))
|
387
409
|
|
388
410
|
def pangea_token_store(
|
389
411
|
self,
|
@@ -453,7 +475,7 @@ class Vault(ServiceBase):
|
|
453
475
|
rotation_state=rotation_state,
|
454
476
|
expiration=expiration,
|
455
477
|
)
|
456
|
-
return self.request.post("v1/secret/store", SecretStoreResult, data=input.
|
478
|
+
return self.request.post("v1/secret/store", SecretStoreResult, data=input.model_dump(exclude_none=True))
|
457
479
|
|
458
480
|
# Rotate endpoint
|
459
481
|
def secret_rotate(
|
@@ -493,7 +515,7 @@ class Vault(ServiceBase):
|
|
493
515
|
)
|
494
516
|
"""
|
495
517
|
input = SecretRotateRequest(id=id, secret=secret, rotation_state=rotation_state)
|
496
|
-
return self.request.post("v1/secret/rotate", SecretRotateResult, data=input.
|
518
|
+
return self.request.post("v1/secret/rotate", SecretRotateResult, data=input.model_dump(exclude_none=True))
|
497
519
|
|
498
520
|
# Rotate endpoint
|
499
521
|
def pangea_token_rotate(self, id: str) -> PangeaResponse[SecretRotateResult]:
|
@@ -521,7 +543,7 @@ class Vault(ServiceBase):
|
|
521
543
|
)
|
522
544
|
"""
|
523
545
|
input = SecretRotateRequest(id=id) # type: ignore[call-arg]
|
524
|
-
return self.request.post("v1/secret/rotate", SecretRotateResult, data=input.
|
546
|
+
return self.request.post("v1/secret/rotate", SecretRotateResult, data=input.model_dump(exclude_none=True))
|
525
547
|
|
526
548
|
def symmetric_generate(
|
527
549
|
self,
|
@@ -598,7 +620,7 @@ class Vault(ServiceBase):
|
|
598
620
|
return self.request.post(
|
599
621
|
"v1/key/generate",
|
600
622
|
SymmetricGenerateResult,
|
601
|
-
data=input.
|
623
|
+
data=input.model_dump(exclude_none=True),
|
602
624
|
)
|
603
625
|
|
604
626
|
def asymmetric_generate(
|
@@ -676,7 +698,7 @@ class Vault(ServiceBase):
|
|
676
698
|
return self.request.post(
|
677
699
|
"v1/key/generate",
|
678
700
|
AsymmetricGenerateResult,
|
679
|
-
data=input.
|
701
|
+
data=input.model_dump(exclude_none=True),
|
680
702
|
)
|
681
703
|
|
682
704
|
# Store endpoints
|
@@ -760,7 +782,7 @@ class Vault(ServiceBase):
|
|
760
782
|
rotation_state=rotation_state,
|
761
783
|
expiration=expiration,
|
762
784
|
)
|
763
|
-
return self.request.post("v1/key/store", AsymmetricStoreResult, data=input.
|
785
|
+
return self.request.post("v1/key/store", AsymmetricStoreResult, data=input.model_dump(exclude_none=True))
|
764
786
|
|
765
787
|
def symmetric_store(
|
766
788
|
self,
|
@@ -838,7 +860,7 @@ class Vault(ServiceBase):
|
|
838
860
|
rotation_state=rotation_state,
|
839
861
|
expiration=expiration,
|
840
862
|
)
|
841
|
-
return self.request.post("v1/key/store", SymmetricStoreResult, data=input.
|
863
|
+
return self.request.post("v1/key/store", SymmetricStoreResult, data=input.model_dump(exclude_none=True))
|
842
864
|
|
843
865
|
# Rotate endpoint
|
844
866
|
def key_rotate(
|
@@ -891,7 +913,7 @@ class Vault(ServiceBase):
|
|
891
913
|
key=key,
|
892
914
|
rotation_state=rotation_state,
|
893
915
|
)
|
894
|
-
return self.request.post("v1/key/rotate", KeyRotateResult, data=input.
|
916
|
+
return self.request.post("v1/key/rotate", KeyRotateResult, data=input.model_dump(exclude_none=True))
|
895
917
|
|
896
918
|
# Encrypt
|
897
919
|
def encrypt(self, id: str, plain_text: str, version: Optional[int] = None) -> PangeaResponse[EncryptResult]:
|
@@ -922,8 +944,8 @@ class Vault(ServiceBase):
|
|
922
944
|
version=1,
|
923
945
|
)
|
924
946
|
"""
|
925
|
-
input = EncryptRequest(id=id, plain_text=plain_text, version=version)
|
926
|
-
return self.request.post("v1/key/encrypt", EncryptResult, data=input.
|
947
|
+
input = EncryptRequest(id=id, plain_text=plain_text, version=version)
|
948
|
+
return self.request.post("v1/key/encrypt", EncryptResult, data=input.model_dump(exclude_none=True))
|
927
949
|
|
928
950
|
# Decrypt
|
929
951
|
def decrypt(self, id: str, cipher_text: str, version: Optional[int] = None) -> PangeaResponse[DecryptResult]:
|
@@ -954,8 +976,8 @@ class Vault(ServiceBase):
|
|
954
976
|
version=1,
|
955
977
|
)
|
956
978
|
"""
|
957
|
-
input = DecryptRequest(id=id, cipher_text=cipher_text, version=version)
|
958
|
-
return self.request.post("v1/key/decrypt", DecryptResult, data=input.
|
979
|
+
input = DecryptRequest(id=id, cipher_text=cipher_text, version=version)
|
980
|
+
return self.request.post("v1/key/decrypt", DecryptResult, data=input.model_dump(exclude_none=True))
|
959
981
|
|
960
982
|
# Sign
|
961
983
|
def sign(self, id: str, message: str, version: Optional[int] = None) -> PangeaResponse[SignResult]:
|
@@ -987,7 +1009,7 @@ class Vault(ServiceBase):
|
|
987
1009
|
)
|
988
1010
|
"""
|
989
1011
|
input = SignRequest(id=id, message=message, version=version)
|
990
|
-
return self.request.post("v1/key/sign", SignResult, data=input.
|
1012
|
+
return self.request.post("v1/key/sign", SignResult, data=input.model_dump(exclude_none=True))
|
991
1013
|
|
992
1014
|
# Verify
|
993
1015
|
def verify(
|
@@ -1028,7 +1050,7 @@ class Vault(ServiceBase):
|
|
1028
1050
|
signature=signature,
|
1029
1051
|
version=version,
|
1030
1052
|
)
|
1031
|
-
return self.request.post("v1/key/verify", VerifyResult, data=input.
|
1053
|
+
return self.request.post("v1/key/verify", VerifyResult, data=input.model_dump(exclude_none=True))
|
1032
1054
|
|
1033
1055
|
def jwt_verify(self, jws: str) -> PangeaResponse[JWTVerifyResult]:
|
1034
1056
|
"""
|
@@ -1055,7 +1077,7 @@ class Vault(ServiceBase):
|
|
1055
1077
|
)
|
1056
1078
|
"""
|
1057
1079
|
input = JWTVerifyRequest(jws=jws)
|
1058
|
-
return self.request.post("v1/key/verify/jwt", JWTVerifyResult, data=input.
|
1080
|
+
return self.request.post("v1/key/verify/jwt", JWTVerifyResult, data=input.model_dump(exclude_none=True))
|
1059
1081
|
|
1060
1082
|
def jwt_sign(self, id: str, payload: str) -> PangeaResponse[JWTSignResult]:
|
1061
1083
|
"""
|
@@ -1084,7 +1106,7 @@ class Vault(ServiceBase):
|
|
1084
1106
|
)
|
1085
1107
|
"""
|
1086
1108
|
input = JWTSignRequest(id=id, payload=payload)
|
1087
|
-
return self.request.post("v1/key/sign/jwt", JWTSignResult, data=input.
|
1109
|
+
return self.request.post("v1/key/sign/jwt", JWTSignResult, data=input.model_dump(exclude_none=True))
|
1088
1110
|
|
1089
1111
|
# Get endpoint
|
1090
1112
|
def jwk_get(self, id: str, version: Optional[str] = None) -> PangeaResponse[JWKGetResult]:
|
@@ -1115,7 +1137,7 @@ class Vault(ServiceBase):
|
|
1115
1137
|
)
|
1116
1138
|
"""
|
1117
1139
|
input = JWKGetRequest(id=id, version=version)
|
1118
|
-
return self.request.post("v1/get/jwk", JWKGetResult, data=input.
|
1140
|
+
return self.request.post("v1/get/jwk", JWKGetResult, data=input.model_dump(exclude_none=True))
|
1119
1141
|
|
1120
1142
|
# State change
|
1121
1143
|
def state_change(
|
@@ -1158,7 +1180,7 @@ class Vault(ServiceBase):
|
|
1158
1180
|
)
|
1159
1181
|
"""
|
1160
1182
|
input = StateChangeRequest(id=id, state=state, version=version, destroy_period=destroy_period)
|
1161
|
-
return self.request.post("v1/state/change", StateChangeResult, data=input.
|
1183
|
+
return self.request.post("v1/state/change", StateChangeResult, data=input.model_dump(exclude_none=True))
|
1162
1184
|
|
1163
1185
|
# Folder create
|
1164
1186
|
def folder_create(
|
@@ -1195,7 +1217,7 @@ class Vault(ServiceBase):
|
|
1195
1217
|
)
|
1196
1218
|
"""
|
1197
1219
|
input = FolderCreateRequest(name=name, folder=folder, metadata=metadata, tags=tags)
|
1198
|
-
return self.request.post("v1/folder/create", FolderCreateResult, data=input.
|
1220
|
+
return self.request.post("v1/folder/create", FolderCreateResult, data=input.model_dump(exclude_none=True))
|
1199
1221
|
|
1200
1222
|
# Encrypt structured
|
1201
1223
|
def encrypt_structured(
|
@@ -1216,7 +1238,7 @@ class Vault(ServiceBase):
|
|
1216
1238
|
Args:
|
1217
1239
|
id (str): The item ID.
|
1218
1240
|
structured_data (dict): Structured data for applying bulk operations.
|
1219
|
-
filter (str
|
1241
|
+
filter (str): A filter expression for applying bulk operations to the data field.
|
1220
1242
|
version (int, optional): The item version. Defaults to the current version.
|
1221
1243
|
additional_data (str, optional): User provided authentication data.
|
1222
1244
|
|
@@ -1243,7 +1265,7 @@ class Vault(ServiceBase):
|
|
1243
1265
|
return self.request.post(
|
1244
1266
|
"v1/key/encrypt/structured",
|
1245
1267
|
EncryptStructuredResult,
|
1246
|
-
data=input.
|
1268
|
+
data=input.model_dump(exclude_none=True),
|
1247
1269
|
)
|
1248
1270
|
|
1249
1271
|
# Decrypt structured
|
@@ -1265,7 +1287,7 @@ class Vault(ServiceBase):
|
|
1265
1287
|
Args:
|
1266
1288
|
id (str): The item ID.
|
1267
1289
|
structured_data (dict): Structured data to decrypt.
|
1268
|
-
filter (str
|
1290
|
+
filter (str): A filter expression for applying bulk operations to the data field.
|
1269
1291
|
version (int, optional): The item version. Defaults to the current version.
|
1270
1292
|
additional_data (str, optional): User provided authentication data.
|
1271
1293
|
|
@@ -1292,5 +1314,94 @@ class Vault(ServiceBase):
|
|
1292
1314
|
return self.request.post(
|
1293
1315
|
"v1/key/decrypt/structured",
|
1294
1316
|
EncryptStructuredResult,
|
1295
|
-
data=input.
|
1317
|
+
data=input.model_dump(exclude_none=True),
|
1318
|
+
)
|
1319
|
+
|
1320
|
+
def encrypt_transform(
|
1321
|
+
self,
|
1322
|
+
id: str,
|
1323
|
+
plain_text: str,
|
1324
|
+
alphabet: TransformAlphabet,
|
1325
|
+
tweak: str | None = None,
|
1326
|
+
version: int | None = None,
|
1327
|
+
) -> PangeaResponse[EncryptTransformResult]:
|
1328
|
+
"""
|
1329
|
+
Encrypt transform
|
1330
|
+
|
1331
|
+
Encrypt using a format-preserving algorithm (FPE).
|
1332
|
+
|
1333
|
+
OperationId: vault_post_v1_key_encrypt_transform
|
1334
|
+
|
1335
|
+
Args:
|
1336
|
+
id: The item ID.
|
1337
|
+
plain_text: A message to be encrypted.
|
1338
|
+
alphabet: Set of characters to use for format-preserving encryption (FPE).
|
1339
|
+
tweak: User provided tweak string. If not provided, a random string will be generated and returned.
|
1340
|
+
version: The item version. Defaults to the current version.
|
1341
|
+
|
1342
|
+
Raises:
|
1343
|
+
PangeaAPIException: If an API error happens.
|
1344
|
+
|
1345
|
+
Returns:
|
1346
|
+
A `PangeaResponse` containing the encrypted message.
|
1347
|
+
|
1348
|
+
Examples:
|
1349
|
+
vault.encrypt_transform(
|
1350
|
+
id="pvi_[...]",
|
1351
|
+
plain_text="message to encrypt",
|
1352
|
+
alphabet=TransformAlphabet.ALPHANUMERIC,
|
1353
|
+
tweak="MTIzMTIzMT==",
|
1354
|
+
)
|
1355
|
+
"""
|
1356
|
+
|
1357
|
+
input = EncryptTransformRequest(
|
1358
|
+
id=id,
|
1359
|
+
plain_text=plain_text,
|
1360
|
+
tweak=tweak,
|
1361
|
+
alphabet=alphabet,
|
1362
|
+
version=version,
|
1363
|
+
)
|
1364
|
+
return self.request.post(
|
1365
|
+
"v1/key/encrypt/transform",
|
1366
|
+
EncryptTransformResult,
|
1367
|
+
data=input.model_dump(exclude_none=True),
|
1368
|
+
)
|
1369
|
+
|
1370
|
+
def decrypt_transform(
|
1371
|
+
self, id: str, cipher_text: str, tweak: str, alphabet: TransformAlphabet, version: int | None = None
|
1372
|
+
) -> PangeaResponse[DecryptTransformResult]:
|
1373
|
+
"""
|
1374
|
+
Decrypt transform
|
1375
|
+
|
1376
|
+
Decrypt using a format-preserving algorithm (FPE).
|
1377
|
+
|
1378
|
+
OperationId: vault_post_v1_key_decrypt_transform
|
1379
|
+
|
1380
|
+
Args:
|
1381
|
+
id: The item ID.
|
1382
|
+
cipher_text: A message encrypted by Vault.
|
1383
|
+
tweak: User provided tweak string.
|
1384
|
+
alphabet: Set of characters to use for format-preserving encryption (FPE).
|
1385
|
+
version: The item version. Defaults to the current version.
|
1386
|
+
|
1387
|
+
Raises:
|
1388
|
+
PangeaAPIException: If an API error happens.
|
1389
|
+
|
1390
|
+
Returns:
|
1391
|
+
A `PangeaResponse` containing the decrypted message.
|
1392
|
+
|
1393
|
+
Examples:
|
1394
|
+
vault.decrypt_transform(
|
1395
|
+
id="pvi_[...]",
|
1396
|
+
cipher_text="encrypted message",
|
1397
|
+
tweak="MTIzMTIzMT==",
|
1398
|
+
alphabet=TransformAlphabet.ALPHANUMERIC,
|
1399
|
+
)
|
1400
|
+
"""
|
1401
|
+
|
1402
|
+
input = DecryptTransformRequest(id=id, cipher_text=cipher_text, tweak=tweak, alphabet=alphabet, version=version)
|
1403
|
+
return self.request.post(
|
1404
|
+
"v1/key/decrypt/transform",
|
1405
|
+
DecryptTransformResult,
|
1406
|
+
data=input.model_dump(exclude_none=True),
|
1296
1407
|
)
|
pangea/utils.py
CHANGED
@@ -3,11 +3,9 @@ import copy
|
|
3
3
|
import datetime
|
4
4
|
import io
|
5
5
|
import json
|
6
|
-
from
|
7
|
-
from hashlib import md5, new, sha1, sha256, sha512
|
8
|
-
from typing import Union
|
6
|
+
from hashlib import new, sha1, sha256, sha512
|
9
7
|
|
10
|
-
from google_crc32c import Checksum as CRC32C # type: ignore[import]
|
8
|
+
from google_crc32c import Checksum as CRC32C # type: ignore[import-untyped]
|
11
9
|
from pydantic import BaseModel
|
12
10
|
|
13
11
|
|
@@ -31,24 +29,8 @@ def default_encoder(obj) -> str:
|
|
31
29
|
return str(obj)
|
32
30
|
|
33
31
|
|
34
|
-
def str2str_b64(data: str):
|
35
|
-
return base64.b64encode(data.encode(
|
36
|
-
|
37
|
-
|
38
|
-
def dict_order_keys(data: dict) -> OrderedDict:
|
39
|
-
if isinstance(data, dict):
|
40
|
-
return OrderedDict(sorted(data.items()))
|
41
|
-
else:
|
42
|
-
return data
|
43
|
-
|
44
|
-
|
45
|
-
def dict_order_keys_recursive(data: dict) -> OrderedDict:
|
46
|
-
if isinstance(data, dict):
|
47
|
-
for k, v in data.items():
|
48
|
-
if type(v) is dict:
|
49
|
-
data[k] = dict_order_keys_recursive(v)
|
50
|
-
|
51
|
-
return data # type: ignore[return-value]
|
32
|
+
def str2str_b64(data: str, encoding: str = "utf-8") -> str:
|
33
|
+
return base64.b64encode(data.encode(encoding)).decode("ascii")
|
52
34
|
|
53
35
|
|
54
36
|
def canonicalize_nested_json(data: dict) -> dict:
|
@@ -77,97 +59,33 @@ def canonicalize(data: dict) -> str:
|
|
77
59
|
return str(data)
|
78
60
|
|
79
61
|
|
80
|
-
def hash_sha256(
|
81
|
-
# Return
|
82
|
-
|
83
|
-
if isinstance(input, io.BufferedReader):
|
84
|
-
input.seek(0) # restart reading
|
85
|
-
while True:
|
86
|
-
chunk = input.read(1024 * 1024)
|
87
|
-
if not chunk:
|
88
|
-
break
|
89
|
-
hash.update(chunk)
|
90
|
-
|
91
|
-
input.seek(0) # restart reading
|
92
|
-
else:
|
93
|
-
hash.update(input) # type: ignore
|
94
|
-
|
95
|
-
return hash.hexdigest()
|
96
|
-
|
62
|
+
def hash_sha256(data: str) -> str:
|
63
|
+
# Return sha256 hash in hex format
|
64
|
+
return sha256(data.encode("ascii")).hexdigest()
|
97
65
|
|
98
|
-
def hash_sha1(input: Union[str, io.BufferedReader]) -> str:
|
99
|
-
# Return SHA1 hash in hex format
|
100
|
-
hash = sha1()
|
101
|
-
if isinstance(input, io.BufferedReader):
|
102
|
-
input.seek(0) # restart reading
|
103
|
-
while True:
|
104
|
-
chunk = input.read(1024 * 1024)
|
105
|
-
if not chunk:
|
106
|
-
break
|
107
|
-
hash.update(chunk)
|
108
|
-
|
109
|
-
input.seek(0) # restart reading
|
110
|
-
else:
|
111
|
-
hash.update(input) # type: ignore
|
112
66
|
|
113
|
-
|
67
|
+
def hash_256_filepath(filepath: str) -> str:
|
68
|
+
data = open(filepath, "rb")
|
69
|
+
hash = sha256(data.read()).hexdigest()
|
70
|
+
data.close()
|
71
|
+
return hash
|
114
72
|
|
115
73
|
|
116
|
-
def
|
117
|
-
# Return
|
118
|
-
|
119
|
-
if isinstance(input, io.BufferedReader):
|
120
|
-
input.seek(0) # restart reading
|
121
|
-
while True:
|
122
|
-
chunk = input.read(1024 * 1024)
|
123
|
-
if not chunk:
|
124
|
-
break
|
125
|
-
hash.update(chunk)
|
74
|
+
def hash_sha1(data: str) -> str:
|
75
|
+
# Return sha1 hash in hex format
|
76
|
+
return sha1(data.encode("ascii")).hexdigest()
|
126
77
|
|
127
|
-
input.seek(0) # restart reading
|
128
|
-
else:
|
129
|
-
hash.update(input) # type: ignore
|
130
78
|
|
131
|
-
|
79
|
+
def hash_sha512(data: str) -> str:
|
80
|
+
# Return sha512 hash in hex format
|
81
|
+
return sha512(data.encode("ascii")).hexdigest()
|
132
82
|
|
133
83
|
|
134
|
-
def hash_ntlm(data: str)
|
135
|
-
#
|
84
|
+
def hash_ntlm(data: str):
|
85
|
+
# Calculate the NTLM hash
|
136
86
|
return new("md4", data.encode("utf-16le")).hexdigest()
|
137
87
|
|
138
88
|
|
139
|
-
def hash_md5(input: Union[str, io.BufferedReader]) -> str:
|
140
|
-
# Return MD5 hash in hex format
|
141
|
-
hash = md5()
|
142
|
-
if isinstance(input, io.BufferedReader):
|
143
|
-
input.seek(0) # restart reading
|
144
|
-
|
145
|
-
while True:
|
146
|
-
chunk = input.read(1024 * 1024)
|
147
|
-
if not chunk:
|
148
|
-
break
|
149
|
-
hash.update(chunk)
|
150
|
-
|
151
|
-
input.seek(0) # restart reading
|
152
|
-
else:
|
153
|
-
hash.update(input) # type: ignore
|
154
|
-
|
155
|
-
return hash.hexdigest()
|
156
|
-
|
157
|
-
|
158
|
-
def get_crc32c(data: str) -> str:
|
159
|
-
crc = CRC32C()
|
160
|
-
crc.update(data)
|
161
|
-
return crc.hexdigest().decode("utf-8")
|
162
|
-
|
163
|
-
|
164
|
-
def hash_256_filepath(filepath: str) -> str:
|
165
|
-
data = open(filepath, "rb")
|
166
|
-
hash = sha256(data.read()).hexdigest()
|
167
|
-
data.close()
|
168
|
-
return hash
|
169
|
-
|
170
|
-
|
171
89
|
def get_prefix(hash: str, len: int = 5):
|
172
90
|
return hash[0:len]
|
173
91
|
|
@@ -197,10 +115,3 @@ def get_file_upload_params(file: io.BufferedReader) -> FileUploadParams:
|
|
197
115
|
|
198
116
|
file.seek(0) # restart reading
|
199
117
|
return FileUploadParams(crc_hex=crc.hexdigest().decode("utf-8"), sha256_hex=sha.hexdigest(), size=size)
|
200
|
-
|
201
|
-
|
202
|
-
def get_file_size(file: io.BufferedReader) -> int:
|
203
|
-
file.seek(0, io.SEEK_END)
|
204
|
-
size = file.tell()
|
205
|
-
file.seek(0) # restart reading
|
206
|
-
return size
|