def upload_file(self, artifact, attempts=3, **kwargs): if not self.upload_url: raise exceptions.InvalidValueException( 'upload_url must be set to upload a file') if not artifact: raise exceptions.InvalidValueException( 'A LocalArtifact must be provided in order to upload') r = None while attempts > 0 and not r: attempts -= 1 artifact.seek(0) r = requests.put(self.upload_url, data=artifact, **kwargs) return r
def from_path(cls, api, path, artifact_type=None, analyze=False, create=False, **kwargs): if not isinstance(path, string_types): raise exceptions.InvalidValueException('Path should be a string') folder, file_name = os.path.split(path) if create: # TODO: this should be replaced with os.makedirs(path, exist_ok=True) # once we drop support to python 2.7 if not os.path.exists(folder): try: os.makedirs(folder) except FileExistsError: pass elif not os.path.isfile(path): raise exceptions.ArtifactDeletedException( "The file does not exist") mode = kwargs.pop('mode', 'wb+' if create else 'rb') handler = open(path, mode=mode, **kwargs) return cls(handler, artifact_name=file_name, artifact_type=artifact_type, analyze=analyze, polyswarm=api)
def _endpoint(cls, api, **kwargs): if cls.RESOURCE_ENDPOINT is None: raise exceptions.InvalidValueException( 'RESOURCE_ENDPOINT is not configured for this resource.') return '{api.uri}{endpoint}'.format(api=api, endpoint=cls.RESOURCE_ENDPOINT, **kwargs)
def refresh_engine_cache(self): """ Rrefresh the cached engine listing """ engines = list(resources.Engine.list(self).result()) if not engines: raise exceptions.InvalidValueException( "Recieved empty engines listing") self._engines = engines
def parse(value): if isinstance(value, ArtifactType): return value try: return ArtifactType[value.upper()] except Exception as e: raise raise_from( exceptions.InvalidValueException( 'Unable to get the artifact type from the provided value {}' .format(value)), e)
def submit(self, artifact, artifact_type=resources.ArtifactType.FILE, artifact_name=None, scan_config=None): """ Submit artifacts to polyswarm and return UUIDs :param artifact: A file-like, path to file, url or LocalArtifact instance :param artifact_type: The ArtifactType or strings containing "file" or "url" :param artifact_name: An appropriate filename for the Artifact :param scan_config: The scan configuration to be used, e.g.: "default", "more-time", "most-time" :return: An ArtifactInstance resource """ logger.info('Submitting artifact of type %s', artifact_type) artifact_type = resources.ArtifactType.parse(artifact_type) # TODO This is a python 2.7 check if artifact is a file-like instance, consider changing # to isinstance(artifact, io.IOBase) when deprecating 2.7 and implementing making LocalHandle # inherit io.IOBase, although this will change the method delegation logic in the resource if hasattr(artifact, 'read') and hasattr(artifact.read, '__call__'): artifact = resources.LocalArtifact.from_handle( self, artifact, artifact_name=artifact_name or '', artifact_type=artifact_type) elif isinstance(artifact, string_types): if artifact_type == resources.ArtifactType.FILE: artifact = resources.LocalArtifact.from_path( self, artifact, artifact_type=artifact_type, artifact_name=artifact_name) elif artifact_type == resources.ArtifactType.URL: artifact = resources.LocalArtifact.from_content( self, artifact, artifact_name=artifact_name or artifact, artifact_type=artifact_type) if artifact_type == resources.ArtifactType.URL: scan_config = scan_config or 'more-time' if isinstance(artifact, resources.LocalArtifact): instance = resources.ArtifactInstance.create( self, artifact_name=artifact.artifact_name, artifact_type=artifact.artifact_type.name, scan_config=scan_config, community=self.community).result() instance.upload_file(artifact) return resources.ArtifactInstance.update(self, id=instance.id).result() else: raise exceptions.InvalidValueException( 'Artifacts should be a path to a file or a LocalArtifact instance' )
def __init__(self, hash_, hash_type=None, polyswarm=None): super(Hash, self).__init__(polyswarm=polyswarm) hash_ = hash_.strip() if hash_type and hash_type not in Hash.SUPPORTED_HASH_TYPES: raise exceptions.InvalidValueException( 'Hash type provided is not supported.') self._hash_type = Hash.get_hash_type(hash_) if self._hash_type is None: raise exceptions.InvalidValueException( 'Invalid hash provided: {}'.format(hash_)) if hash_type and self.hash_type != hash_type: raise exceptions.InvalidValueException( 'Detected hash type {}, got {} for hash {}'.format( hash_type, self.hash_type, hash_)) self._hash = hash_
def __init__(self, content, api=None): super(YaraRuleset, self).__init__(content, api=api) self.yara = content['yara'] self.name = content.get('name') self.id = content.get('id') self.description = content.get('description') self.created = core.parse_isoformat(content.get('created')) self.modified = core.parse_isoformat(content.get('modified')) self.deleted = content.get('deleted') if not self.yara: raise exceptions.InvalidValueException( "Must provide yara ruleset content")
def __init__(self, json, polyswarm=None): super(YaraRuleset, self).__init__(json, polyswarm) self.yara = json['yara'] self.name = json.get('name') self.id = json.get('id') self.description = json.get('description') self.created = date.parse_isoformat(json.get('created')) self.modified = date.parse_isoformat(json.get('modified')) self.deleted = json.get('deleted') if not self.yara: raise exceptions.InvalidValueException( "Must provide yara ruleset content")
def _parse_rule(self, rule): if isinstance(rule, string_types): rule, rule_id = resources.YaraRuleset(dict(yara=rule), api=self), None try: rule.validate() except exceptions.NotImportedException as e: logger.debug('%s\nSkipping validation.', str(e)) elif isinstance(rule, (resources.YaraRuleset, int)): rule, rule_id = None, rule else: raise exceptions.InvalidValueException( 'Either yara or rule_id must be provided.') return rule, rule_id
def __init__(self, *args, **kwargs): # hack to behave as in python 3, signature should be # __init__(self, content, *args, hash_value=None, hash_type=None, validate_hash=False, **kwargs) hash_value = kwargs.pop('hash_value', None) hash_type = kwargs.pop('hash_type', None) validate_hash = kwargs.pop('validate_hash', False) super(Hashable, self).__init__(*args, **kwargs) self._hash = hash_value.strip() if hash_value is not None else None if hash_type: if hash_type not in self.SUPPORTED_HASH_TYPES: raise exceptions.InvalidValueException( 'Hash type provided is not supported.') self._hash_type = hash_type else: self._hash_type = self.resolve_hash_type() if self._hash_type is None: raise exceptions.InvalidValueException( 'Invalid hash provided: {}'.format(self._hash)) if validate_hash: self.validate()
def from_hashable(cls, hash_, hash_type=None): """ Coerce to Hashable object :param hash_: Hashable object :param hash_type: Hash type :param polyswarm: PolyswarmAPI instance :return: Hash """ if issubclass(type(hash_), core.Hashable): if hash_type and hash_.hash_type != hash_type: raise exceptions.InvalidValueException( 'Detected hash type {}, got {} for hashable {}'.format( hash_.hash_type, hash_type, hash_.hash)) return Hash(hash_.hash, hash_type=hash_type) return Hash(hash_, hash_type=hash_type)
def from_path(cls, api, path, artifact_type=None, analyze=False, artifact_name=None, **kwargs): if not isinstance(path, string_types): raise exceptions.InvalidValueException('Path should be a string') artifact_name = artifact_name or os.path.basename(path) handle = open(path, mode='rb', **kwargs) # create the LocalHandle with the given handle and don't write anything to it return cls(b'', handle=handle, artifact_name=artifact_name, artifact_type=artifact_type, analyze=analyze, api=api)
def __init__(self, response, api=None, handle=None, folder=None, artifact_name=None, artifact_type=None, analyze=False, **kwargs): """ A representation of an artifact we have locally :param artifact_name: Name of the artifact :param artifact_type: Type of artifact :param api: PolyswarmAPI instance :param analyze: Boolean, if True will run analyses on artifact on startup (Note: this may still run later if False) """ # check if we have a destination to store the file # raise an error if we don't have exacltly one if folder and handle: raise exceptions.InvalidValueException( 'Only one of path or handle should be defined.') if not (folder or handle): raise exceptions.InvalidValueException( 'At least one of path or handle must be defined.') # initialize super classes and default values super(LocalArtifact, self).__init__(response, api=api, hash_type='sha256') self.sha256 = None self.sha1 = None self.md5 = None self.analyzed = False self.artifact_type = artifact_type or ArtifactType.FILE # resolve the file name if artifact_name: # prioritize explicitly provided name self.artifact_name = artifact_name else: if response: # respect content-disposition if there is a response filename = response.headers.get('content-disposition', '').partition('filename=')[2] if filename: self.artifact_name = filename elif os.path.basename(getattr(handle, 'name', '')): self.artifact_name = os.path.basename( getattr(handle, 'name', '')) else: self.artifact_name = os.path.basename( urlparse(response.url).path) elif os.path.basename(getattr(handle, 'name', '')): # if there is no response and no artifact_name, try to get from the handle self.artifact_name = os.path.basename( getattr(handle, 'name', '')) # resolve the handle to be used # only one of handle or folder can be provided (we checked for this above) # if one was explicitly provided, use it # if we have a folder, use a file named after file_name in that folder # otherwise use an in-memory handle remove_on_error = False try: if folder: # TODO: this should be replaced with os.makedirs(path, exist_ok=True) # once we drop support to python 2.7 if not os.path.exists(folder): try: os.makedirs(folder) except FileExistsError: pass remove_on_error = True self.handle = open(os.path.join(folder, self.artifact_name), mode='wb+', **kwargs) else: self.handle = handle or io.BytesIO() if response: # process the content in the response if available, write to handle for chunk in response.iter_content( settings.DOWNLOAD_CHUNK_SIZE): self.handle.write(chunk) if hasattr(self.handle, 'flush'): self.handle.flush() if analyze: # analyze the artifact in case it is needed self.analyze_artifact() except Exception: try: if remove_on_error and self.handle: # make sure we cleanup the handle # if an exception happened and this is a file we created self.handle.close() os.remove(self.handle.name) except Exception: logger.exception('Failed to cleanup the target file.') raise
def validate(self): hash_type = self.resolve_hash_type() if self.hash_type != hash_type: raise exceptions.InvalidValueException( 'Detected hash type {}, got type {} for hash {}'.format( hash_type, self.hash_type, self.hash))