pangea-sdk 3.7.0__py3-none-any.whl → 3.8.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 +123 -32
- pangea/asyncio/services/__init__.py +1 -0
- pangea/asyncio/services/audit.py +236 -21
- pangea/asyncio/services/authn.py +79 -50
- pangea/asyncio/services/authz.py +259 -0
- pangea/asyncio/services/base.py +9 -6
- pangea/asyncio/services/file_scan.py +3 -4
- pangea/asyncio/services/intel.py +5 -6
- pangea/asyncio/services/redact.py +21 -3
- pangea/asyncio/services/vault.py +28 -12
- pangea/config.py +10 -18
- pangea/dump_audit.py +1 -0
- pangea/exceptions.py +8 -0
- pangea/request.py +164 -74
- pangea/response.py +63 -17
- pangea/services/__init__.py +1 -0
- pangea/services/audit/audit.py +241 -55
- pangea/services/audit/exceptions.py +1 -2
- pangea/services/audit/models.py +83 -21
- pangea/services/audit/signing.py +1 -0
- pangea/services/audit/util.py +1 -0
- pangea/services/authn/authn.py +38 -4
- pangea/services/authn/models.py +9 -9
- pangea/services/authz.py +377 -0
- pangea/services/base.py +34 -14
- pangea/services/embargo.py +1 -2
- pangea/services/file_scan.py +3 -4
- pangea/services/intel.py +3 -4
- pangea/services/redact.py +21 -3
- pangea/services/vault/vault.py +29 -12
- pangea/utils.py +2 -3
- {pangea_sdk-3.7.0.dist-info → pangea_sdk-3.8.0.dist-info}/METADATA +33 -6
- pangea_sdk-3.8.0.dist-info/RECORD +46 -0
- pangea_sdk-3.7.0.dist-info/RECORD +0 -44
- {pangea_sdk-3.7.0.dist-info → pangea_sdk-3.8.0.dist-info}/WHEEL +0 -0
pangea/asyncio/services/authn.py
CHANGED
@@ -1,13 +1,14 @@
|
|
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
|
8
|
+
from pangea.asyncio.services.base import ServiceBaseAsync
|
9
|
+
from pangea.config import PangeaConfig
|
7
10
|
from pangea.response import PangeaResponse
|
8
11
|
|
9
|
-
from .base import ServiceBaseAsync
|
10
|
-
|
11
12
|
SERVICE_NAME = "authn"
|
12
13
|
|
13
14
|
|
@@ -38,10 +39,24 @@ class AuthNAsync(ServiceBaseAsync):
|
|
38
39
|
|
39
40
|
def __init__(
|
40
41
|
self,
|
41
|
-
token,
|
42
|
-
config=None,
|
43
|
-
logger_name="pangea",
|
44
|
-
):
|
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
|
+
"""
|
45
60
|
super().__init__(token, config, logger_name=logger_name)
|
46
61
|
self.user = AuthNAsync.UserAsync(token, config, logger_name=logger_name)
|
47
62
|
self.flow = AuthNAsync.FlowAsync(token, config, logger_name=logger_name)
|
@@ -54,10 +69,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
54
69
|
|
55
70
|
def __init__(
|
56
71
|
self,
|
57
|
-
token,
|
58
|
-
config=None,
|
59
|
-
logger_name="pangea",
|
60
|
-
):
|
72
|
+
token: str,
|
73
|
+
config: PangeaConfig | None = None,
|
74
|
+
logger_name: str = "pangea",
|
75
|
+
) -> None:
|
61
76
|
super().__init__(token, config, logger_name=logger_name)
|
62
77
|
|
63
78
|
async def invalidate(self, session_id: str) -> PangeaResponse[m.SessionInvalidateResult]:
|
@@ -114,6 +129,9 @@ class AuthNAsync(ServiceBaseAsync):
|
|
114
129
|
Examples:
|
115
130
|
response = authn.session.list()
|
116
131
|
"""
|
132
|
+
if isinstance(filter, dict):
|
133
|
+
filter = m.SessionListFilter(**filter)
|
134
|
+
|
117
135
|
input = m.SessionListRequest(filter=filter, last=last, order=order, order_by=order_by, size=size)
|
118
136
|
return await self.request.post("v2/session/list", m.SessionListResults, data=input.dict(exclude_none=True))
|
119
137
|
|
@@ -146,10 +164,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
146
164
|
|
147
165
|
def __init__(
|
148
166
|
self,
|
149
|
-
token,
|
150
|
-
config=None,
|
151
|
-
logger_name="pangea",
|
152
|
-
):
|
167
|
+
token: str,
|
168
|
+
config: PangeaConfig | None = None,
|
169
|
+
logger_name: str = "pangea",
|
170
|
+
) -> None:
|
153
171
|
super().__init__(token, config, logger_name=logger_name)
|
154
172
|
self.session = AuthNAsync.ClientAsync.SessionAsync(token, config, logger_name=logger_name)
|
155
173
|
self.password = AuthNAsync.ClientAsync.PasswordAsync(token, config, logger_name=logger_name)
|
@@ -206,10 +224,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
206
224
|
|
207
225
|
def __init__(
|
208
226
|
self,
|
209
|
-
token,
|
210
|
-
config=None,
|
211
|
-
logger_name="pangea",
|
212
|
-
):
|
227
|
+
token: str,
|
228
|
+
config: PangeaConfig | None = None,
|
229
|
+
logger_name: str = "pangea",
|
230
|
+
) -> None:
|
213
231
|
super().__init__(token, config, logger_name=logger_name)
|
214
232
|
|
215
233
|
async def invalidate(self, token: str, session_id: str) -> PangeaResponse[m.ClientSessionInvalidateResult]:
|
@@ -272,6 +290,9 @@ class AuthNAsync(ServiceBaseAsync):
|
|
272
290
|
token="ptu_wuk7tvtpswyjtlsx52b7yyi2l7zotv4a",
|
273
291
|
)
|
274
292
|
"""
|
293
|
+
if isinstance(filter, dict):
|
294
|
+
filter = m.SessionListFilter(**filter)
|
295
|
+
|
275
296
|
input = m.ClientSessionListRequest(
|
276
297
|
token=token, filter=filter, last=last, order=order, order_by=order_by, size=size
|
277
298
|
)
|
@@ -338,10 +359,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
338
359
|
|
339
360
|
def __init__(
|
340
361
|
self,
|
341
|
-
token,
|
342
|
-
config=None,
|
343
|
-
logger_name="pangea",
|
344
|
-
):
|
362
|
+
token: str,
|
363
|
+
config: PangeaConfig | None = None,
|
364
|
+
logger_name: str = "pangea",
|
365
|
+
) -> None:
|
345
366
|
super().__init__(token, config, logger_name=logger_name)
|
346
367
|
|
347
368
|
async def change(
|
@@ -379,10 +400,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
379
400
|
|
380
401
|
def __init__(
|
381
402
|
self,
|
382
|
-
token,
|
383
|
-
config=None,
|
384
|
-
logger_name="pangea",
|
385
|
-
):
|
403
|
+
token: str,
|
404
|
+
config: PangeaConfig | None = None,
|
405
|
+
logger_name: str = "pangea",
|
406
|
+
) -> None:
|
386
407
|
super().__init__(token, config, logger_name=logger_name)
|
387
408
|
|
388
409
|
async def check(self, token: str) -> PangeaResponse[m.ClientTokenCheckResult]:
|
@@ -416,10 +437,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
416
437
|
|
417
438
|
def __init__(
|
418
439
|
self,
|
419
|
-
token,
|
420
|
-
config=None,
|
421
|
-
logger_name="pangea",
|
422
|
-
):
|
440
|
+
token: str,
|
441
|
+
config: PangeaConfig | None = None,
|
442
|
+
logger_name: str = "pangea",
|
443
|
+
) -> None:
|
423
444
|
super().__init__(token, config, logger_name=logger_name)
|
424
445
|
self.profile = AuthNAsync.UserAsync.ProfileAsync(token, config, logger_name=logger_name)
|
425
446
|
self.authenticators = AuthNAsync.UserAsync.AuthenticatorsAsync(token, config, logger_name=logger_name)
|
@@ -593,6 +614,9 @@ class AuthNAsync(ServiceBaseAsync):
|
|
593
614
|
Examples:
|
594
615
|
response = authn.user.list()
|
595
616
|
"""
|
617
|
+
if isinstance(filter, dict):
|
618
|
+
filter = m.UserListFilter(**filter)
|
619
|
+
|
596
620
|
input = m.UserListRequest(
|
597
621
|
filter=filter,
|
598
622
|
last=last,
|
@@ -607,10 +631,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
607
631
|
|
608
632
|
def __init__(
|
609
633
|
self,
|
610
|
-
token,
|
611
|
-
config=None,
|
612
|
-
logger_name="pangea",
|
613
|
-
):
|
634
|
+
token: str,
|
635
|
+
config: PangeaConfig | None = None,
|
636
|
+
logger_name: str = "pangea",
|
637
|
+
) -> None:
|
614
638
|
super().__init__(token, config, logger_name=logger_name)
|
615
639
|
|
616
640
|
async def list(
|
@@ -642,6 +666,9 @@ class AuthNAsync(ServiceBaseAsync):
|
|
642
666
|
Examples:
|
643
667
|
response = authn.user.invites.list()
|
644
668
|
"""
|
669
|
+
if isinstance(filter, dict):
|
670
|
+
filter = m.UserInviteListFilter(**filter)
|
671
|
+
|
645
672
|
input = m.UserInviteListRequest(filter=filter, last=last, order=order, order_by=order_by, size=size)
|
646
673
|
return await self.request.post(
|
647
674
|
"v2/user/invite/list", m.UserInviteListResult, data=input.dict(exclude_none=True)
|
@@ -676,10 +703,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
676
703
|
|
677
704
|
def __init__(
|
678
705
|
self,
|
679
|
-
token,
|
680
|
-
config=None,
|
681
|
-
logger_name="pangea",
|
682
|
-
):
|
706
|
+
token: str,
|
707
|
+
config: PangeaConfig | None = None,
|
708
|
+
logger_name: str = "pangea",
|
709
|
+
) -> None:
|
683
710
|
super().__init__(token, config, logger_name=logger_name)
|
684
711
|
|
685
712
|
async def delete(
|
@@ -747,10 +774,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
747
774
|
|
748
775
|
def __init__(
|
749
776
|
self,
|
750
|
-
token,
|
751
|
-
config=None,
|
752
|
-
logger_name="pangea",
|
753
|
-
):
|
777
|
+
token: str,
|
778
|
+
config: PangeaConfig | None = None,
|
779
|
+
logger_name: str = "pangea",
|
780
|
+
) -> None:
|
754
781
|
super().__init__(token, config, logger_name=logger_name)
|
755
782
|
|
756
783
|
async def get(
|
@@ -827,10 +854,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
827
854
|
|
828
855
|
def __init__(
|
829
856
|
self,
|
830
|
-
token,
|
831
|
-
config=None,
|
832
|
-
logger_name="pangea",
|
833
|
-
):
|
857
|
+
token: str,
|
858
|
+
config: PangeaConfig | None = None,
|
859
|
+
logger_name: str = "pangea",
|
860
|
+
) -> None:
|
834
861
|
super().__init__(token, config, logger_name=logger_name)
|
835
862
|
|
836
863
|
async def complete(self, flow_id: str) -> PangeaResponse[m.FlowCompleteResult]:
|
@@ -967,10 +994,10 @@ class AuthNAsync(ServiceBaseAsync):
|
|
967
994
|
|
968
995
|
def __init__(
|
969
996
|
self,
|
970
|
-
token,
|
971
|
-
config=None,
|
972
|
-
logger_name="pangea",
|
973
|
-
):
|
997
|
+
token: str,
|
998
|
+
config: PangeaConfig | None = None,
|
999
|
+
logger_name: str = "pangea",
|
1000
|
+
) -> None:
|
974
1001
|
super().__init__(token, config, logger_name=logger_name)
|
975
1002
|
|
976
1003
|
async def create(
|
@@ -1064,6 +1091,8 @@ class AuthNAsync(ServiceBaseAsync):
|
|
1064
1091
|
Examples:
|
1065
1092
|
response = authn.agreements.list()
|
1066
1093
|
"""
|
1094
|
+
if isinstance(filter, dict):
|
1095
|
+
filter = m.AgreementListFilter(**filter)
|
1067
1096
|
|
1068
1097
|
input = m.AgreementListRequest(filter=filter, last=last, order=order, order_by=order_by, size=size)
|
1069
1098
|
return await self.request.post(
|
@@ -0,0 +1,259 @@
|
|
1
|
+
# Copyright 2022 Pangea Cyber Corporation
|
2
|
+
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
from typing import Dict, List, Optional, Union
|
5
|
+
|
6
|
+
from pangea.asyncio.services.base import ServiceBaseAsync
|
7
|
+
from pangea.response import PangeaResponse
|
8
|
+
from pangea.services.authz import (
|
9
|
+
CheckRequest,
|
10
|
+
CheckResult,
|
11
|
+
ItemOrder,
|
12
|
+
ListResourcesRequest,
|
13
|
+
ListResourcesResult,
|
14
|
+
ListSubjectsRequest,
|
15
|
+
ListSubjectsResult,
|
16
|
+
Resource,
|
17
|
+
Subject,
|
18
|
+
Tuple,
|
19
|
+
TupleCreateRequest,
|
20
|
+
TupleCreateResult,
|
21
|
+
TupleDeleteRequest,
|
22
|
+
TupleDeleteResult,
|
23
|
+
TupleListFilter,
|
24
|
+
TupleListRequest,
|
25
|
+
TupleListResult,
|
26
|
+
TupleOrderBy,
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
class AuthZAsync(ServiceBaseAsync):
|
31
|
+
"""AuthZ service client. (Beta)
|
32
|
+
|
33
|
+
Provides methods to interact with the Pangea AuthZ Service.
|
34
|
+
Documentation for the AuthZ Service API can be found at
|
35
|
+
<https://pangea.cloud/docs/api/authz>. Note that this service is in Beta and
|
36
|
+
is subject to change.
|
37
|
+
|
38
|
+
Examples:
|
39
|
+
import os
|
40
|
+
from pangea.config import PangeaConfig
|
41
|
+
from pangea.services import AuthZ
|
42
|
+
|
43
|
+
PANGEA_TOKEN = os.getenv("PANGEA_AUTHZ_TOKEN")
|
44
|
+
|
45
|
+
authz_config = PangeaConfig(domain="aws.us.pangea.cloud")
|
46
|
+
|
47
|
+
# Setup Pangea AuthZ service client
|
48
|
+
authz = AuthZAsync(token=PANGEA_TOKEN, config=authz_config)
|
49
|
+
"""
|
50
|
+
|
51
|
+
service_name = "authz"
|
52
|
+
|
53
|
+
def __init__(self, token: str, config=None, logger_name="pangea", config_id: Optional[str] = None):
|
54
|
+
super().__init__(token, config, logger_name, config_id=config_id)
|
55
|
+
|
56
|
+
async def tuple_create(self, tuples: List[Tuple]) -> PangeaResponse[TupleCreateResult]:
|
57
|
+
"""Create tuples. (Beta)
|
58
|
+
|
59
|
+
Create tuples in the AuthZ Service. The request will fail if there is no schema
|
60
|
+
or the tuples do not validate against the schema.
|
61
|
+
How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
|
62
|
+
|
63
|
+
Args:
|
64
|
+
tuples (List[Tuple]): List of tuples to be created.
|
65
|
+
|
66
|
+
Raises:
|
67
|
+
PangeaAPIException: If an API Error happens.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
Pangea Response with empty result.
|
71
|
+
Available response fields can be found in our
|
72
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/create).
|
73
|
+
|
74
|
+
Examples:
|
75
|
+
await authz.tuple_create(
|
76
|
+
tuples=[
|
77
|
+
Tuple(
|
78
|
+
resource=Resource(type="file", id="file_1"),
|
79
|
+
relation="owner",
|
80
|
+
subject=Subject(type="user", id="user_1"),
|
81
|
+
)
|
82
|
+
]
|
83
|
+
)
|
84
|
+
"""
|
85
|
+
|
86
|
+
input_data = TupleCreateRequest(tuples=tuples)
|
87
|
+
return await self.request.post("v1/tuple/create", TupleCreateResult, data=input_data.dict(exclude_none=True))
|
88
|
+
|
89
|
+
async def tuple_list(
|
90
|
+
self,
|
91
|
+
filter: TupleListFilter,
|
92
|
+
size: Optional[int] = None,
|
93
|
+
last: Optional[str] = None,
|
94
|
+
order: Optional[ItemOrder] = None,
|
95
|
+
order_by: Optional[TupleOrderBy] = None,
|
96
|
+
) -> PangeaResponse[TupleListResult]:
|
97
|
+
"""List tuples. (Beta)
|
98
|
+
|
99
|
+
Return a paginated list of filtered tuples. The filter is given in terms
|
100
|
+
of a tuple. Fill out the fields that you want to filter. If the filter
|
101
|
+
is empty it will return all the tuples.
|
102
|
+
How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
|
103
|
+
|
104
|
+
Args:
|
105
|
+
filter (TupleListFilter): The filter for listing tuples.
|
106
|
+
size (Optional[int]): The size of the result set. Default is None.
|
107
|
+
last (Optional[str]): The last token from a previous response. Default is None.
|
108
|
+
order (Optional[ItemOrder]): Order results asc(ending) or desc(ending).
|
109
|
+
order_by (Optional[TupleOrderBy]): Which field to order results by.
|
110
|
+
|
111
|
+
Raises:
|
112
|
+
PangeaAPIException: If an API Error happens.
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
Pangea Response with a list of tuples and the last token.
|
116
|
+
Available response fields can be found in our
|
117
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/list).
|
118
|
+
|
119
|
+
Examples:
|
120
|
+
await authz.tuple_list(TupleListFilter(subject_type="user", subject_id="user_1"))
|
121
|
+
"""
|
122
|
+
input_data = TupleListRequest(
|
123
|
+
filter=filter.dict(exclude_none=True), size=size, last=last, order=order, order_by=order_by
|
124
|
+
)
|
125
|
+
return await self.request.post("v1/tuple/list", TupleListResult, data=input_data.dict(exclude_none=True))
|
126
|
+
|
127
|
+
async def tuple_delete(self, tuples: List[Tuple]) -> PangeaResponse[TupleDeleteResult]:
|
128
|
+
"""Delete tuples. (Beta)
|
129
|
+
|
130
|
+
Delete tuples in the AuthZ Service.
|
131
|
+
How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
|
132
|
+
|
133
|
+
Args:
|
134
|
+
tuples (List[Tuple]): List of tuples to be deleted.
|
135
|
+
|
136
|
+
Raises:
|
137
|
+
PangeaAPIException: If an API Error happens.
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
Pangea Response with empty result.
|
141
|
+
Available response fields can be found in our
|
142
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/delete).
|
143
|
+
|
144
|
+
Examples:
|
145
|
+
await authz.tuple_delete(
|
146
|
+
tuples=[
|
147
|
+
Tuple(
|
148
|
+
resource=Resource(type="file", id="file_1"),
|
149
|
+
relation="owner",
|
150
|
+
subject=Subject(type="user", id="user_1"),
|
151
|
+
)
|
152
|
+
]
|
153
|
+
)
|
154
|
+
"""
|
155
|
+
|
156
|
+
input_data = TupleDeleteRequest(tuples=tuples)
|
157
|
+
return await self.request.post("v1/tuple/delete", TupleDeleteResult, data=input_data.dict(exclude_none=True))
|
158
|
+
|
159
|
+
async def check(
|
160
|
+
self,
|
161
|
+
resource: Resource,
|
162
|
+
action: str,
|
163
|
+
subject: Subject,
|
164
|
+
debug: Optional[bool] = None,
|
165
|
+
attributes: Optional[Dict[str, Union[int, str]]] = None,
|
166
|
+
) -> PangeaResponse[CheckResult]:
|
167
|
+
"""Perform a check request. (Beta)
|
168
|
+
|
169
|
+
Check if a subject has permission to perform an action on the resource.
|
170
|
+
How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
|
171
|
+
|
172
|
+
Args:
|
173
|
+
resource (Resource): The resource to check.
|
174
|
+
action (str): The action to check.
|
175
|
+
subject (Subject): The subject to check.
|
176
|
+
debug (Optional[bool]): Setting this value to True will provide a detailed analysis of the check.
|
177
|
+
attributes (Optional[Dict[str, Union[int, str]]]): Additional attributes for the check.
|
178
|
+
|
179
|
+
Raises:
|
180
|
+
PangeaAPIException: If an API Error happens.
|
181
|
+
|
182
|
+
Returns:
|
183
|
+
Pangea Response with the result of the check.
|
184
|
+
Available response fields can be found in our
|
185
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/check).
|
186
|
+
|
187
|
+
Examples:
|
188
|
+
await authz.check(
|
189
|
+
resource=Resource(type="file", id="file_1"),
|
190
|
+
action="update",
|
191
|
+
subject=Subject(type="user", id="user_1"),
|
192
|
+
debug=True,
|
193
|
+
)
|
194
|
+
"""
|
195
|
+
|
196
|
+
input_data = CheckRequest(resource=resource, action=action, subject=subject, debug=debug, attributes=attributes)
|
197
|
+
return await self.request.post("v1/check", CheckResult, data=input_data.dict(exclude_none=True))
|
198
|
+
|
199
|
+
async def list_resources(self, type: str, action: str, subject: Subject) -> PangeaResponse[ListResourcesResult]:
|
200
|
+
"""List resources. (Beta)
|
201
|
+
|
202
|
+
Given a type, action, and subject, list all the resources in the
|
203
|
+
type that the subject has access to the action with.
|
204
|
+
How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
|
205
|
+
|
206
|
+
Args:
|
207
|
+
type (str): The type to filter resources.
|
208
|
+
action (str): The action to filter resources.
|
209
|
+
subject (Subject): The subject to filter resources.
|
210
|
+
|
211
|
+
Raises:
|
212
|
+
PangeaAPIException: If an API Error happens.
|
213
|
+
|
214
|
+
Returns:
|
215
|
+
Pangea Response with a list of resource IDs.
|
216
|
+
Available response fields can be found in our
|
217
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-resources).
|
218
|
+
|
219
|
+
Examples:
|
220
|
+
await authz.list_resources(
|
221
|
+
type="file",
|
222
|
+
action="update",
|
223
|
+
subject=Subject(type="user", id="user_1"),
|
224
|
+
)
|
225
|
+
"""
|
226
|
+
|
227
|
+
input_data = ListResourcesRequest(type=type, action=action, subject=subject)
|
228
|
+
return await self.request.post(
|
229
|
+
"v1/list-resources", ListResourcesResult, data=input_data.dict(exclude_none=True)
|
230
|
+
)
|
231
|
+
|
232
|
+
async def list_subjects(self, resource: Resource, action: str) -> PangeaResponse[ListSubjectsResult]:
|
233
|
+
"""List subjects. (Beta)
|
234
|
+
|
235
|
+
Given a resource and an action, return the list of subjects who have
|
236
|
+
access to the action for the given resource.
|
237
|
+
How to install a [Beta release](https://pangea.cloud/docs/sdk/python/#beta-releases).
|
238
|
+
|
239
|
+
Args:
|
240
|
+
resource (Resource): The resource to filter subjects.
|
241
|
+
action (str): The action to filter subjects.
|
242
|
+
|
243
|
+
Raises:
|
244
|
+
PangeaAPIException: If an API Error happens.
|
245
|
+
|
246
|
+
Returns:
|
247
|
+
Pangea Response with a list of subjects.
|
248
|
+
Available response fields can be found in our
|
249
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-subjects).
|
250
|
+
|
251
|
+
Examples:
|
252
|
+
await authz.list_subjects(
|
253
|
+
resource=Resource(type="file", id="file_1"),
|
254
|
+
action="update",
|
255
|
+
)
|
256
|
+
"""
|
257
|
+
|
258
|
+
input_data = ListSubjectsRequest(resource=resource, action=action)
|
259
|
+
return await self.request.post("v1/list-subjects", ListSubjectsResult, data=input_data.dict(exclude_none=True))
|
pangea/asyncio/services/base.py
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
3
|
|
4
|
-
from typing import Optional, Type, Union
|
4
|
+
from typing import Dict, Optional, Type, Union
|
5
5
|
|
6
6
|
from pangea.asyncio.request import PangeaRequestAsync
|
7
7
|
from pangea.exceptions import AcceptedRequestException
|
8
|
-
from pangea.response import PangeaResponse, PangeaResponseResult
|
9
|
-
from pangea.services.base import ServiceBase
|
8
|
+
from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
|
9
|
+
from pangea.services.base import PangeaRequest, ServiceBase
|
10
10
|
|
11
11
|
|
12
12
|
class ServiceBaseAsync(ServiceBase):
|
13
13
|
@property
|
14
|
-
def request(self):
|
15
|
-
if
|
14
|
+
def request(self) -> PangeaRequestAsync: # type: ignore[override]
|
15
|
+
if self._request is None or isinstance(self._request, PangeaRequest):
|
16
16
|
self._request = PangeaRequestAsync(
|
17
17
|
config=self.config,
|
18
18
|
token=self.token,
|
@@ -28,7 +28,7 @@ class ServiceBaseAsync(ServiceBase):
|
|
28
28
|
exception: Optional[AcceptedRequestException] = None,
|
29
29
|
response: Optional[PangeaResponse] = None,
|
30
30
|
request_id: Optional[str] = None,
|
31
|
-
result_class: Union[Type[PangeaResponseResult],
|
31
|
+
result_class: Union[Type[PangeaResponseResult], Type[Dict]] = dict,
|
32
32
|
) -> PangeaResponse:
|
33
33
|
"""
|
34
34
|
Poll result
|
@@ -58,6 +58,9 @@ class ServiceBaseAsync(ServiceBase):
|
|
58
58
|
else:
|
59
59
|
raise AttributeError("Need to set exception, response or request_id")
|
60
60
|
|
61
|
+
async def download_file(self, url: str, filename: Optional[str] = None) -> AttachedFile: # type: ignore[override]
|
62
|
+
return await self.request.download_file(url=url, filename=filename)
|
63
|
+
|
61
64
|
async def close(self):
|
62
65
|
await self.request.session.close()
|
63
66
|
# Loop over all attributes to check if they are derived from ServiceBaseAsync and close them
|
@@ -2,16 +2,15 @@
|
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
3
|
import io
|
4
4
|
import logging
|
5
|
-
from typing import Dict, Optional
|
5
|
+
from typing import Dict, List, Optional, Tuple
|
6
6
|
|
7
7
|
import pangea.services.file_scan as m
|
8
8
|
from pangea.asyncio.request import PangeaRequestAsync
|
9
|
+
from pangea.asyncio.services.base import ServiceBaseAsync
|
9
10
|
from pangea.request import PangeaConfig
|
10
11
|
from pangea.response import PangeaResponse, TransferMethod
|
11
12
|
from pangea.utils import FileUploadParams, get_file_upload_params
|
12
13
|
|
13
|
-
from .base import ServiceBaseAsync
|
14
|
-
|
15
14
|
|
16
15
|
class FileScanAsync(ServiceBaseAsync):
|
17
16
|
"""FileScan service client.
|
@@ -96,7 +95,7 @@ class FileScanAsync(ServiceBaseAsync):
|
|
96
95
|
size = params.size
|
97
96
|
else:
|
98
97
|
crc, sha, size = None, None, None
|
99
|
-
files = [("upload", ("filename", file, "application/octet-stream"))]
|
98
|
+
files: List[Tuple] = [("upload", ("filename", file, "application/octet-stream"))]
|
100
99
|
else:
|
101
100
|
raise ValueError("Need to set file_path or file arguments")
|
102
101
|
|
pangea/asyncio/services/intel.py
CHANGED
@@ -4,11 +4,10 @@ import hashlib
|
|
4
4
|
from typing import List, Optional
|
5
5
|
|
6
6
|
import pangea.services.intel as m
|
7
|
+
from pangea.asyncio.services.base import ServiceBaseAsync
|
7
8
|
from pangea.response import PangeaResponse
|
8
9
|
from pangea.utils import hash_256_filepath
|
9
10
|
|
10
|
-
from .base import ServiceBaseAsync
|
11
|
-
|
12
11
|
|
13
12
|
class FileIntelAsync(ServiceBaseAsync):
|
14
13
|
"""File Intel service client
|
@@ -77,7 +76,7 @@ class FileIntelAsync(ServiceBaseAsync):
|
|
77
76
|
provider: Optional[str] = None,
|
78
77
|
verbose: Optional[bool] = None,
|
79
78
|
raw: Optional[bool] = None,
|
80
|
-
) -> PangeaResponse[m.
|
79
|
+
) -> PangeaResponse[m.FileReputationBulkResult]:
|
81
80
|
"""
|
82
81
|
Reputation check
|
83
82
|
|
@@ -183,7 +182,7 @@ class FileIntelAsync(ServiceBaseAsync):
|
|
183
182
|
hash = hash_256_filepath(filepath)
|
184
183
|
hashes.append(hash)
|
185
184
|
|
186
|
-
return await self.hash_reputation_bulk(
|
185
|
+
return await self.hash_reputation_bulk(
|
187
186
|
hashes=hashes, hash_type="sha256", verbose=verbose, raw=raw, provider=provider
|
188
187
|
)
|
189
188
|
|
@@ -252,7 +251,7 @@ class DomainIntelAsync(ServiceBaseAsync):
|
|
252
251
|
verbose: Optional[bool] = None,
|
253
252
|
raw: Optional[bool] = None,
|
254
253
|
provider: Optional[str] = None,
|
255
|
-
) -> PangeaResponse[m.
|
254
|
+
) -> PangeaResponse[m.DomainReputationBulkResult]:
|
256
255
|
"""
|
257
256
|
Reputation
|
258
257
|
|
@@ -374,7 +373,7 @@ class IpIntelAsync(ServiceBaseAsync):
|
|
374
373
|
|
375
374
|
async def reputation_bulk(
|
376
375
|
self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
|
377
|
-
) -> PangeaResponse[m.
|
376
|
+
) -> PangeaResponse[m.IPReputationBulkResult]:
|
378
377
|
"""
|
379
378
|
Reputation
|
380
379
|
|
@@ -1,13 +1,14 @@
|
|
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.redact as m
|
8
|
+
from pangea.asyncio.services.base import ServiceBaseAsync
|
9
|
+
from pangea.config import PangeaConfig
|
7
10
|
from pangea.response import PangeaResponse
|
8
11
|
|
9
|
-
from .base import ServiceBaseAsync
|
10
|
-
|
11
12
|
|
12
13
|
class RedactAsync(ServiceBaseAsync):
|
13
14
|
"""Redact service client.
|
@@ -36,7 +37,24 @@ class RedactAsync(ServiceBaseAsync):
|
|
36
37
|
|
37
38
|
service_name = "redact"
|
38
39
|
|
39
|
-
def __init__(
|
40
|
+
def __init__(
|
41
|
+
self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
|
42
|
+
) -> None:
|
43
|
+
"""
|
44
|
+
Redact client
|
45
|
+
|
46
|
+
Initializes a new Redact client.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
token: Pangea API token.
|
50
|
+
config: Configuration.
|
51
|
+
logger_name: Logger name.
|
52
|
+
|
53
|
+
Examples:
|
54
|
+
config = PangeaConfig(domain="pangea_domain")
|
55
|
+
redact = RedactAsync(token="pangea_token", config=config)
|
56
|
+
"""
|
57
|
+
|
40
58
|
super().__init__(token, config, logger_name, config_id=config_id)
|
41
59
|
|
42
60
|
async def redact(
|