pangea-sdk 6.2.0b1__py3-none-any.whl → 6.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 +9 -1
- pangea/asyncio/__init__.py +1 -0
- pangea/asyncio/file_uploader.py +4 -2
- pangea/asyncio/request.py +70 -169
- pangea/asyncio/services/__init__.py +2 -1
- pangea/asyncio/services/ai_guard.py +9 -12
- pangea/asyncio/services/audit.py +13 -307
- pangea/asyncio/services/authn.py +40 -32
- pangea/asyncio/services/authz.py +51 -17
- pangea/asyncio/services/base.py +4 -0
- pangea/asyncio/services/file_scan.py +8 -2
- pangea/asyncio/services/intel.py +26 -28
- pangea/asyncio/services/redact.py +11 -268
- pangea/asyncio/services/sanitize.py +5 -1
- pangea/asyncio/services/share.py +5 -1
- pangea/asyncio/services/vault.py +71 -55
- pangea/audit_logger.py +3 -1
- pangea/deep_verify.py +13 -13
- pangea/deprecated.py +1 -1
- pangea/dump_audit.py +2 -3
- pangea/exceptions.py +8 -5
- pangea/file_uploader.py +4 -0
- pangea/request.py +80 -200
- pangea/response.py +21 -18
- pangea/services/__init__.py +2 -1
- pangea/services/ai_guard.py +35 -24
- pangea/services/audit/audit.py +17 -314
- pangea/services/audit/models.py +69 -307
- pangea/services/audit/signing.py +1 -1
- pangea/services/audit/util.py +10 -10
- pangea/services/authn/authn.py +39 -31
- pangea/services/authn/models.py +183 -148
- pangea/services/authz.py +108 -60
- pangea/services/base.py +7 -4
- pangea/services/embargo.py +6 -0
- pangea/services/file_scan.py +8 -2
- pangea/services/intel.py +36 -19
- pangea/services/redact.py +14 -476
- pangea/services/sanitize.py +5 -1
- pangea/services/share/share.py +13 -7
- pangea/services/vault/models/asymmetric.py +4 -0
- pangea/services/vault/models/common.py +15 -12
- pangea/services/vault/models/keys.py +4 -9
- pangea/services/vault/models/secret.py +3 -8
- pangea/services/vault/models/symmetric.py +4 -0
- pangea/services/vault/vault.py +69 -59
- pangea/tools.py +13 -9
- pangea/utils.py +3 -5
- pangea/verify_audit.py +23 -27
- {pangea_sdk-6.2.0b1.dist-info → pangea_sdk-6.3.0.dist-info}/METADATA +36 -17
- pangea_sdk-6.3.0.dist-info/RECORD +60 -0
- {pangea_sdk-6.2.0b1.dist-info → pangea_sdk-6.3.0.dist-info}/WHEEL +1 -1
- pangea/asyncio/services/management.py +0 -576
- pangea/services/management.py +0 -720
- pangea_sdk-6.2.0b1.dist-info/RECORD +0 -62
pangea/services/authz.py
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
3
4
|
from __future__ import annotations
|
4
5
|
|
5
6
|
import enum
|
6
|
-
from
|
7
|
+
from collections.abc import Mapping, Sequence
|
8
|
+
from typing import Annotated, Any, Optional, Union
|
9
|
+
|
10
|
+
from pydantic import Field
|
7
11
|
|
8
12
|
from pangea.config import PangeaConfig
|
9
|
-
from pangea.response import APIRequestModel, APIResponseModel, PangeaResponse, PangeaResponseResult
|
13
|
+
from pangea.response import APIRequestModel, APIResponseModel, PangeaDateTime, PangeaResponse, PangeaResponseResult
|
10
14
|
from pangea.services.base import ServiceBase
|
11
15
|
|
12
16
|
|
@@ -43,20 +47,18 @@ class Resource(PangeaResponseResult):
|
|
43
47
|
|
44
48
|
class Subject(PangeaResponseResult):
|
45
49
|
type: str
|
46
|
-
id:
|
47
|
-
action: Optional[str] = None
|
50
|
+
id: Annotated[str, Field(pattern="^([a-zA-Z0-9_][a-zA-Z0-9/|_.@-]*)$")]
|
51
|
+
action: Annotated[Optional[str], Field(pattern="^([a-zA-Z0-9_][a-zA-Z0-9/|_]*)$")] = None
|
48
52
|
|
49
53
|
|
50
54
|
class Tuple(PangeaResponseResult):
|
51
55
|
resource: Resource
|
52
|
-
relation: str
|
56
|
+
relation: Annotated[str, Field(pattern="^([a-zA-Z0-9_][a-zA-Z0-9/|_]*)$")]
|
53
57
|
subject: Subject
|
54
|
-
expires_at: Optional[
|
58
|
+
expires_at: Optional[PangeaDateTime] = None
|
55
59
|
"""A time in ISO-8601 format"""
|
56
|
-
|
57
|
-
|
58
|
-
class TupleCreateRequest(APIRequestModel):
|
59
|
-
tuples: List[Tuple]
|
60
|
+
attributes: Optional[dict[str, Any]] = None
|
61
|
+
"""A JSON object of attribute data."""
|
60
62
|
|
61
63
|
|
62
64
|
class TupleCreateResult(PangeaResponseResult):
|
@@ -66,54 +68,54 @@ class TupleCreateResult(PangeaResponseResult):
|
|
66
68
|
class TupleListFilter(APIRequestModel):
|
67
69
|
resource_type: Optional[str] = None
|
68
70
|
"""Only records where resource type equals this value."""
|
69
|
-
resource_type__contains: Optional[
|
71
|
+
resource_type__contains: Optional[list[str]] = None
|
70
72
|
"""Only records where resource type includes each substring."""
|
71
|
-
resource_type__in: Optional[
|
73
|
+
resource_type__in: Optional[list[str]] = None
|
72
74
|
"""Only records where resource type equals one of the provided substrings."""
|
73
75
|
resource_id: Optional[str] = None
|
74
76
|
"""Only records where resource id equals this value."""
|
75
|
-
resource_id__contains: Optional[
|
77
|
+
resource_id__contains: Optional[list[str]] = None
|
76
78
|
"""Only records where resource id includes each substring."""
|
77
|
-
resource_id__in: Optional[
|
79
|
+
resource_id__in: Optional[list[str]] = None
|
78
80
|
"""Only records where resource id equals one of the provided substrings."""
|
79
81
|
relation: Optional[str] = None
|
80
82
|
"""Only records where relation equals this value."""
|
81
|
-
relation__contains: Optional[
|
83
|
+
relation__contains: Optional[list[str]] = None
|
82
84
|
"""Only records where relation includes each substring."""
|
83
|
-
relation__in: Optional[
|
85
|
+
relation__in: Optional[list[str]] = None
|
84
86
|
"""Only records where relation equals one of the provided substrings."""
|
85
87
|
subject_type: Optional[str] = None
|
86
88
|
"""Only records where subject type equals this value."""
|
87
|
-
subject_type__contains: Optional[
|
89
|
+
subject_type__contains: Optional[list[str]] = None
|
88
90
|
"""Only records where subject type includes each substring."""
|
89
|
-
subject_type__in: Optional[
|
91
|
+
subject_type__in: Optional[list[str]] = None
|
90
92
|
"""Only records where subject type equals one of the provided substrings."""
|
91
93
|
subject_id: Optional[str] = None
|
92
94
|
"""Only records where subject id equals this value."""
|
93
|
-
subject_id__contains: Optional[
|
95
|
+
subject_id__contains: Optional[list[str]] = None
|
94
96
|
"""Only records where subject id includes each substring."""
|
95
|
-
subject_id__in: Optional[
|
97
|
+
subject_id__in: Optional[list[str]] = None
|
96
98
|
"""Only records where subject id equals one of the provided substrings."""
|
97
99
|
subject_action: Optional[str] = None
|
98
100
|
"""Only records where subject action equals this value."""
|
99
|
-
subject_action__contains: Optional[
|
101
|
+
subject_action__contains: Optional[list[str]] = None
|
100
102
|
"""Only records where subject action includes each substring."""
|
101
|
-
subject_action__in: Optional[
|
103
|
+
subject_action__in: Optional[list[str]] = None
|
102
104
|
"""Only records where subject action equals one of the provided substrings."""
|
103
|
-
expires_at: Optional[
|
105
|
+
expires_at: Optional[PangeaDateTime] = None
|
104
106
|
"""Only records where expires_at equals this value."""
|
105
|
-
expires_at__gt: Optional[
|
107
|
+
expires_at__gt: Optional[PangeaDateTime] = None
|
106
108
|
"""Only records where expires_at is greater than this value."""
|
107
|
-
expires_at__gte: Optional[
|
109
|
+
expires_at__gte: Optional[PangeaDateTime] = None
|
108
110
|
"""Only records where expires_at is greater than or equal to this value."""
|
109
|
-
expires_at__lt: Optional[
|
111
|
+
expires_at__lt: Optional[PangeaDateTime] = None
|
110
112
|
"""Only records where expires_at is less than this value."""
|
111
|
-
expires_at__lte: Optional[
|
113
|
+
expires_at__lte: Optional[PangeaDateTime] = None
|
112
114
|
"""Only records where expires_at is less than or equal to this value."""
|
113
115
|
|
114
116
|
|
115
117
|
class TupleListRequest(APIRequestModel):
|
116
|
-
filter: Optional[Union[
|
118
|
+
filter: Optional[Union[dict, TupleListFilter]] = None
|
117
119
|
size: Optional[int] = None
|
118
120
|
last: Optional[str] = None
|
119
121
|
order: Optional[ItemOrder] = None
|
@@ -121,37 +123,27 @@ class TupleListRequest(APIRequestModel):
|
|
121
123
|
|
122
124
|
|
123
125
|
class TupleListResult(PangeaResponseResult):
|
124
|
-
tuples:
|
126
|
+
tuples: list[Tuple]
|
125
127
|
last: str
|
126
128
|
count: int
|
127
129
|
|
128
130
|
|
129
131
|
class TupleDeleteRequest(APIRequestModel):
|
130
|
-
tuples:
|
132
|
+
tuples: list[Tuple]
|
131
133
|
|
132
134
|
|
133
135
|
class TupleDeleteResult(PangeaResponseResult):
|
134
136
|
pass
|
135
137
|
|
136
138
|
|
137
|
-
class CheckRequest(APIRequestModel):
|
138
|
-
resource: Resource
|
139
|
-
action: str
|
140
|
-
subject: Subject
|
141
|
-
debug: Optional[bool] = None
|
142
|
-
"""In the event of an allowed check, return a path that granted access."""
|
143
|
-
attributes: Optional[Dict[str, Any]] = None
|
144
|
-
"""A JSON object of attribute data."""
|
145
|
-
|
146
|
-
|
147
139
|
class DebugPath(APIResponseModel):
|
148
|
-
type: str
|
149
|
-
id: str
|
140
|
+
type: Optional[str] = None
|
141
|
+
id: Optional[str] = None
|
150
142
|
action: Optional[str] = None
|
151
143
|
|
152
144
|
|
153
145
|
class Debug(APIResponseModel):
|
154
|
-
path:
|
146
|
+
path: list[DebugPath]
|
155
147
|
|
156
148
|
|
157
149
|
class CheckResult(PangeaResponseResult):
|
@@ -162,27 +154,47 @@ class CheckResult(PangeaResponseResult):
|
|
162
154
|
debug: Optional[Debug] = None
|
163
155
|
|
164
156
|
|
157
|
+
class BulkCheckRequestItem(APIRequestModel):
|
158
|
+
resource: Resource
|
159
|
+
action: Annotated[str, Field(pattern="^([a-zA-Z0-9_][a-zA-Z0-9/|_]*)$")]
|
160
|
+
subject: Subject
|
161
|
+
|
162
|
+
|
163
|
+
class BulkCheckItemResult(APIResponseModel):
|
164
|
+
checked: str
|
165
|
+
allowed: bool
|
166
|
+
depth: int
|
167
|
+
debug: Optional[Debug] = None
|
168
|
+
|
169
|
+
|
170
|
+
class BulkCheckResult(PangeaResponseResult):
|
171
|
+
schema_id: str
|
172
|
+
schema_version: int
|
173
|
+
allowed: bool
|
174
|
+
results: list[BulkCheckItemResult]
|
175
|
+
|
176
|
+
|
165
177
|
class ListResourcesRequest(APIRequestModel):
|
166
178
|
type: str
|
167
179
|
action: str
|
168
180
|
subject: Subject
|
169
|
-
attributes: Optional[
|
181
|
+
attributes: Optional[dict[str, Any]] = None
|
170
182
|
|
171
183
|
|
172
184
|
class ListResourcesResult(PangeaResponseResult):
|
173
|
-
ids:
|
185
|
+
ids: list[str]
|
174
186
|
|
175
187
|
|
176
188
|
class ListSubjectsRequest(APIRequestModel):
|
177
189
|
resource: Resource
|
178
190
|
action: str
|
179
|
-
attributes: Optional[
|
191
|
+
attributes: Optional[dict[str, Any]] = None
|
180
192
|
debug: Optional[bool] = None
|
181
193
|
"""Return a path for each found subject"""
|
182
194
|
|
183
195
|
|
184
196
|
class ListSubjectsResult(PangeaResponseResult):
|
185
|
-
subjects:
|
197
|
+
subjects: list[Subject]
|
186
198
|
|
187
199
|
|
188
200
|
class AuthZ(ServiceBase):
|
@@ -228,7 +240,7 @@ class AuthZ(ServiceBase):
|
|
228
240
|
|
229
241
|
super().__init__(token, config, logger_name, config_id=config_id)
|
230
242
|
|
231
|
-
def tuple_create(self, tuples:
|
243
|
+
def tuple_create(self, tuples: Sequence[Tuple]) -> PangeaResponse[TupleCreateResult]:
|
232
244
|
"""Create tuples.
|
233
245
|
|
234
246
|
Create tuples in the AuthZ Service. The request will fail if there is no schema
|
@@ -243,7 +255,7 @@ class AuthZ(ServiceBase):
|
|
243
255
|
Returns:
|
244
256
|
Pangea Response with empty result.
|
245
257
|
Available response fields can be found in our
|
246
|
-
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/create).
|
258
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/create-post).
|
247
259
|
|
248
260
|
Examples:
|
249
261
|
response = authz.tuple_create(
|
@@ -257,8 +269,7 @@ class AuthZ(ServiceBase):
|
|
257
269
|
)
|
258
270
|
"""
|
259
271
|
|
260
|
-
|
261
|
-
return self.request.post("v1/tuple/create", TupleCreateResult, data=input_data.model_dump(exclude_none=True))
|
272
|
+
return self.request.post("v1/tuple/create", TupleCreateResult, data={"tuples": tuples})
|
262
273
|
|
263
274
|
def tuple_list(
|
264
275
|
self,
|
@@ -287,7 +298,7 @@ class AuthZ(ServiceBase):
|
|
287
298
|
Returns:
|
288
299
|
Pangea Response with a list of tuples and the last token.
|
289
300
|
Available response fields can be found in our
|
290
|
-
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/list).
|
301
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/list-post).
|
291
302
|
|
292
303
|
Examples:
|
293
304
|
authz.tuple_list(TupleListFilter(subject_type="user", subject_id="user_1"))
|
@@ -311,7 +322,7 @@ class AuthZ(ServiceBase):
|
|
311
322
|
Returns:
|
312
323
|
Pangea Response with empty result.
|
313
324
|
Available response fields can be found in our
|
314
|
-
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/delete).
|
325
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/tuple/delete-post).
|
315
326
|
|
316
327
|
Examples:
|
317
328
|
response = authz.tuple_delete(
|
@@ -333,8 +344,9 @@ class AuthZ(ServiceBase):
|
|
333
344
|
resource: Resource,
|
334
345
|
action: str,
|
335
346
|
subject: Subject,
|
347
|
+
*,
|
336
348
|
debug: bool | None = None,
|
337
|
-
attributes:
|
349
|
+
attributes: Mapping[str, Any] | None = None,
|
338
350
|
) -> PangeaResponse[CheckResult]:
|
339
351
|
"""Perform a check request.
|
340
352
|
|
@@ -345,7 +357,7 @@ class AuthZ(ServiceBase):
|
|
345
357
|
action: The action to check.
|
346
358
|
subject: The subject to check.
|
347
359
|
debug: In the event of an allowed check, return a path that granted access.
|
348
|
-
attributes:
|
360
|
+
attributes: A JSON object of attribute data.
|
349
361
|
|
350
362
|
Raises:
|
351
363
|
PangeaAPIException: If an API Error happens.
|
@@ -353,7 +365,7 @@ class AuthZ(ServiceBase):
|
|
353
365
|
Returns:
|
354
366
|
Pangea Response with the result of the check.
|
355
367
|
Available response fields can be found in our
|
356
|
-
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/check).
|
368
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/check-post).
|
357
369
|
|
358
370
|
Examples:
|
359
371
|
response = authz.check(
|
@@ -364,8 +376,44 @@ class AuthZ(ServiceBase):
|
|
364
376
|
)
|
365
377
|
"""
|
366
378
|
|
367
|
-
|
368
|
-
|
379
|
+
return self.request.post(
|
380
|
+
"v1/check",
|
381
|
+
CheckResult,
|
382
|
+
data={"resource": resource, "action": action, "subject": subject, "debug": debug, "attributes": attributes},
|
383
|
+
)
|
384
|
+
|
385
|
+
def bulk_check(
|
386
|
+
self,
|
387
|
+
checks: Sequence[BulkCheckRequestItem],
|
388
|
+
*,
|
389
|
+
debug: bool | None = None,
|
390
|
+
attributes: Mapping[str, Any] | None = None,
|
391
|
+
) -> PangeaResponse[BulkCheckResult]:
|
392
|
+
"""Perform a bulk check request
|
393
|
+
|
394
|
+
Perform multiple checks in a single request to see if a subjects have
|
395
|
+
permission to do actions on the resources.
|
396
|
+
|
397
|
+
Args:
|
398
|
+
checks: Check requests to perform.
|
399
|
+
debug: In the event of an allowed check, return a path that granted access.
|
400
|
+
attributes: A JSON object of attribute data.
|
401
|
+
|
402
|
+
Examples:
|
403
|
+
authz.bulk_check(
|
404
|
+
checks=[
|
405
|
+
BulkCheckRequestItem(
|
406
|
+
resource=Resource(type="file", id="file_1"),
|
407
|
+
action="read",
|
408
|
+
subject=Subject(type="user", id="user_1", action="read"),
|
409
|
+
)
|
410
|
+
]
|
411
|
+
)
|
412
|
+
"""
|
413
|
+
|
414
|
+
return self.request.post(
|
415
|
+
"v1/check/bulk", BulkCheckResult, data={"checks": checks, "debug": debug, "attributes": attributes}
|
416
|
+
)
|
369
417
|
|
370
418
|
def list_resources(
|
371
419
|
self, type: str, action: str, subject: Subject, attributes: dict[str, Any] | None = None
|
@@ -387,7 +435,7 @@ class AuthZ(ServiceBase):
|
|
387
435
|
Returns:
|
388
436
|
Pangea Response with a list of resource IDs.
|
389
437
|
Available response fields can be found in our
|
390
|
-
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-resources).
|
438
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-resources-post).
|
391
439
|
|
392
440
|
Examples:
|
393
441
|
authz.list_resources(
|
@@ -422,7 +470,7 @@ class AuthZ(ServiceBase):
|
|
422
470
|
Returns:
|
423
471
|
Pangea Response with a list of subjects.
|
424
472
|
Available response fields can be found in our
|
425
|
-
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-subjects).
|
473
|
+
[API Documentation](https://pangea.cloud/docs/api/authz#/v1/list-subjects-post).
|
426
474
|
|
427
475
|
Examples:
|
428
476
|
response = authz.list_subjects(
|
pangea/services/base.py
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
# TODO: Modernize.
|
5
|
+
# ruff: noqa: UP006, UP035
|
6
|
+
|
3
7
|
from __future__ import annotations
|
4
8
|
|
5
9
|
import copy
|
6
10
|
import logging
|
7
|
-
from typing import
|
11
|
+
from typing import Optional, Type, Union
|
8
12
|
|
9
13
|
from typing_extensions import TypeVar
|
10
14
|
|
@@ -17,7 +21,7 @@ from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
|
|
17
21
|
TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
|
18
22
|
|
19
23
|
|
20
|
-
class ServiceBase
|
24
|
+
class ServiceBase:
|
21
25
|
service_name: str = "base"
|
22
26
|
|
23
27
|
def __init__(
|
@@ -43,8 +47,7 @@ class ServiceBase(object):
|
|
43
47
|
self._token = token
|
44
48
|
self.config_id: Optional[str] = config_id
|
45
49
|
self._request: Optional[Union[PangeaRequest, PangeaRequestAsync]] = None
|
46
|
-
|
47
|
-
self.request.set_extra_headers(extra_headers)
|
50
|
+
self.request.set_extra_headers({})
|
48
51
|
|
49
52
|
@property
|
50
53
|
def token(self) -> str:
|
pangea/services/embargo.py
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
# TODO: Use `list` instead of `List`.
|
5
|
+
# ruff: noqa: UP006, UP035
|
6
|
+
|
7
|
+
from __future__ import annotations
|
8
|
+
|
3
9
|
from typing import Any, Dict, List
|
4
10
|
|
5
11
|
from pangea.response import APIRequestModel, APIResponseModel, PangeaResponse, PangeaResponseResult
|
pangea/services/file_scan.py
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
# TODO: Use `list` instead of `List`.
|
5
|
+
# ruff: noqa: UP006, UP035
|
6
|
+
|
7
|
+
from __future__ import annotations
|
8
|
+
|
3
9
|
import io
|
4
10
|
import logging
|
5
11
|
from typing import Dict, List, Optional, Tuple
|
@@ -52,7 +58,7 @@ class FileScan(ServiceBase):
|
|
52
58
|
"""FileScan service client.
|
53
59
|
|
54
60
|
Provides methods to interact with Pangea FileScan Service:
|
55
|
-
https://pangea.cloud/docs/api/
|
61
|
+
https://pangea.cloud/docs/api/file-scan
|
56
62
|
|
57
63
|
The following information is needed:
|
58
64
|
PANGEA_TOKEN - service token which can be found on the Pangea User
|
@@ -133,7 +139,7 @@ class FileScan(ServiceBase):
|
|
133
139
|
files: Optional[List[Tuple]] = None
|
134
140
|
if file or file_path:
|
135
141
|
if file_path:
|
136
|
-
file = open(file_path, "rb")
|
142
|
+
file = open(file_path, "rb") # noqa: SIM115
|
137
143
|
if transfer_method == TransferMethod.POST_URL:
|
138
144
|
params = get_file_upload_params(file) # type: ignore[arg-type]
|
139
145
|
crc = params.crc_hex
|
pangea/services/intel.py
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# Copyright 2022 Pangea Cyber Corporation
|
2
2
|
# Author: Pangea Cyber Corporation
|
3
|
+
|
4
|
+
# TODO: Use `list` instead of `List`.
|
5
|
+
# ruff: noqa: UP006, UP035
|
6
|
+
|
3
7
|
from __future__ import annotations
|
4
8
|
|
5
9
|
import enum
|
6
10
|
import hashlib
|
7
|
-
from typing import Dict, List, Optional
|
11
|
+
from typing import Dict, List, Literal, Optional
|
8
12
|
|
9
13
|
from pangea.exceptions import PangeaException
|
10
14
|
from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult
|
@@ -61,8 +65,20 @@ class FileReputationBulkRequest(APIRequestModel):
|
|
61
65
|
hash_type (str): Type of hash, can be "sha256", "sha" or "md5"
|
62
66
|
"""
|
63
67
|
|
64
|
-
hashes:
|
65
|
-
|
68
|
+
hashes: list[str]
|
69
|
+
"""The hash of the file to be looked up"""
|
70
|
+
|
71
|
+
hash_type: Literal["sha256", "sha", "md5"]
|
72
|
+
"""One of "sha256", "sha", "md5"."""
|
73
|
+
|
74
|
+
verbose: Optional[bool] = None
|
75
|
+
"""Echo the API parameters in the response"""
|
76
|
+
|
77
|
+
raw: Optional[bool] = None
|
78
|
+
"""Include raw data from this provider"""
|
79
|
+
|
80
|
+
provider: Optional[Literal["reversinglabs", "crowdstrike"]] = None
|
81
|
+
"""Use reputation data from this provider"""
|
66
82
|
|
67
83
|
|
68
84
|
class FileReputationData(IntelReputationData):
|
@@ -356,7 +372,8 @@ class DomainWhoIsRequest(DomainCommonRequest):
|
|
356
372
|
Domain whois request data
|
357
373
|
"""
|
358
374
|
|
359
|
-
|
375
|
+
domain: str
|
376
|
+
"""The domain to query."""
|
360
377
|
|
361
378
|
|
362
379
|
class DomainWhoIsData(PangeaResponseResult):
|
@@ -530,11 +547,11 @@ class FileIntel(ServiceBase):
|
|
530
547
|
|
531
548
|
def hash_reputation_bulk(
|
532
549
|
self,
|
533
|
-
hashes:
|
534
|
-
hash_type:
|
535
|
-
provider:
|
536
|
-
verbose:
|
537
|
-
raw:
|
550
|
+
hashes: list[str],
|
551
|
+
hash_type: Literal["sha256", "sha", "md5"],
|
552
|
+
provider: Literal["reversinglabs", "crowdstrike"] | None = None,
|
553
|
+
verbose: bool | None = None,
|
554
|
+
raw: bool | None = None,
|
538
555
|
) -> PangeaResponse[FileReputationBulkResult]:
|
539
556
|
"""
|
540
557
|
Reputation check V2
|
@@ -562,7 +579,7 @@ class FileIntel(ServiceBase):
|
|
562
579
|
provider="reversinglabs",
|
563
580
|
)
|
564
581
|
"""
|
565
|
-
input = FileReputationBulkRequest(
|
582
|
+
input = FileReputationBulkRequest(
|
566
583
|
hashes=hashes, hash_type=hash_type, verbose=verbose, raw=raw, provider=provider
|
567
584
|
)
|
568
585
|
return self.request.post("v2/reputation", FileReputationBulkResult, data=input.model_dump(exclude_none=True))
|
@@ -610,10 +627,10 @@ class FileIntel(ServiceBase):
|
|
610
627
|
|
611
628
|
def filepath_reputation_bulk(
|
612
629
|
self,
|
613
|
-
filepaths:
|
614
|
-
provider:
|
615
|
-
verbose:
|
616
|
-
raw:
|
630
|
+
filepaths: list[str],
|
631
|
+
provider: Literal["reversinglabs", "crowdstrike"] | None = None,
|
632
|
+
verbose: bool | None = None,
|
633
|
+
raw: bool | None = None,
|
617
634
|
) -> PangeaResponse[FileReputationBulkResult]:
|
618
635
|
"""
|
619
636
|
Reputation, from filepath V2
|
@@ -624,10 +641,10 @@ class FileIntel(ServiceBase):
|
|
624
641
|
OperationId: file_intel_post_v2_reputation
|
625
642
|
|
626
643
|
Args:
|
627
|
-
filepaths
|
628
|
-
provider
|
629
|
-
verbose
|
630
|
-
raw
|
644
|
+
filepaths: The path list to the files to be looked up
|
645
|
+
provider: Use reputation data from these providers: "reversinglabs" or "crowdstrike"
|
646
|
+
verbose: Echo the API parameters in the response
|
647
|
+
raw: Include raw data from this provider
|
631
648
|
|
632
649
|
Raises:
|
633
650
|
PangeaAPIException: If an API Error happens
|
@@ -777,7 +794,7 @@ class DomainIntel(ServiceBase):
|
|
777
794
|
provider="whoisxml",
|
778
795
|
)
|
779
796
|
"""
|
780
|
-
input = DomainWhoIsRequest(domain=domain, verbose=verbose, provider=provider, raw=raw)
|
797
|
+
input = DomainWhoIsRequest(domain=domain, verbose=verbose, provider=provider, raw=raw)
|
781
798
|
return self.request.post("v1/whois", DomainWhoIsResult, data=input.model_dump(exclude_none=True))
|
782
799
|
|
783
800
|
|