pangea-sdk 5.0.0__py3-none-any.whl → 5.2.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 -1
- pangea/asyncio/request.py +20 -4
- pangea/asyncio/services/__init__.py +1 -0
- pangea/asyncio/services/audit.py +6 -10
- pangea/asyncio/services/authz.py +23 -2
- pangea/asyncio/services/base.py +21 -2
- pangea/asyncio/services/intel.py +3 -0
- pangea/asyncio/services/sanitize.py +26 -2
- pangea/asyncio/services/share.py +643 -0
- pangea/deep_verify.py +7 -1
- pangea/dump_audit.py +8 -7
- pangea/request.py +20 -6
- pangea/response.py +12 -0
- pangea/services/__init__.py +1 -0
- pangea/services/audit/audit.py +5 -10
- pangea/services/authz.py +21 -1
- pangea/services/base.py +16 -2
- pangea/services/intel.py +18 -0
- pangea/services/redact.py +16 -0
- pangea/services/sanitize.py +22 -0
- pangea/services/share/file_format.py +170 -0
- pangea/services/share/share.py +1278 -0
- pangea/utils.py +88 -17
- {pangea_sdk-5.0.0.dist-info → pangea_sdk-5.2.0.dist-info}/METADATA +11 -10
- {pangea_sdk-5.0.0.dist-info → pangea_sdk-5.2.0.dist-info}/RECORD +26 -23
- {pangea_sdk-5.0.0.dist-info → pangea_sdk-5.2.0.dist-info}/WHEEL +0 -0
pangea/__init__.py
CHANGED
pangea/asyncio/request.py
CHANGED
@@ -182,13 +182,27 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
182
182
|
if resp.status < 200 or resp.status >= 300:
|
183
183
|
raise pe.PresignedUploadError(f"presigned PUT failure: {resp.status}", await resp.text())
|
184
184
|
|
185
|
-
async def download_file(self, url: str, filename:
|
185
|
+
async def download_file(self, url: str, filename: str | None = None) -> AttachedFile:
|
186
|
+
"""
|
187
|
+
Download file
|
188
|
+
|
189
|
+
Download a file from the specified URL and save it with the given
|
190
|
+
filename.
|
191
|
+
|
192
|
+
Args:
|
193
|
+
url: URL of the file to download
|
194
|
+
filename: Name to save the downloaded file as. If not provided, the
|
195
|
+
filename will be determined from the Content-Disposition header or
|
196
|
+
the URL.
|
197
|
+
"""
|
198
|
+
|
186
199
|
self.logger.debug(
|
187
200
|
json.dumps(
|
188
201
|
{
|
189
202
|
"service": self.service,
|
190
203
|
"action": "download_file",
|
191
204
|
"url": url,
|
205
|
+
"filename": filename,
|
192
206
|
"status": "start",
|
193
207
|
}
|
194
208
|
)
|
@@ -303,6 +317,9 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
303
317
|
raise AttributeError("files attribute should have at least 1 file")
|
304
318
|
|
305
319
|
response = await self.request_presigned_url(endpoint=endpoint, result_class=result_class, data=data)
|
320
|
+
if response.success: # This should only happen when uploading a zero bytes file
|
321
|
+
return response.raw_response
|
322
|
+
|
306
323
|
if response.accepted_result is None:
|
307
324
|
raise pe.PangeaException("No accepted_result field when requesting presigned url")
|
308
325
|
if response.accepted_result.post_url is None:
|
@@ -322,9 +339,8 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
322
339
|
) -> PangeaResponse:
|
323
340
|
# Send request
|
324
341
|
try:
|
325
|
-
# This should return 202 (AcceptedRequestException)
|
326
|
-
|
327
|
-
raise pe.PresignedURLException("Should return 202", resp)
|
342
|
+
# This should return 202 (AcceptedRequestException) at least zero size file is sent
|
343
|
+
return await self.post(endpoint=endpoint, result_class=result_class, data=data, poll_result=False)
|
328
344
|
except pe.AcceptedRequestException as e:
|
329
345
|
accepted_exception = e
|
330
346
|
except Exception as e:
|
pangea/asyncio/services/audit.py
CHANGED
@@ -174,14 +174,16 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
174
174
|
verbose: Optional[bool] = None,
|
175
175
|
) -> PangeaResponse[LogResult]:
|
176
176
|
"""
|
177
|
-
Log an
|
177
|
+
Log an event
|
178
178
|
|
179
179
|
Create a log entry in the Secure Audit Log.
|
180
|
+
|
180
181
|
Args:
|
181
182
|
event (dict[str, Any]): event to be logged
|
182
183
|
verify (bool, optional): True to verify logs consistency after response.
|
183
184
|
sign_local (bool, optional): True to sign event with local key.
|
184
185
|
verbose (bool, optional): True to get a more verbose response.
|
186
|
+
|
185
187
|
Raises:
|
186
188
|
AuditException: If an audit based api exception happens
|
187
189
|
PangeaAPIException: If an API Error happens
|
@@ -192,13 +194,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
192
194
|
Available response fields can be found in our [API documentation](https://pangea.cloud/docs/api/audit#log-an-entry).
|
193
195
|
|
194
196
|
Examples:
|
195
|
-
|
196
|
-
log_response = audit.log({"message"="Hello world"}, verbose=False)
|
197
|
-
print(f"Response. Hash: {log_response.result.hash}")
|
198
|
-
except pe.PangeaAPIException as e:
|
199
|
-
print(f"Request Error: {e.response.summary}")
|
200
|
-
for err in e.errors:
|
201
|
-
print(f"\\t{err.detail} \\n")
|
197
|
+
response = await audit.log_event({"message": "hello world"}, verbose=True)
|
202
198
|
"""
|
203
199
|
|
204
200
|
input = self._get_log_request(event, sign_local=sign_local, verify=verify, verbose=verbose)
|
@@ -632,9 +628,9 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
632
628
|
if pub_root is not None:
|
633
629
|
self.pub_roots[tree_size] = pub_root
|
634
630
|
|
635
|
-
await self.
|
631
|
+
await self._fix_consistency_proofs(tree_sizes)
|
636
632
|
|
637
|
-
async def
|
633
|
+
async def _fix_consistency_proofs(self, tree_sizes: Iterable[int]) -> None:
|
638
634
|
# on very rare occasions, the consistency proof in Arweave may be wrong
|
639
635
|
# override it with the proof from pangea (not the root hash, just the proof)
|
640
636
|
for tree_size in tree_sizes:
|
pangea/asyncio/services/authz.py
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
3
|
|
4
|
+
from __future__ import annotations
|
5
|
+
|
4
6
|
from typing import Any, Dict, List, Optional
|
5
7
|
|
6
8
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
9
|
+
from pangea.config import PangeaConfig
|
7
10
|
from pangea.response import PangeaResponse
|
8
11
|
from pangea.services.authz import (
|
9
12
|
CheckRequest,
|
@@ -36,8 +39,8 @@ class AuthZAsync(ServiceBaseAsync):
|
|
36
39
|
|
37
40
|
Examples:
|
38
41
|
import os
|
42
|
+
from pangea.asyncio.services import AuthZAsync
|
39
43
|
from pangea.config import PangeaConfig
|
40
|
-
from pangea.services import AuthZ
|
41
44
|
|
42
45
|
PANGEA_TOKEN = os.getenv("PANGEA_AUTHZ_TOKEN")
|
43
46
|
|
@@ -49,7 +52,25 @@ class AuthZAsync(ServiceBaseAsync):
|
|
49
52
|
|
50
53
|
service_name = "authz"
|
51
54
|
|
52
|
-
def __init__(
|
55
|
+
def __init__(
|
56
|
+
self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
|
57
|
+
) -> None:
|
58
|
+
"""
|
59
|
+
AuthZ client
|
60
|
+
|
61
|
+
Initializes a new AuthZ client.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
token: Pangea API token.
|
65
|
+
config: Configuration.
|
66
|
+
logger_name: Logger name.
|
67
|
+
config_id: Configuration ID.
|
68
|
+
|
69
|
+
Examples:
|
70
|
+
config = PangeaConfig(domain="aws.us.pangea.cloud")
|
71
|
+
authz = AuthZAsync(token="pangea_token", config=config)
|
72
|
+
"""
|
73
|
+
|
53
74
|
super().__init__(token, config, logger_name, config_id=config_id)
|
54
75
|
|
55
76
|
async def tuple_create(self, tuples: List[Tuple]) -> PangeaResponse[TupleCreateResult]:
|
pangea/asyncio/services/base.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
from __future__ import annotations
|
3
4
|
|
4
5
|
from typing import Dict, Optional, Type, Union
|
5
6
|
|
7
|
+
from typing_extensions import override
|
8
|
+
|
6
9
|
from pangea.asyncio.request import PangeaRequestAsync
|
7
10
|
from pangea.exceptions import AcceptedRequestException
|
8
11
|
from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
|
@@ -23,6 +26,7 @@ class ServiceBaseAsync(ServiceBase):
|
|
23
26
|
|
24
27
|
return self._request
|
25
28
|
|
29
|
+
@override
|
26
30
|
async def poll_result( # type: ignore[override]
|
27
31
|
self,
|
28
32
|
exception: Optional[AcceptedRequestException] = None,
|
@@ -36,7 +40,8 @@ class ServiceBaseAsync(ServiceBase):
|
|
36
40
|
Returns request's result that has been accepted by the server
|
37
41
|
|
38
42
|
Args:
|
39
|
-
exception
|
43
|
+
exception: Exception that was previously raised by the SDK on a call
|
44
|
+
that is being processed.
|
40
45
|
|
41
46
|
Returns:
|
42
47
|
PangeaResponse
|
@@ -58,7 +63,21 @@ class ServiceBaseAsync(ServiceBase):
|
|
58
63
|
else:
|
59
64
|
raise AttributeError("Need to set exception, response or request_id")
|
60
65
|
|
61
|
-
|
66
|
+
@override
|
67
|
+
async def download_file(self, url: str, filename: str | None = None) -> AttachedFile: # type: ignore[override]
|
68
|
+
"""
|
69
|
+
Download file
|
70
|
+
|
71
|
+
Download a file from the specified URL and save it with the given
|
72
|
+
filename.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
url: URL of the file to download
|
76
|
+
filename: Name to save the downloaded file as. If not provided, the
|
77
|
+
filename will be determined from the Content-Disposition header or
|
78
|
+
the URL.
|
79
|
+
"""
|
80
|
+
|
62
81
|
return await self.request.download_file(url=url, filename=filename)
|
63
82
|
|
64
83
|
async def close(self):
|
pangea/asyncio/services/intel.py
CHANGED
@@ -790,6 +790,7 @@ class UserIntelAsync(ServiceBaseAsync):
|
|
790
790
|
verbose: Optional[bool] = None,
|
791
791
|
raw: Optional[bool] = None,
|
792
792
|
provider: Optional[str] = None,
|
793
|
+
cursor: Optional[str] = None,
|
793
794
|
) -> PangeaResponse[m.UserBreachedResult]:
|
794
795
|
"""
|
795
796
|
Look up breached users
|
@@ -808,6 +809,7 @@ class UserIntelAsync(ServiceBaseAsync):
|
|
808
809
|
verbose (bool, optional): Echo the API parameters in the response
|
809
810
|
raw (bool, optional): Include raw data from this provider
|
810
811
|
provider (str, optional): Use reputation data from this provider: "crowdstrike"
|
812
|
+
cursor (str, optional): A token given in the raw response from SpyCloud. Post this back to paginate results
|
811
813
|
|
812
814
|
Raises:
|
813
815
|
PangeaAPIException: If an API Error happens
|
@@ -835,6 +837,7 @@ class UserIntelAsync(ServiceBaseAsync):
|
|
835
837
|
end=end,
|
836
838
|
verbose=verbose,
|
837
839
|
raw=raw,
|
840
|
+
cursor=cursor,
|
838
841
|
)
|
839
842
|
return await self.request.post(
|
840
843
|
"v1/user/breached", m.UserBreachedResult, data=input.model_dump(exclude_none=True)
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
from __future__ import annotations
|
4
|
+
|
3
5
|
import io
|
4
6
|
from typing import List, Optional, Tuple
|
5
7
|
|
6
8
|
import pangea.services.sanitize as m
|
7
9
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
10
|
+
from pangea.config import PangeaConfig
|
8
11
|
from pangea.response import PangeaResponse, TransferMethod
|
9
12
|
from pangea.utils import FileUploadParams, get_file_upload_params
|
10
13
|
|
@@ -16,17 +19,38 @@ class SanitizeAsync(ServiceBaseAsync):
|
|
16
19
|
import os
|
17
20
|
|
18
21
|
# Pangea SDK
|
22
|
+
from pangea.asyncio.services import SanitizeAsync
|
19
23
|
from pangea.config import PangeaConfig
|
20
|
-
from pangea.asyncio.services import Sanitize
|
21
24
|
|
22
25
|
PANGEA_SANITIZE_TOKEN = os.getenv("PANGEA_SANITIZE_TOKEN")
|
23
26
|
config = PangeaConfig(domain="pangea.cloud")
|
24
27
|
|
25
|
-
sanitize =
|
28
|
+
sanitize = SanitizeAsync(token=PANGEA_SANITIZE_TOKEN, config=config)
|
26
29
|
"""
|
27
30
|
|
28
31
|
service_name = "sanitize"
|
29
32
|
|
33
|
+
def __init__(
|
34
|
+
self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
|
35
|
+
) -> None:
|
36
|
+
"""
|
37
|
+
Sanitize client
|
38
|
+
|
39
|
+
Initializes a new Sanitize client.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
token: Pangea API token.
|
43
|
+
config: Configuration.
|
44
|
+
logger_name: Logger name.
|
45
|
+
config_id: Configuration ID.
|
46
|
+
|
47
|
+
Examples:
|
48
|
+
config = PangeaConfig(domain="aws.us.pangea.cloud")
|
49
|
+
authz = SanitizeAsync(token="pangea_token", config=config)
|
50
|
+
"""
|
51
|
+
|
52
|
+
super().__init__(token, config, logger_name, config_id=config_id)
|
53
|
+
|
30
54
|
async def sanitize(
|
31
55
|
self,
|
32
56
|
transfer_method: TransferMethod = TransferMethod.POST_URL,
|