pangea-sdk 3.8.0__py3-none-any.whl → 3.8.0b2__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/services/base.py CHANGED
@@ -1,40 +1,23 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
3
 
5
4
  import copy
6
5
  import logging
7
6
  from typing import Dict, Optional, Type, Union
8
7
 
9
- from typing_extensions import TypeVar
10
-
11
8
  from pangea.asyncio.request import PangeaRequestAsync
12
9
  from pangea.config import PangeaConfig
13
10
  from pangea.exceptions import AcceptedRequestException
14
11
  from pangea.request import PangeaRequest
15
12
  from pangea.response import AttachedFile, PangeaResponse, PangeaResponseResult
16
13
 
17
- TResult = TypeVar("TResult", bound=PangeaResponseResult, default=PangeaResponseResult)
18
-
19
14
 
20
15
  class ServiceBase(object):
21
16
  service_name: str = "base"
22
17
 
23
18
  def __init__(
24
- self,
25
- token: str,
26
- config: PangeaConfig | None = None,
27
- logger_name: str = "pangea",
28
- config_id: str | None = None,
29
- ) -> None:
30
- """
31
- Initializes a new Pangea service client.
32
-
33
- Args:
34
- token: Pangea API token.
35
- config: Configuration.
36
- logger_name: Logger name.
37
- """
19
+ self, token, config: Optional[PangeaConfig] = None, logger_name: str = "pangea", config_id: Optional[str] = None
20
+ ):
38
21
  if not token:
39
22
  raise Exception("No token provided")
40
23
 
@@ -47,11 +30,11 @@ class ServiceBase(object):
47
30
  self.request.set_extra_headers(extra_headers)
48
31
 
49
32
  @property
50
- def token(self) -> str:
33
+ def token(self):
51
34
  return self._token
52
35
 
53
36
  @token.setter
54
- def token(self, value: str) -> None:
37
+ def token(self, value):
55
38
  self._token = value
56
39
 
57
40
  @property
@@ -72,8 +55,8 @@ class ServiceBase(object):
72
55
  exception: Optional[AcceptedRequestException] = None,
73
56
  response: Optional[PangeaResponse] = None,
74
57
  request_id: Optional[str] = None,
75
- result_class: Type[TResult] = PangeaResponseResult, # type: ignore[assignment]
76
- ) -> PangeaResponse[TResult]:
58
+ result_class: Union[Type[PangeaResponseResult], Type[Dict]] = dict,
59
+ ) -> PangeaResponse:
77
60
  """
78
61
  Poll result
79
62
 
@@ -71,7 +71,6 @@ class FileScan(ServiceBase):
71
71
  """
72
72
 
73
73
  service_name = "file-scan"
74
- version = "v1"
75
74
 
76
75
  def file_scan(
77
76
  self,
pangea/services/intel.py CHANGED
@@ -839,7 +839,7 @@ class IpIntel(ServiceBase):
839
839
 
840
840
  def reputation_bulk(
841
841
  self, ips: List[str], verbose: Optional[bool] = None, raw: Optional[bool] = None, provider: Optional[str] = None
842
- ) -> PangeaResponse[IPReputationBulkResult]:
842
+ ) -> PangeaResponse[IPReputationResult]:
843
843
  """
844
844
  Reputation V2
845
845
 
@@ -1195,7 +1195,7 @@ class UrlIntel(ServiceBase):
1195
1195
  verbose: Optional[bool] = None,
1196
1196
  raw: Optional[bool] = None,
1197
1197
  provider: Optional[str] = None,
1198
- ) -> PangeaResponse[URLReputationBulkResult]:
1198
+ ) -> PangeaResponse[URLReputationResult]:
1199
1199
  """
1200
1200
  Reputation V2
1201
1201
 
pangea/services/redact.py CHANGED
@@ -1,11 +1,9 @@
1
1
  # Copyright 2022 Pangea Cyber Corporation
2
2
  # Author: Pangea Cyber Corporation
3
- from __future__ import annotations
4
3
 
5
4
  import enum
6
5
  from typing import Dict, List, Optional, Union
7
6
 
8
- from pangea.config import PangeaConfig
9
7
  from pangea.response import APIRequestModel, APIResponseModel, PangeaResponse, PangeaResponseResult
10
8
  from pangea.services.base import ServiceBase
11
9
 
@@ -134,24 +132,7 @@ class Redact(ServiceBase):
134
132
 
135
133
  service_name = "redact"
136
134
 
137
- def __init__(
138
- self, token: str, config: PangeaConfig | None = None, logger_name: str = "pangea", config_id: str | None = None
139
- ) -> None:
140
- """
141
- Redact client
142
-
143
- Initializes a new Redact client.
144
-
145
- Args:
146
- token: Pangea API token.
147
- config: Configuration.
148
- logger_name: Logger name.
149
- config_id: Configuration ID.
150
-
151
- Examples:
152
- config = PangeaConfig(domain="pangea_domain")
153
- redact = Redact(token="pangea_token", config=config)
154
- """
135
+ def __init__(self, token, config=None, logger_name="pangea", config_id: Optional[str] = None):
155
136
  super().__init__(token, config, logger_name, config_id=config_id)
156
137
 
157
138
  def redact(
@@ -0,0 +1,275 @@
1
+ # Copyright 2022 Pangea Cyber Corporation
2
+ # Author: Pangea Cyber Corporation
3
+ import io
4
+ from typing import Dict, List, Optional, Tuple
5
+
6
+ from pangea.response import APIRequestModel, PangeaResponse, PangeaResponseResult, TransferMethod
7
+ from pangea.services.base import ServiceBase
8
+ from pangea.utils import FileUploadParams, get_file_upload_params
9
+
10
+
11
+ class SanitizeFile(APIRequestModel):
12
+ scan_provider: Optional[str] = None
13
+ """Provider to use for File Scan."""
14
+
15
+ cdr_provider: Optional[str] = None
16
+ """Provider to use for CDR."""
17
+
18
+
19
+ class SanitizeContent(APIRequestModel):
20
+ url_intel: Optional[bool] = None
21
+ """Perform URL Intel lookup."""
22
+
23
+ url_intel_provider: Optional[str] = None
24
+ """Provider to use for URL Intel."""
25
+
26
+ domain_intel: Optional[bool] = None
27
+ """Perform Domain Intel lookup."""
28
+
29
+ domain_intel_provider: Optional[str] = None
30
+ """Provider to use for Domain Intel lookup."""
31
+
32
+ defang: Optional[bool] = None
33
+ """Defang external links."""
34
+
35
+ defang_threshold: Optional[int] = None
36
+ """Defang risk threshold."""
37
+
38
+ redact: Optional[bool] = None
39
+ """Redact sensitive content."""
40
+
41
+ remove_attachments: Optional[bool] = None
42
+ """Remove file attachments (PDF only)."""
43
+
44
+ remove_interactive: Optional[bool] = None
45
+ """Remove interactive content (PDF only)."""
46
+
47
+
48
+ class SanitizeShareOutput(APIRequestModel):
49
+ enabled: Optional[bool] = None
50
+ """Store Sanitized files to Pangea Secure Share."""
51
+
52
+ output_folder: Optional[str] = None
53
+ """
54
+ Store Sanitized files to this Secure Share folder (will be auto-created if
55
+ it does not exist)
56
+ """
57
+
58
+
59
+ class SanitizeRequest(APIRequestModel):
60
+ transfer_method: TransferMethod = TransferMethod.POST_URL
61
+ source_url: Optional[str] = None
62
+ share_id: Optional[str] = None
63
+ file: Optional[SanitizeFile] = None
64
+ content: Optional[SanitizeContent] = None
65
+ share_output: Optional[SanitizeShareOutput] = None
66
+ size: Optional[int] = None
67
+ crc32c: Optional[str] = None
68
+ sha256: Optional[str] = None
69
+ uploaded_file_name: Optional[str] = None
70
+
71
+
72
+ class DefangData(PangeaResponseResult):
73
+ external_urls_count: Optional[int] = None
74
+ external_domains_count: Optional[int] = None
75
+ defanged_count: Optional[int] = None
76
+ url_intel_summary: Optional[str] = None
77
+ domain_intel_summary: Optional[str] = None
78
+
79
+
80
+ class RedactData(PangeaResponseResult):
81
+ redaction_count: Optional[int] = None
82
+ summary_counts: Dict = {}
83
+
84
+
85
+ class CDR(PangeaResponseResult):
86
+ file_attachments_removed: Optional[int] = None
87
+ interactive_contents_removed: Optional[int] = None
88
+
89
+
90
+ class SanitizeData(PangeaResponseResult):
91
+ defang: Optional[DefangData] = None
92
+ redact: Optional[RedactData] = None
93
+ malicious_file: Optional[bool] = None
94
+ cdr: Optional[CDR] = None
95
+
96
+
97
+ class SanitizeResult(PangeaResponseResult):
98
+ dest_url: Optional[str] = None
99
+ dest_share_id: Optional[str] = None
100
+ data: SanitizeData
101
+ parameters: Dict = {}
102
+
103
+
104
+ class Sanitize(ServiceBase):
105
+ """Sanitize service client.
106
+
107
+ Examples:
108
+ import os
109
+
110
+ # Pangea SDK
111
+ from pangea.config import PangeaConfig
112
+ from pangea.services import Sanitize
113
+
114
+ PANGEA_SANITIZE_TOKEN = os.getenv("PANGEA_SANITIZE_TOKEN")
115
+ config = PangeaConfig(domain="pangea.cloud")
116
+
117
+ sanitize = Sanitize(token=PANGEA_SANITIZE_TOKEN, config=config)
118
+ """
119
+
120
+ service_name = "sanitize"
121
+
122
+ def sanitize(
123
+ self,
124
+ transfer_method: TransferMethod = TransferMethod.POST_URL,
125
+ file_path: Optional[str] = None,
126
+ file: Optional[io.BufferedReader] = None,
127
+ source_url: Optional[str] = None,
128
+ share_id: Optional[str] = None,
129
+ file_scan: Optional[SanitizeFile] = None,
130
+ content: Optional[SanitizeContent] = None,
131
+ share_output: Optional[SanitizeShareOutput] = None,
132
+ size: Optional[int] = None,
133
+ crc32c: Optional[str] = None,
134
+ sha256: Optional[str] = None,
135
+ uploaded_file_name: Optional[str] = None,
136
+ sync_call: bool = True,
137
+ ) -> PangeaResponse[SanitizeResult]:
138
+ """
139
+ Sanitize
140
+
141
+ Apply file sanitization actions according to specified rules.
142
+ [**Beta API**](https://pangea.cloud/docs/sdk/python/#beta-releases).
143
+
144
+ OperationId: sanitize_post_v1beta_sanitize
145
+
146
+ Args:
147
+ transfer_method: The transfer method used to upload the file data.
148
+ file_path: Path to file to sanitize.
149
+ file: File to sanitize.
150
+ source_url: A URL where the file to be sanitized can be downloaded.
151
+ share_id: A Pangea Secure Share ID where the file to be sanitized is stored.
152
+ file_scan: Options for File Scan.
153
+ content: Options for how the file should be sanitized.
154
+ share_output: Integration with Secure Share.
155
+ size: The size (in bytes) of the file. If the upload doesn't match, the call will fail.
156
+ crc32c: The CRC32C hash of the file data, which will be verified by the server if provided.
157
+ sha256: The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided.
158
+ uploaded_file_name: Name of the user-uploaded file, required for `TransferMethod.PUT_URL` and `TransferMethod.POST_URL`.
159
+ sync_call: Whether or not to poll on HTTP/202.
160
+
161
+ Raises:
162
+ PangeaAPIException: If an API error happens.
163
+
164
+ Returns:
165
+ The sanitized file and information on the sanitization that was
166
+ performed.
167
+
168
+ Examples:
169
+ with open("/path/to/file.pdf", "rb") as f:
170
+ response = sanitize.sanitize(
171
+ file=f,
172
+ transfer_method=TransferMethod.POST_URL,
173
+ uploaded_file_name="uploaded_file",
174
+ )
175
+ """
176
+
177
+ if file or file_path:
178
+ if file_path:
179
+ file = open(file_path, "rb")
180
+ if transfer_method == TransferMethod.POST_URL and (sha256 is None or crc32c is None or size is None):
181
+ params = get_file_upload_params(file) # type: ignore[arg-type]
182
+ crc32c = params.crc_hex if crc32c is None else crc32c
183
+ sha256 = params.sha256_hex if sha256 is None else sha256
184
+ size = params.size if size is None else size
185
+ else:
186
+ crc32c, sha256, size = None, None, None
187
+ files: List[Tuple] = [("upload", ("filename", file, "application/octet-stream"))]
188
+ else:
189
+ raise ValueError("Need to set file_path or file arguments")
190
+
191
+ input = SanitizeRequest(
192
+ transfer_method=transfer_method,
193
+ source_url=source_url,
194
+ share_id=share_id,
195
+ file=file_scan,
196
+ content=content,
197
+ share_output=share_output,
198
+ crc32c=crc32c,
199
+ sha256=sha256,
200
+ size=size,
201
+ uploaded_file_name=uploaded_file_name,
202
+ )
203
+ data = input.dict(exclude_none=True)
204
+ response = self.request.post("v1beta/sanitize", SanitizeResult, data=data, files=files, poll_result=sync_call)
205
+ if file_path and file is not None:
206
+ file.close()
207
+ return response
208
+
209
+ def request_upload_url(
210
+ self,
211
+ transfer_method: TransferMethod = TransferMethod.PUT_URL,
212
+ params: Optional[FileUploadParams] = None,
213
+ file_scan: Optional[SanitizeFile] = None,
214
+ content: Optional[SanitizeContent] = None,
215
+ share_output: Optional[SanitizeShareOutput] = None,
216
+ size: Optional[int] = None,
217
+ crc32c: Optional[str] = None,
218
+ sha256: Optional[str] = None,
219
+ uploaded_file_name: Optional[str] = None,
220
+ ) -> PangeaResponse[SanitizeResult]:
221
+ """
222
+ Sanitize via presigned URL
223
+
224
+ Apply file sanitization actions according to specified rules via a
225
+ [presigned URL](https://pangea.cloud/docs/api/presigned-urls).
226
+ [**Beta API**](https://pangea.cloud/docs/sdk/python/#beta-releases).
227
+
228
+ OperationId: sanitize_post_v1beta_sanitize 2
229
+
230
+ Args:
231
+ transfer_method: The transfer method used to upload the file data.
232
+ params: File upload parameters.
233
+ file_scan: Options for File Scan.
234
+ content: Options for how the file should be sanitized.
235
+ share_output: Integration with Secure Share.
236
+ size: The size (in bytes) of the file. If the upload doesn't match, the call will fail.
237
+ crc32c: The CRC32C hash of the file data, which will be verified by the server if provided.
238
+ sha256: The hexadecimal-encoded SHA256 hash of the file data, which will be verified by the server if provided.
239
+ uploaded_file_name: Name of the user-uploaded file, required for `TransferMethod.PUT_URL` and `TransferMethod.POST_URL`.
240
+
241
+ Raises:
242
+ PangeaAPIException: If an API error happens.
243
+
244
+ Returns:
245
+ A presigned URL.
246
+
247
+ Examples:
248
+ presignedUrl = sanitize.request_upload_url(
249
+ transfer_method=TransferMethod.PUT_URL,
250
+ uploaded_file_name="uploaded_file",
251
+ )
252
+
253
+ # Upload file to `presignedUrl.accepted_result.put_url`.
254
+
255
+ # Poll for Sanitize's result.
256
+ response: PangeaResponse[SanitizeResult] = sanitize.poll_result(response=presignedUrl)
257
+ """
258
+
259
+ input = SanitizeRequest(
260
+ transfer_method=transfer_method,
261
+ file=file_scan,
262
+ content=content,
263
+ share_output=share_output,
264
+ crc32c=crc32c,
265
+ sha256=sha256,
266
+ size=size,
267
+ uploaded_file_name=uploaded_file_name,
268
+ )
269
+ if params is not None and (transfer_method == TransferMethod.POST_URL):
270
+ input.crc32c = params.crc_hex
271
+ input.sha256 = params.sha256_hex
272
+ input.size = params.size
273
+
274
+ data = input.dict(exclude_none=True)
275
+ return self.request.request_presigned_url("v1beta/sanitize", SanitizeResult, data=data)
@@ -0,0 +1,170 @@
1
+ import enum
2
+
3
+
4
+ class FileFormat(str, enum.Enum):
5
+ F3G2 = "3G2"
6
+ F3GP = "3GP"
7
+ F3MF = "3MF"
8
+ F7Z = "7Z"
9
+ A = "A"
10
+ AAC = "AAC"
11
+ ACCDB = "ACCDB"
12
+ AIFF = "AIFF"
13
+ AMF = "AMF"
14
+ AMR = "AMR"
15
+ APE = "APE"
16
+ ASF = "ASF"
17
+ ATOM = "ATOM"
18
+ AU = "AU"
19
+ AVI = "AVI"
20
+ AVIF = "AVIF"
21
+ BIN = "BIN"
22
+ BMP = "BMP"
23
+ BPG = "BPG"
24
+ BZ2 = "BZ2"
25
+ CAB = "CAB"
26
+ CLASS = "CLASS"
27
+ CPIO = "CPIO"
28
+ CRX = "CRX"
29
+ CSV = "CSV"
30
+ DAE = "DAE"
31
+ DBF = "DBF"
32
+ DCM = "DCM"
33
+ DEB = "DEB"
34
+ DJVU = "DJVU"
35
+ DLL = "DLL"
36
+ DOC = "DOC"
37
+ DOCX = "DOCX"
38
+ DWG = "DWG"
39
+ EOT = "EOT"
40
+ EPUB = "EPUB"
41
+ EXE = "EXE"
42
+ FDF = "FDF"
43
+ FITS = "FITS"
44
+ FLAC = "FLAC"
45
+ FLV = "FLV"
46
+ GBR = "GBR"
47
+ GEOJSON = "GEOJSON"
48
+ GIF = "GIF"
49
+ GLB = "GLB"
50
+ GML = "GML"
51
+ GPX = "GPX"
52
+ GZ = "GZ"
53
+ HAR = "HAR"
54
+ HDR = "HDR"
55
+ HEIC = "HEIC"
56
+ HEIF = "HEIF"
57
+ HTML = "HTML"
58
+ ICNS = "ICNS"
59
+ ICO = "ICO"
60
+ ICS = "ICS"
61
+ ISO = "ISO"
62
+ JAR = "JAR"
63
+ JP2 = "JP2"
64
+ JPF = "JPF"
65
+ JPG = "JPG"
66
+ JPM = "JPM"
67
+ JS = "JS"
68
+ JSON = "JSON"
69
+ JXL = "JXL"
70
+ JXR = "JXR"
71
+ KML = "KML"
72
+ LIT = "LIT"
73
+ LNK = "LNK"
74
+ LUA = "LUA"
75
+ LZ = "LZ"
76
+ M3U = "M3U"
77
+ M4A = "M4A"
78
+ MACHO = "MACHO"
79
+ MDB = "MDB"
80
+ MIDI = "MIDI"
81
+ MKV = "MKV"
82
+ MOBI = "MOBI"
83
+ MOV = "MOV"
84
+ MP3 = "MP3"
85
+ MP4 = "MP4"
86
+ MPC = "MPC"
87
+ MPEG = "MPEG"
88
+ MQV = "MQV"
89
+ MRC = "MRC"
90
+ MSG = "MSG"
91
+ MSI = "MSI"
92
+ NDJSON = "NDJSON"
93
+ NES = "NES"
94
+ ODC = "ODC"
95
+ ODF = "ODF"
96
+ ODG = "ODG"
97
+ ODP = "ODP"
98
+ ODS = "ODS"
99
+ ODT = "ODT"
100
+ OGA = "OGA"
101
+ OGV = "OGV"
102
+ OTF = "OTF"
103
+ OTG = "OTG"
104
+ OTP = "OTP"
105
+ OTS = "OTS"
106
+ OTT = "OTT"
107
+ OWL = "OWL"
108
+ P7S = "P7S"
109
+ PAT = "PAT"
110
+ PDF = "PDF"
111
+ PHP = "PHP"
112
+ PL = "PL"
113
+ PNG = "PNG"
114
+ PPT = "PPT"
115
+ PPTX = "PPTX"
116
+ PS = "PS"
117
+ PSD = "PSD"
118
+ PUB = "PUB"
119
+ PY = "PY"
120
+ QCP = "QCP"
121
+ RAR = "RAR"
122
+ RMVB = "RMVB"
123
+ RPM = "RPM"
124
+ RSS = "RSS"
125
+ RTF = "RTF"
126
+ SHP = "SHP"
127
+ SHX = "SHX"
128
+ SO = "SO"
129
+ SQLITE = "SQLITE"
130
+ SRT = "SRT"
131
+ SVG = "SVG"
132
+ SWF = "SWF"
133
+ SXC = "SXC"
134
+ TAR = "TAR"
135
+ TCL = "TCL"
136
+ TCX = "TCX"
137
+ TIFF = "TIFF"
138
+ TORRENT = "TORRENT"
139
+ TSV = "TSV"
140
+ TTC = "TTC"
141
+ TTF = "TTF"
142
+ TXT = "TXT"
143
+ VCF = "VCF"
144
+ VOC = "VOC"
145
+ VTT = "VTT"
146
+ WARC = "WARC"
147
+ WASM = "WASM"
148
+ WAV = "WAV"
149
+ WEBM = "WEBM"
150
+ WEBP = "WEBP"
151
+ WOFF = "WOFF"
152
+ WOFF2 = "WOFF2"
153
+ X3D = "X3D"
154
+ XAR = "XAR"
155
+ XCF = "XCF"
156
+ XFDF = "XFDF"
157
+ XLF = "XLF"
158
+ XLS = "XLS"
159
+ XLSX = "XLSX"
160
+ XML = "XML"
161
+ XPM = "XPM"
162
+ XZ = "XZ"
163
+ ZIP = "ZIP"
164
+ ZST = "ZST"
165
+
166
+ def __str__(self):
167
+ return str(self.value)
168
+
169
+ def __repr__(self):
170
+ return str(self.value)