polyswarm-api 3.8.0__tar.gz → 3.10.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.
- {polyswarm-api-3.8.0/src/polyswarm_api.egg-info → polyswarm-api-3.10.0}/PKG-INFO +1 -1
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/setup.py +1 -1
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api/__init__.py +1 -1
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api/api.py +110 -26
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api/resources.py +52 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0/src/polyswarm_api.egg-info}/PKG-INFO +1 -1
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/LICENSE +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/MANIFEST.in +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/README.md +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/requirements.txt +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/setup.cfg +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api/core.py +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api/exceptions.py +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api/settings.py +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api.egg-info/SOURCES.txt +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api.egg-info/dependency_links.txt +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api.egg-info/requires.txt +0 -0
- {polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api.egg-info/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ with open('README.md', 'r') as readme:
|
|
|
9
9
|
|
|
10
10
|
setup(
|
|
11
11
|
name='polyswarm-api',
|
|
12
|
-
version='3.
|
|
12
|
+
version='3.10.0',
|
|
13
13
|
description='Client library to simplify interacting with the PolySwarm consumer API',
|
|
14
14
|
long_description=long_description,
|
|
15
15
|
long_description_content_type='text/markdown',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import io
|
|
1
2
|
import logging
|
|
2
3
|
import time
|
|
3
4
|
|
|
@@ -217,8 +218,7 @@ class PolyswarmAPI:
|
|
|
217
218
|
artifact_type=resources.ArtifactType.FILE,
|
|
218
219
|
artifact_name=None,
|
|
219
220
|
scan_config=None,
|
|
220
|
-
|
|
221
|
-
zip_password=None,
|
|
221
|
+
preprocessing=None,
|
|
222
222
|
):
|
|
223
223
|
"""
|
|
224
224
|
Submit artifacts to polyswarm
|
|
@@ -227,18 +227,18 @@ class PolyswarmAPI:
|
|
|
227
227
|
:param artifact_type: The ArtifactType or strings containing "file" or "url"
|
|
228
228
|
:param artifact_name: An appropriate filename for the Artifact
|
|
229
229
|
:param scan_config: The scan configuration to be used, e.g.: "default", "more-time", "most-time"
|
|
230
|
-
:param
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
:param preprocessing: Preprocessing settings to be applied to the artifact, None means no preprocessing,
|
|
231
|
+
otherwise a dict with the following attributes can be passed:
|
|
232
|
+
- type (string): either "zip" or "qrcode", the first mean the file is a zip that
|
|
233
|
+
the server has to decompress to then scan the content (only one file inside allowed).
|
|
234
|
+
"qrcode" means the file is a QR Code image with a URL as payload, and you want
|
|
235
|
+
to scan the URL, not the actual file (artifact_type has to be "URL").
|
|
236
|
+
- password (string, optional): will use this password to decompress the zip file.
|
|
234
237
|
:return: An ArtifactInstance resource
|
|
235
238
|
"""
|
|
236
239
|
logger.info('Submitting artifact of type %s', artifact_type)
|
|
237
240
|
artifact_type = resources.ArtifactType.parse(artifact_type)
|
|
238
|
-
|
|
239
|
-
# to isinstance(artifact, io.IOBase) when deprecating 2.7 and implementing making LocalHandle
|
|
240
|
-
# inherit io.IOBase, although this will change the method delegation logic in the resource
|
|
241
|
-
if hasattr(artifact, 'read') and hasattr(artifact.read, '__call__'):
|
|
241
|
+
if isinstance(artifact, io.IOBase):
|
|
242
242
|
artifact = resources.LocalArtifact.from_handle(self, artifact, artifact_name=artifact_name or '',
|
|
243
243
|
artifact_type=artifact_type)
|
|
244
244
|
elif isinstance(artifact, str):
|
|
@@ -246,8 +246,16 @@ class PolyswarmAPI:
|
|
|
246
246
|
artifact = resources.LocalArtifact.from_path(self, artifact, artifact_type=artifact_type,
|
|
247
247
|
artifact_name=artifact_name)
|
|
248
248
|
elif artifact_type == resources.ArtifactType.URL:
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
if preprocessing and preprocessing['type'] == 'qrcode':
|
|
250
|
+
artifact = resources.LocalArtifact.from_path(self,
|
|
251
|
+
artifact,
|
|
252
|
+
artifact_type=artifact_type,
|
|
253
|
+
artifact_name=artifact_name)
|
|
254
|
+
else:
|
|
255
|
+
artifact = resources.LocalArtifact.from_content(self,
|
|
256
|
+
artifact,
|
|
257
|
+
artifact_name=artifact_name or artifact,
|
|
258
|
+
artifact_type=artifact_type)
|
|
251
259
|
if artifact_type == resources.ArtifactType.URL:
|
|
252
260
|
scan_config = scan_config or 'more-time'
|
|
253
261
|
if isinstance(artifact, resources.LocalArtifact):
|
|
@@ -257,8 +265,7 @@ class PolyswarmAPI:
|
|
|
257
265
|
artifact_type=artifact.artifact_type.name,
|
|
258
266
|
scan_config=scan_config,
|
|
259
267
|
community=self.community,
|
|
260
|
-
|
|
261
|
-
zip_password=zip_password,
|
|
268
|
+
preprocessing=preprocessing,
|
|
262
269
|
).result()
|
|
263
270
|
instance.upload_file(artifact)
|
|
264
271
|
return resources.ArtifactInstance.update(self, id=instance.id, community=self.community).result()
|
|
@@ -714,15 +721,35 @@ class PolyswarmAPI:
|
|
|
714
721
|
artifact_type=resources.ArtifactType.FILE,
|
|
715
722
|
artifact_name=None,
|
|
716
723
|
network_enabled=True,
|
|
717
|
-
|
|
718
|
-
zip_password=None,
|
|
724
|
+
preprocessing=None,
|
|
719
725
|
):
|
|
720
|
-
|
|
726
|
+
"""
|
|
727
|
+
Submit artifacts to Polyswarm Sandboxing system.
|
|
728
|
+
|
|
729
|
+
:param artifact: A file-like, path to file, url or LocalArtifact instance
|
|
730
|
+
:param artifact_name: An appropriate filename for the Artifact
|
|
731
|
+
:artifact_type: the type of artifact to be submitted, default FILE. Use URL type
|
|
732
|
+
with the preprocessing field to scan URLs inside QR Code images
|
|
733
|
+
:param network_enabled: Whether the VM has to have Internet connection enabled or not.
|
|
734
|
+
:param provider_slug: the slug of the provider that is going to execute the sandboxing, e.g.
|
|
735
|
+
'cape' or 'triage'.
|
|
736
|
+
Use `sandbox_providers()` to get the list of providers.
|
|
737
|
+
:param vm_slug: The slug of the virtual machine used for the sandboxing, depending on the
|
|
738
|
+
VM chosen is the OS and software that is going to host the sandboxing. Each
|
|
739
|
+
provider (provider_slug) support different VMs, so check with `sandbox_providers()`
|
|
740
|
+
the list of VMs available.
|
|
741
|
+
:param preprocessing: Preprocessing settings to be applied to the artifact, None means no preprocessing,
|
|
742
|
+
otherwise a dict with the following attributes can be passed:
|
|
743
|
+
- type (string): either "zip" or "qrcode", the first mean the file is a zip that
|
|
744
|
+
the server has to decompress to then scan the content (only one file inside allowed).
|
|
745
|
+
"qrcode" means the file is a QR Code image with a URL as payload, and you want
|
|
746
|
+
to scan the URL, not the actual file (artifact_type has to be "URL").
|
|
747
|
+
- password (string, optional): will use this password to decompress the zip file.
|
|
748
|
+
:return: An ArtifactInstance resource
|
|
749
|
+
"""
|
|
750
|
+
logger.info('Sandboxing %s in provider %s vm %s', artifact_type.name.lower(), provider_slug, vm_slug)
|
|
721
751
|
artifact_type = resources.ArtifactType.parse(artifact_type)
|
|
722
|
-
|
|
723
|
-
# to isinstance(artifact, io.IOBase) when deprecating 2.7 and implementing making LocalHandle
|
|
724
|
-
# inherit io.IOBase, although this will change the method delegation logic in the resource
|
|
725
|
-
if hasattr(artifact, 'read') and hasattr(artifact.read, '__call__'):
|
|
752
|
+
if isinstance(artifact, io.IOBase):
|
|
726
753
|
artifact = resources.LocalArtifact.from_handle(self, artifact, artifact_name=artifact_name or '',
|
|
727
754
|
artifact_type=artifact_type)
|
|
728
755
|
elif isinstance(artifact, str):
|
|
@@ -742,8 +769,7 @@ class PolyswarmAPI:
|
|
|
742
769
|
provider_slug=provider_slug,
|
|
743
770
|
vm_slug=vm_slug,
|
|
744
771
|
network_enabled=network_enabled,
|
|
745
|
-
|
|
746
|
-
zip_password=zip_password,
|
|
772
|
+
preprocessing=preprocessing,
|
|
747
773
|
).result()
|
|
748
774
|
task.upload_file(artifact)
|
|
749
775
|
return resources.SandboxTask.update_file(self, id=task.id, community=self.community).result()
|
|
@@ -751,16 +777,68 @@ class PolyswarmAPI:
|
|
|
751
777
|
raise exceptions.InvalidValueException(
|
|
752
778
|
'Artifacts should be a path to a file or a LocalArtifact instance')
|
|
753
779
|
|
|
754
|
-
def sandbox_url(self,
|
|
780
|
+
def sandbox_url(self,
|
|
781
|
+
url,
|
|
782
|
+
provider_slug,
|
|
783
|
+
vm_slug,
|
|
784
|
+
browser=None,
|
|
785
|
+
artifact=None,
|
|
786
|
+
artifact_name=None,
|
|
787
|
+
preprocessing=None):
|
|
788
|
+
"""
|
|
789
|
+
Submit URL to Polyswarm Sandboxing system.
|
|
790
|
+
:param url: A string with the URL to be submitted. Set to `None` if the URL is provided
|
|
791
|
+
through a QR Code image in the artifact param (see artifact and preprocessing params).
|
|
792
|
+
:param provider_slug: the slug of the provider that is going to execute the sandboxing, e.g.
|
|
793
|
+
'cape' or 'triage'.
|
|
794
|
+
Use `sandbox_providers()` to get the list of providers.
|
|
795
|
+
:param vm_slug: The slug of the virtual machine used for the sandboxing, depending on the
|
|
796
|
+
VM chosen is the OS and software that is going to host the sandboxing. Each
|
|
797
|
+
provider (provider_slug) support different VMs, so check with `sandbox_providers()`
|
|
798
|
+
the list of VMs available.
|
|
799
|
+
:param browser: browser name, e.g. 'edge' or 'firefox'.
|
|
800
|
+
:param artifact: A file-like, path to file, or LocalArtifact instance (default None). The url
|
|
801
|
+
param has to be None to use this param. For now QR Code image files
|
|
802
|
+
are supported
|
|
803
|
+
:param artifact_name: name of the artifact, if None (default) the URL string is used as a name,
|
|
804
|
+
or the file name if artifact is provided (QR Code image file).
|
|
805
|
+
:param preprocessing: Preprocessing settings to be applied to the artifact, None means no preprocessing,
|
|
806
|
+
otherwise a dict with the following attributes can be passed:
|
|
807
|
+
- type (string): only "qrcode" is supported for URL sandboxing:
|
|
808
|
+
the file is a QR Code image with a URL as payload, and you want
|
|
809
|
+
to scan the URL, not the actual file. This argument has to be used with the
|
|
810
|
+
`artifact` param, and `url` set to `None`.
|
|
811
|
+
"""
|
|
755
812
|
logger.info('Sandboxing url in provider %s vm %s', provider_slug, vm_slug)
|
|
756
|
-
artifact
|
|
813
|
+
if artifact and url:
|
|
814
|
+
raise exceptions.InvalidValueException("Cannot use artifact with url param")
|
|
815
|
+
if artifact:
|
|
816
|
+
if not preprocessing or preprocessing.get('type') != 'qrcode':
|
|
817
|
+
raise exceptions.InvalidValueException("Only artifact of type qrcode is supported")
|
|
818
|
+
if isinstance(artifact, str):
|
|
819
|
+
artifact = resources.LocalArtifact.from_path(self,
|
|
820
|
+
artifact,
|
|
821
|
+
artifact_type='URL',
|
|
822
|
+
artifact_name=artifact_name)
|
|
823
|
+
else:
|
|
824
|
+
artifact = resources.LocalArtifact.from_handle(self,
|
|
825
|
+
artifact,
|
|
826
|
+
artifact_name=artifact_name or '',
|
|
827
|
+
artifact_type='URL')
|
|
828
|
+
else:
|
|
829
|
+
artifact_name = url
|
|
830
|
+
artifact = resources.LocalArtifact.from_content(self,
|
|
831
|
+
url,
|
|
832
|
+
artifact_name=artifact_name,
|
|
833
|
+
artifact_type='URL')
|
|
757
834
|
task = resources.SandboxTask.create_file(self,
|
|
758
|
-
artifact_name=
|
|
835
|
+
artifact_name=artifact_name,
|
|
759
836
|
artifact_type="URL",
|
|
760
837
|
community=self.community,
|
|
761
838
|
provider_slug=provider_slug,
|
|
762
839
|
vm_slug=vm_slug,
|
|
763
840
|
browser=browser,
|
|
841
|
+
preprocessing=preprocessing,
|
|
764
842
|
network_enabled=True).result()
|
|
765
843
|
task.upload_file(artifact)
|
|
766
844
|
return resources.SandboxTask.update_file(self, id=task.id, community=self.community).result()
|
|
@@ -978,3 +1056,9 @@ class PolyswarmAPI:
|
|
|
978
1056
|
|
|
979
1057
|
def report_template_list(self, is_default=None, **kwargs):
|
|
980
1058
|
return resources.ReportTemplate.list(self, is_default=is_default, **kwargs).result()
|
|
1059
|
+
|
|
1060
|
+
def account_whois(self, **kwargs):
|
|
1061
|
+
return resources.WhoIs.get(self, **kwargs).result()
|
|
1062
|
+
|
|
1063
|
+
def account_features(self, **kwargs):
|
|
1064
|
+
return resources.AccountFeatures.get(self, **kwargs).result()
|
|
@@ -295,6 +295,7 @@ class ArtifactInstance(core.BaseJsonResource, core.Hashable):
|
|
|
295
295
|
self.community = content.get('community')
|
|
296
296
|
self.created = core.parse_isoformat(content.get('created'))
|
|
297
297
|
self.failed = content.get('failed')
|
|
298
|
+
self.failed_reason = content.get('failed_reason')
|
|
298
299
|
self.filename = content.get('filename')
|
|
299
300
|
self.result = content.get('result')
|
|
300
301
|
self.type = content.get('type')
|
|
@@ -1019,6 +1020,8 @@ class SandboxTask(core.BaseJsonResource):
|
|
|
1019
1020
|
self.sha256 = content['sha256']
|
|
1020
1021
|
self.report = content['report']
|
|
1021
1022
|
self.upload_url = content['upload_url']
|
|
1023
|
+
self.config = content['config']
|
|
1024
|
+
self.artifact = content['artifact']
|
|
1022
1025
|
self.sandbox_artifacts = [SandboxArtifact(a, api=api) for a in content.get('sandbox_artifacts', [])]
|
|
1023
1026
|
|
|
1024
1027
|
def upload_file(self, artifact, attempts=3, **kwargs):
|
|
@@ -1129,6 +1132,10 @@ class ReportTask(core.BaseJsonResource):
|
|
|
1129
1132
|
|
|
1130
1133
|
def download_report(self, folder=None):
|
|
1131
1134
|
""" This method is special, in that it is simply for downloading from S3 """
|
|
1135
|
+
if self.state == 'PENDING':
|
|
1136
|
+
raise exceptions.InvalidValueException('Report is in PENDING state, wait for completion first')
|
|
1137
|
+
if self.state == 'FAILED':
|
|
1138
|
+
raise exceptions.InvalidValueException("Report is in FAILED state, won't be generated")
|
|
1132
1139
|
return core.PolyswarmRequest(
|
|
1133
1140
|
self.api,
|
|
1134
1141
|
{
|
|
@@ -1203,3 +1210,48 @@ class ReportTemplate(core.BaseJsonResource):
|
|
|
1203
1210
|
},
|
|
1204
1211
|
result_parser=self.__class__
|
|
1205
1212
|
).execute()
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
class AccountFeatures(core.BaseJsonResource):
|
|
1216
|
+
RESOURCE_ENDPOINT = "/public/accounts"
|
|
1217
|
+
|
|
1218
|
+
def __init__(self, content, api=None):
|
|
1219
|
+
super().__init__(content, api=api)
|
|
1220
|
+
self.account_number = content['account_number']
|
|
1221
|
+
self.user_account_number = content.get('user_account_number')
|
|
1222
|
+
self.account_plan_name = content['account_plan_name']
|
|
1223
|
+
self.plan_period_start = content['plan_period_start']
|
|
1224
|
+
self.plan_period_end = content['plan_period_end']
|
|
1225
|
+
self.window_start = content['window_start']
|
|
1226
|
+
self.window_end = content['window_end']
|
|
1227
|
+
self.tenant = content.get('tenant')
|
|
1228
|
+
self.daily_api_limit = content['daily_api_limit']
|
|
1229
|
+
self.daily_api_remaining = content['daily_api_remaining']
|
|
1230
|
+
self.has_stream_access = content['has_stream_access']
|
|
1231
|
+
self.is_trial = content['is_trial']
|
|
1232
|
+
self.is_trial_expired = content['is_trial_expired']
|
|
1233
|
+
self.trial_started_at = content['trial_started_at']
|
|
1234
|
+
self.trial_ended_at = content['trial_ended_at']
|
|
1235
|
+
self.features = []
|
|
1236
|
+
for feature in content['features']:
|
|
1237
|
+
self.features.append({
|
|
1238
|
+
'base_uses': feature['base_uses'],
|
|
1239
|
+
'name': feature['name'],
|
|
1240
|
+
'overage': feature['overage'],
|
|
1241
|
+
'remaining_uses': feature['remaining_uses'],
|
|
1242
|
+
'tag': feature['tag'],
|
|
1243
|
+
'value': feature['value'],
|
|
1244
|
+
})
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
class WhoIs(core.BaseJsonResource):
|
|
1248
|
+
RESOURCE_ENDPOINT = "/public/accounts/whois"
|
|
1249
|
+
|
|
1250
|
+
def __init__(self, content, api=None):
|
|
1251
|
+
super().__init__(content, api=api)
|
|
1252
|
+
self.account_number = content['account_number']
|
|
1253
|
+
self.user_account_number = content.get('user_account_number')
|
|
1254
|
+
self.account_name = content['account_name']
|
|
1255
|
+
self.account_type = content['account_type']
|
|
1256
|
+
self.communities = content['communities']
|
|
1257
|
+
self.tenant = content.get('tenant')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polyswarm-api-3.8.0 → polyswarm-api-3.10.0}/src/polyswarm_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|