pangea-sdk 3.7.1__tar.gz → 3.8.0__tar.gz
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_sdk-3.7.1 → pangea_sdk-3.8.0}/PKG-INFO +13 -8
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/README.md +9 -5
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/__init__.py +1 -1
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/request.py +11 -12
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/__init__.py +1 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/audit.py +141 -10
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/authn.py +64 -48
- pangea_sdk-3.8.0/pangea/asyncio/services/authz.py +259 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/intel.py +4 -4
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/redact.py +20 -1
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/vault.py +21 -4
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/request.py +20 -17
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/response.py +27 -16
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/__init__.py +1 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/audit/audit.py +145 -13
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/audit/models.py +40 -3
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/authn/authn.py +20 -4
- pangea_sdk-3.8.0/pangea/services/authz.py +377 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/base.py +23 -6
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/intel.py +2 -2
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/redact.py +20 -1
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/vault/vault.py +23 -6
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/utils.py +2 -2
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pyproject.toml +4 -3
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/base.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/embargo.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/asyncio/services/file_scan.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/audit_logger.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/config.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/deep_verify.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/deprecated.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/dump_audit.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/exceptions.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/py.typed +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/audit/exceptions.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/audit/signing.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/audit/util.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/authn/models.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/embargo.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/file_scan.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/vault/models/asymmetric.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/vault/models/common.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/vault/models/secret.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/services/vault/models/symmetric.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/tools.py +0 -0
- {pangea_sdk-3.7.1 → pangea_sdk-3.8.0}/pangea/verify_audit.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pangea-sdk
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.8.0
|
4
4
|
Summary: Pangea API SDK
|
5
5
|
Home-page: https://pangea.cloud/docs/sdk/python/
|
6
6
|
License: MIT
|
@@ -18,13 +18,14 @@ Classifier: Topic :: Software Development
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries
|
19
19
|
Requires-Dist: aiohttp (>=3.8.6,<4.0.0)
|
20
20
|
Requires-Dist: asyncio (>=3.4.3,<4.0.0)
|
21
|
-
Requires-Dist: cryptography (>=42.0.
|
21
|
+
Requires-Dist: cryptography (>=42.0.7,<43.0.0)
|
22
22
|
Requires-Dist: deprecated (>=1.2.14,<2.0.0)
|
23
23
|
Requires-Dist: google-crc32c (>=1.5.0,<2.0.0)
|
24
|
-
Requires-Dist: pydantic (>=1.10.
|
24
|
+
Requires-Dist: pydantic (>=1.10.15,<2.0.0)
|
25
25
|
Requires-Dist: python-dateutil (>=2.9.0,<3.0.0)
|
26
26
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
27
27
|
Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
|
28
|
+
Requires-Dist: typing-extensions (>=4.7.1,<5.0.0)
|
28
29
|
Project-URL: Repository, https://github.com/pangeacyber/pangea-python/tree/main/packages/pangea-sdk
|
29
30
|
Description-Content-Type: text/markdown
|
30
31
|
|
@@ -44,6 +45,8 @@ above.
|
|
44
45
|
|
45
46
|
## Installation
|
46
47
|
|
48
|
+
#### GA releases
|
49
|
+
|
47
50
|
Via pip:
|
48
51
|
|
49
52
|
```bash
|
@@ -58,7 +61,7 @@ $ poetry add pangea-sdk
|
|
58
61
|
|
59
62
|
<a name="beta-releases"></a>
|
60
63
|
|
61
|
-
|
64
|
+
#### Beta releases
|
62
65
|
|
63
66
|
Pre-release versions may be available with the `b` (beta) denotation in the
|
64
67
|
version number. These releases serve to preview beta services and APIs. Per
|
@@ -68,19 +71,20 @@ compatibility guarantees as stable releases. [Beta changelog](https://github.com
|
|
68
71
|
Via pip:
|
69
72
|
|
70
73
|
```bash
|
71
|
-
$ pip3 install pangea-sdk==3.8.
|
74
|
+
$ pip3 install pangea-sdk==3.8.0b2
|
72
75
|
```
|
73
76
|
|
74
77
|
Via poetry:
|
75
78
|
|
76
79
|
```bash
|
77
|
-
$ poetry add pangea-sdk==3.8.
|
80
|
+
$ poetry add pangea-sdk==3.8.0b2
|
78
81
|
```
|
79
82
|
|
80
83
|
## Usage
|
81
84
|
|
82
85
|
- [Documentation][]
|
83
|
-
- [Examples][]
|
86
|
+
- [GA Examples][]
|
87
|
+
- [Beta Examples][]
|
84
88
|
|
85
89
|
General usage would be to create a token for a service through the
|
86
90
|
[Pangea Console][] and then construct an API client for that respective service.
|
@@ -224,7 +228,8 @@ It accepts multiple file formats:
|
|
224
228
|
|
225
229
|
|
226
230
|
[Documentation]: https://pangea.cloud/docs/sdk/python/
|
227
|
-
[Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
|
231
|
+
[GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
|
232
|
+
[Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
|
228
233
|
[Pangea Console]: https://console.pangea.cloud/
|
229
234
|
[Slack]: https://pangea.cloud/join-slack/
|
230
235
|
[Secure Audit Log]: https://pangea.cloud/docs/audit
|
@@ -14,6 +14,8 @@ above.
|
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
17
|
+
#### GA releases
|
18
|
+
|
17
19
|
Via pip:
|
18
20
|
|
19
21
|
```bash
|
@@ -28,7 +30,7 @@ $ poetry add pangea-sdk
|
|
28
30
|
|
29
31
|
<a name="beta-releases"></a>
|
30
32
|
|
31
|
-
|
33
|
+
#### Beta releases
|
32
34
|
|
33
35
|
Pre-release versions may be available with the `b` (beta) denotation in the
|
34
36
|
version number. These releases serve to preview beta services and APIs. Per
|
@@ -38,19 +40,20 @@ compatibility guarantees as stable releases. [Beta changelog](https://github.com
|
|
38
40
|
Via pip:
|
39
41
|
|
40
42
|
```bash
|
41
|
-
$ pip3 install pangea-sdk==3.8.
|
43
|
+
$ pip3 install pangea-sdk==3.8.0b2
|
42
44
|
```
|
43
45
|
|
44
46
|
Via poetry:
|
45
47
|
|
46
48
|
```bash
|
47
|
-
$ poetry add pangea-sdk==3.8.
|
49
|
+
$ poetry add pangea-sdk==3.8.0b2
|
48
50
|
```
|
49
51
|
|
50
52
|
## Usage
|
51
53
|
|
52
54
|
- [Documentation][]
|
53
|
-
- [Examples][]
|
55
|
+
- [GA Examples][]
|
56
|
+
- [Beta Examples][]
|
54
57
|
|
55
58
|
General usage would be to create a token for a service through the
|
56
59
|
[Pangea Console][] and then construct an API client for that respective service.
|
@@ -194,7 +197,8 @@ It accepts multiple file formats:
|
|
194
197
|
|
195
198
|
|
196
199
|
[Documentation]: https://pangea.cloud/docs/sdk/python/
|
197
|
-
[Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
|
200
|
+
[GA Examples]: https://github.com/pangeacyber/pangea-python/tree/main/examples
|
201
|
+
[Beta Examples]: https://github.com/pangeacyber/pangea-python/tree/beta/examples
|
198
202
|
[Pangea Console]: https://console.pangea.cloud/
|
199
203
|
[Slack]: https://pangea.cloud/join-slack/
|
200
204
|
[Secure Audit Log]: https://pangea.cloud/docs/audit
|
@@ -8,12 +8,15 @@ from typing import Dict, List, Optional, Tuple, Type, Union
|
|
8
8
|
|
9
9
|
import aiohttp
|
10
10
|
from aiohttp import FormData
|
11
|
+
from typing_extensions import TypeVar
|
11
12
|
|
12
13
|
import pangea.exceptions as pe
|
13
14
|
from pangea.request import MultipartResponse, PangeaRequestBase
|
14
15
|
from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult, ResponseStatus, TransferMethod
|
15
16
|
from pangea.utils import default_encoder
|
16
17
|
|
18
|
+
TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
|
19
|
+
|
17
20
|
|
18
21
|
class PangeaRequestAsync(PangeaRequestBase):
|
19
22
|
"""An object that makes direct calls to Pangea Service APIs.
|
@@ -27,12 +30,12 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
27
30
|
async def post(
|
28
31
|
self,
|
29
32
|
endpoint: str,
|
30
|
-
result_class: Type[
|
33
|
+
result_class: Type[TResult],
|
31
34
|
data: Union[str, Dict] = {},
|
32
35
|
files: List[Tuple] = [],
|
33
36
|
poll_result: bool = True,
|
34
37
|
url: Optional[str] = None,
|
35
|
-
) -> PangeaResponse:
|
38
|
+
) -> PangeaResponse[TResult]:
|
36
39
|
"""Makes the POST call to a Pangea Service endpoint.
|
37
40
|
|
38
41
|
Args:
|
@@ -90,9 +93,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
90
93
|
|
91
94
|
return self._check_response(pangea_response)
|
92
95
|
|
93
|
-
async def get(
|
94
|
-
self, path: str, result_class: Type[PangeaResponseResult], check_response: bool = True
|
95
|
-
) -> PangeaResponse[Type[PangeaResponseResult]]:
|
96
|
+
async def get(self, path: str, result_class: Type[TResult], check_response: bool = True) -> PangeaResponse[TResult]:
|
96
97
|
"""Makes the GET call to a Pangea Service endpoint.
|
97
98
|
|
98
99
|
Args:
|
@@ -109,7 +110,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
109
110
|
|
110
111
|
async with self.session.get(url, headers=self._headers()) as requests_response:
|
111
112
|
await self._check_http_errors(requests_response)
|
112
|
-
pangea_response = PangeaResponse(
|
113
|
+
pangea_response = PangeaResponse(
|
113
114
|
requests_response, result_class=result_class, json=await requests_response.json()
|
114
115
|
)
|
115
116
|
|
@@ -130,11 +131,11 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
130
131
|
raise pe.ServiceTemporarilyUnavailable(await resp.json())
|
131
132
|
|
132
133
|
async def poll_result_by_id(
|
133
|
-
self, request_id: str, result_class:
|
134
|
-
):
|
134
|
+
self, request_id: str, result_class: Type[TResult], check_response: bool = True
|
135
|
+
) -> PangeaResponse[TResult]:
|
135
136
|
path = self._get_poll_path(request_id)
|
136
137
|
self.logger.debug(json.dumps({"service": self.service, "action": "poll_result_once", "url": path}))
|
137
|
-
return await self.get(path, result_class, check_response=check_response)
|
138
|
+
return await self.get(path, result_class, check_response=check_response)
|
138
139
|
|
139
140
|
async def poll_result_once(self, response: PangeaResponse, check_response: bool = True):
|
140
141
|
request_id = response.request_id
|
@@ -324,9 +325,7 @@ class PangeaRequestAsync(PangeaRequestBase):
|
|
324
325
|
# Receive 202
|
325
326
|
return await self._poll_presigned_url(accepted_exception.response)
|
326
327
|
|
327
|
-
async def _poll_presigned_url(
|
328
|
-
self, response: PangeaResponse[Type[PangeaResponseResult]]
|
329
|
-
) -> PangeaResponse[Type[PangeaResponseResult]]:
|
328
|
+
async def _poll_presigned_url(self, response: PangeaResponse[TResult]) -> PangeaResponse[TResult]:
|
330
329
|
if response.http_status != 202:
|
331
330
|
raise AttributeError("Response should be 202")
|
332
331
|
|
@@ -1,11 +1,14 @@
|
|
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 Any, Dict, List, Optional, Sequence, Union
|
5
7
|
|
6
8
|
import pangea.exceptions as pexc
|
7
9
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
8
|
-
from pangea.
|
10
|
+
from pangea.config import PangeaConfig
|
11
|
+
from pangea.response import PangeaResponse, PangeaResponseResult
|
9
12
|
from pangea.services.audit.audit import AuditBase
|
10
13
|
from pangea.services.audit.exceptions import AuditException
|
11
14
|
from pangea.services.audit.models import (
|
@@ -13,6 +16,7 @@ from pangea.services.audit.models import (
|
|
13
16
|
DownloadRequest,
|
14
17
|
DownloadResult,
|
15
18
|
Event,
|
19
|
+
ExportRequest,
|
16
20
|
LogBulkResult,
|
17
21
|
LogResult,
|
18
22
|
PublishedRoot,
|
@@ -56,14 +60,33 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
56
60
|
|
57
61
|
def __init__(
|
58
62
|
self,
|
59
|
-
token,
|
60
|
-
config=None,
|
63
|
+
token: str,
|
64
|
+
config: PangeaConfig | None = None,
|
61
65
|
private_key_file: str = "",
|
62
|
-
public_key_info:
|
63
|
-
tenant_id:
|
64
|
-
logger_name="pangea",
|
65
|
-
config_id:
|
66
|
-
):
|
66
|
+
public_key_info: dict[str, str] = {},
|
67
|
+
tenant_id: str | None = None,
|
68
|
+
logger_name: str = "pangea",
|
69
|
+
config_id: str | None = None,
|
70
|
+
) -> None:
|
71
|
+
"""
|
72
|
+
Audit client
|
73
|
+
|
74
|
+
Initializes a new Audit client.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
token: Pangea API token.
|
78
|
+
config: Configuration.
|
79
|
+
private_key_file: Private key filepath.
|
80
|
+
public_key_info: Public key information.
|
81
|
+
tenant_id: Tenant ID.
|
82
|
+
logger_name: Logger name.
|
83
|
+
config_id: Configuration ID.
|
84
|
+
|
85
|
+
Examples:
|
86
|
+
config = PangeaConfig(domain="pangea_domain")
|
87
|
+
audit = AuditAsync(token="pangea_token", config=config)
|
88
|
+
"""
|
89
|
+
|
67
90
|
# FIXME: Temporary check to deprecate config_id from PangeaConfig.
|
68
91
|
# Delete it when deprecate PangeaConfig.config_id
|
69
92
|
if config_id and config is not None and config.config_id is not None:
|
@@ -402,6 +425,107 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
402
425
|
|
403
426
|
return self.handle_results_response(response, verify_consistency, verify_events)
|
404
427
|
|
428
|
+
async def export(
|
429
|
+
self,
|
430
|
+
*,
|
431
|
+
format: DownloadFormat = DownloadFormat.CSV,
|
432
|
+
start: Optional[datetime.datetime] = None,
|
433
|
+
end: Optional[datetime.datetime] = None,
|
434
|
+
order: Optional[SearchOrder] = None,
|
435
|
+
order_by: Optional[str] = None,
|
436
|
+
verbose: bool = True,
|
437
|
+
) -> PangeaResponse[PangeaResponseResult]:
|
438
|
+
"""
|
439
|
+
Export from the audit log
|
440
|
+
|
441
|
+
Bulk export of data from the Secure Audit Log, with optional filtering.
|
442
|
+
|
443
|
+
OperationId: audit_post_v1_export
|
444
|
+
|
445
|
+
Args:
|
446
|
+
format: Format for the records.
|
447
|
+
start: The start of the time range to perform the search on.
|
448
|
+
end: The end of the time range to perform the search on. If omitted,
|
449
|
+
then all records up to the latest will be searched.
|
450
|
+
order: Specify the sort order of the response.
|
451
|
+
order_by: Name of column to sort the results by.
|
452
|
+
verbose: Whether or not to include the root hash of the tree and the
|
453
|
+
membership proof for each record.
|
454
|
+
|
455
|
+
Raises:
|
456
|
+
AuditException: If an audit based api exception happens
|
457
|
+
PangeaAPIException: If an API Error happens
|
458
|
+
|
459
|
+
Examples:
|
460
|
+
export_res = await audit.export(verbose=False)
|
461
|
+
|
462
|
+
# Export may take several dozens of minutes, so polling for the result
|
463
|
+
# should be done in a loop. That is omitted here for brevity's sake.
|
464
|
+
try:
|
465
|
+
await audit.poll_result(request_id=export_res.request_id)
|
466
|
+
except AcceptedRequestException:
|
467
|
+
# Retry later.
|
468
|
+
|
469
|
+
# Download the result when it's ready.
|
470
|
+
download_res = await audit.download_results(request_id=export_res.request_id)
|
471
|
+
download_res.result.dest_url
|
472
|
+
# => https://pangea-runtime.s3.amazonaws.com/audit/xxxxx/search_results_[...]
|
473
|
+
"""
|
474
|
+
input = ExportRequest(
|
475
|
+
format=format,
|
476
|
+
start=start,
|
477
|
+
end=end,
|
478
|
+
order=order,
|
479
|
+
order_by=order_by,
|
480
|
+
verbose=verbose,
|
481
|
+
)
|
482
|
+
try:
|
483
|
+
return await self.request.post(
|
484
|
+
"v1/export", PangeaResponseResult, data=input.dict(exclude_none=True), poll_result=False
|
485
|
+
)
|
486
|
+
except pexc.AcceptedRequestException as e:
|
487
|
+
return e.response
|
488
|
+
|
489
|
+
async def log_stream(self, data: dict) -> PangeaResponse[PangeaResponseResult]:
|
490
|
+
"""
|
491
|
+
Log streaming endpoint
|
492
|
+
|
493
|
+
This API allows 3rd party vendors (like Auth0) to stream events to this
|
494
|
+
endpoint where the structure of the payload varies across different
|
495
|
+
vendors.
|
496
|
+
|
497
|
+
OperationId: audit_post_v1_log_stream
|
498
|
+
|
499
|
+
Args:
|
500
|
+
data: Event data. The exact schema of this will vary by vendor.
|
501
|
+
|
502
|
+
Raises:
|
503
|
+
AuditException: If an audit based api exception happens
|
504
|
+
PangeaAPIException: If an API Error happens
|
505
|
+
|
506
|
+
Examples:
|
507
|
+
data = {
|
508
|
+
"logs": [
|
509
|
+
{
|
510
|
+
"log_id": "some log ID",
|
511
|
+
"data": {
|
512
|
+
"date": "2024-03-29T17:26:50.193Z",
|
513
|
+
"type": "sapi",
|
514
|
+
"description": "Create a log stream",
|
515
|
+
"client_id": "some client ID",
|
516
|
+
"ip": "127.0.0.1",
|
517
|
+
"user_agent": "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0",
|
518
|
+
"user_id": "some user ID",
|
519
|
+
},
|
520
|
+
}
|
521
|
+
# ...
|
522
|
+
]
|
523
|
+
}
|
524
|
+
|
525
|
+
response = await audit.log_stream(data)
|
526
|
+
"""
|
527
|
+
return await self.request.post("v1/log_stream", PangeaResponseResult, data=data)
|
528
|
+
|
405
529
|
async def root(self, tree_size: Optional[int] = None) -> PangeaResponse[RootResult]:
|
406
530
|
"""
|
407
531
|
Tamperproof verification
|
@@ -427,7 +551,10 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
427
551
|
return await self.request.post("v1/root", RootResult, data=input.dict(exclude_none=True))
|
428
552
|
|
429
553
|
async def download_results(
|
430
|
-
self,
|
554
|
+
self,
|
555
|
+
result_id: Optional[str] = None,
|
556
|
+
format: DownloadFormat = DownloadFormat.CSV,
|
557
|
+
request_id: Optional[str] = None,
|
431
558
|
) -> PangeaResponse[DownloadResult]:
|
432
559
|
"""
|
433
560
|
Download search results
|
@@ -439,6 +566,7 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
439
566
|
Args:
|
440
567
|
result_id: ID returned by the search API.
|
441
568
|
format: Format for the records.
|
569
|
+
request_id: ID returned by the export API.
|
442
570
|
|
443
571
|
Returns:
|
444
572
|
URL where search results can be downloaded.
|
@@ -454,7 +582,10 @@ class AuditAsync(ServiceBaseAsync, AuditBase):
|
|
454
582
|
)
|
455
583
|
"""
|
456
584
|
|
457
|
-
|
585
|
+
if request_id is None and result_id is None:
|
586
|
+
raise ValueError("must pass one of `request_id` or `result_id`")
|
587
|
+
|
588
|
+
input = DownloadRequest(request_id=request_id, result_id=result_id, format=format)
|
458
589
|
return await self.request.post("v1/download_results", DownloadResult, data=input.dict(exclude_none=True))
|
459
590
|
|
460
591
|
async def update_published_roots(self, result: SearchResultOutput):
|
@@ -1,10 +1,12 @@
|
|
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, List, Optional, Union
|
5
6
|
|
6
7
|
import pangea.services.authn.models as m
|
7
8
|
from pangea.asyncio.services.base import ServiceBaseAsync
|
9
|
+
from pangea.config import PangeaConfig
|
8
10
|
from pangea.response import PangeaResponse
|
9
11
|
|
10
12
|
SERVICE_NAME = "authn"
|
@@ -37,10 +39,24 @@ class AuthNAsync(ServiceBaseAsync):
|
|
37
39
|
|
38
40
|
def __init__(
|
39
41
|
self,
|
40
|
-
token,
|
41
|
-
config=None,
|
42
|
-
logger_name="pangea",
|
43
|
-
):
|
42
|
+
token: str,
|
43
|
+
config: PangeaConfig | None = None,
|
44
|
+
logger_name: str = "pangea",
|
45
|
+
) -> None:
|
46
|
+
"""
|
47
|
+
AuthN client
|
48
|
+
|
49
|
+
Initializes a new AuthN client.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
token: Pangea API token.
|
53
|
+
config: Configuration.
|
54
|
+
logger_name: Logger name.
|
55
|
+
|
56
|
+
Examples:
|
57
|
+
config = PangeaConfig(domain="pangea_domain")
|
58
|
+
authn = AuthNAsync(token="pangea_token", config=config)
|
59
|
+
"""
|
44
60
|
super().__init__(token, config, logger_name=logger_name)
|
45
61
|
self.user = AuthNAsync.UserAsync(token, config, logger_name=logger_name)
|
46
62
|
self.flow = AuthNAsync.FlowAsync(token, config, logger_name=logger_name)
|
@@ -53,10 +69,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
53
69
|
|
54
70
|
def __init__(
|
55
71
|
self,
|
56
|
-
token,
|
57
|
-
config=None,
|
58
|
-
logger_name="pangea",
|
59
|
-
):
|
72
|
+
token: str,
|
73
|
+
config: PangeaConfig | None = None,
|
74
|
+
logger_name: str = "pangea",
|
75
|
+
) -> None:
|
60
76
|
super().__init__(token, config, logger_name=logger_name)
|
61
77
|
|
62
78
|
async def invalidate(self, session_id: str) -> PangeaResponse[m.SessionInvalidateResult]:
|
@@ -148,10 +164,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
148
164
|
|
149
165
|
def __init__(
|
150
166
|
self,
|
151
|
-
token,
|
152
|
-
config=None,
|
153
|
-
logger_name="pangea",
|
154
|
-
):
|
167
|
+
token: str,
|
168
|
+
config: PangeaConfig | None = None,
|
169
|
+
logger_name: str = "pangea",
|
170
|
+
) -> None:
|
155
171
|
super().__init__(token, config, logger_name=logger_name)
|
156
172
|
self.session = AuthNAsync.ClientAsync.SessionAsync(token, config, logger_name=logger_name)
|
157
173
|
self.password = AuthNAsync.ClientAsync.PasswordAsync(token, config, logger_name=logger_name)
|
@@ -208,10 +224,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
208
224
|
|
209
225
|
def __init__(
|
210
226
|
self,
|
211
|
-
token,
|
212
|
-
config=None,
|
213
|
-
logger_name="pangea",
|
214
|
-
):
|
227
|
+
token: str,
|
228
|
+
config: PangeaConfig | None = None,
|
229
|
+
logger_name: str = "pangea",
|
230
|
+
) -> None:
|
215
231
|
super().__init__(token, config, logger_name=logger_name)
|
216
232
|
|
217
233
|
async def invalidate(self, token: str, session_id: str) -> PangeaResponse[m.ClientSessionInvalidateResult]:
|
@@ -343,10 +359,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
343
359
|
|
344
360
|
def __init__(
|
345
361
|
self,
|
346
|
-
token,
|
347
|
-
config=None,
|
348
|
-
logger_name="pangea",
|
349
|
-
):
|
362
|
+
token: str,
|
363
|
+
config: PangeaConfig | None = None,
|
364
|
+
logger_name: str = "pangea",
|
365
|
+
) -> None:
|
350
366
|
super().__init__(token, config, logger_name=logger_name)
|
351
367
|
|
352
368
|
async def change(
|
@@ -384,10 +400,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
384
400
|
|
385
401
|
def __init__(
|
386
402
|
self,
|
387
|
-
token,
|
388
|
-
config=None,
|
389
|
-
logger_name="pangea",
|
390
|
-
):
|
403
|
+
token: str,
|
404
|
+
config: PangeaConfig | None = None,
|
405
|
+
logger_name: str = "pangea",
|
406
|
+
) -> None:
|
391
407
|
super().__init__(token, config, logger_name=logger_name)
|
392
408
|
|
393
409
|
async def check(self, token: str) -> PangeaResponse[m.ClientTokenCheckResult]:
|
@@ -421,10 +437,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
421
437
|
|
422
438
|
def __init__(
|
423
439
|
self,
|
424
|
-
token,
|
425
|
-
config=None,
|
426
|
-
logger_name="pangea",
|
427
|
-
):
|
440
|
+
token: str,
|
441
|
+
config: PangeaConfig | None = None,
|
442
|
+
logger_name: str = "pangea",
|
443
|
+
) -> None:
|
428
444
|
super().__init__(token, config, logger_name=logger_name)
|
429
445
|
self.profile = AuthNAsync.UserAsync.ProfileAsync(token, config, logger_name=logger_name)
|
430
446
|
self.authenticators = AuthNAsync.UserAsync.AuthenticatorsAsync(token, config, logger_name=logger_name)
|
@@ -615,10 +631,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
615
631
|
|
616
632
|
def __init__(
|
617
633
|
self,
|
618
|
-
token,
|
619
|
-
config=None,
|
620
|
-
logger_name="pangea",
|
621
|
-
):
|
634
|
+
token: str,
|
635
|
+
config: PangeaConfig | None = None,
|
636
|
+
logger_name: str = "pangea",
|
637
|
+
) -> None:
|
622
638
|
super().__init__(token, config, logger_name=logger_name)
|
623
639
|
|
624
640
|
async def list(
|
@@ -687,10 +703,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
687
703
|
|
688
704
|
def __init__(
|
689
705
|
self,
|
690
|
-
token,
|
691
|
-
config=None,
|
692
|
-
logger_name="pangea",
|
693
|
-
):
|
706
|
+
token: str,
|
707
|
+
config: PangeaConfig | None = None,
|
708
|
+
logger_name: str = "pangea",
|
709
|
+
) -> None:
|
694
710
|
super().__init__(token, config, logger_name=logger_name)
|
695
711
|
|
696
712
|
async def delete(
|
@@ -758,10 +774,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
758
774
|
|
759
775
|
def __init__(
|
760
776
|
self,
|
761
|
-
token,
|
762
|
-
config=None,
|
763
|
-
logger_name="pangea",
|
764
|
-
):
|
777
|
+
token: str,
|
778
|
+
config: PangeaConfig | None = None,
|
779
|
+
logger_name: str = "pangea",
|
780
|
+
) -> None:
|
765
781
|
super().__init__(token, config, logger_name=logger_name)
|
766
782
|
|
767
783
|
async def get(
|
@@ -838,10 +854,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
838
854
|
|
839
855
|
def __init__(
|
840
856
|
self,
|
841
|
-
token,
|
842
|
-
config=None,
|
843
|
-
logger_name="pangea",
|
844
|
-
):
|
857
|
+
token: str,
|
858
|
+
config: PangeaConfig | None = None,
|
859
|
+
logger_name: str = "pangea",
|
860
|
+
) -> None:
|
845
861
|
super().__init__(token, config, logger_name=logger_name)
|
846
862
|
|
847
863
|
async def complete(self, flow_id: str) -> PangeaResponse[m.FlowCompleteResult]:
|
@@ -978,10 +994,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
978
994
|
|
979
995
|
def __init__(
|
980
996
|
self,
|
981
|
-
token,
|
982
|
-
config=None,
|
983
|
-
logger_name="pangea",
|
984
|
-
):
|
997
|
+
token: str,
|
998
|
+
config: PangeaConfig | None = None,
|
999
|
+
logger_name: str = "pangea",
|
1000
|
+
) -> None:
|
985
1001
|
super().__init__(token, config, logger_name=logger_name)
|
986
1002
|
|
987
1003
|
async def create(
|