async def get_file(self, srcode, file, session=None, raw=None): """ Get file details in a scan identified by srcode :param srcode: scan retrieval code value :param file: file or file id :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the file associated with the srcode and file """ route = "/scan_retrieval_codes/{}/files_ext/{}".format( apiid(srcode), apiid(file)) res = await self._get(route, session) return self._format(res, raw, schema=FileExtSchema.dynschema)
async def search( self, query=None, offset=None, limit=None, session=None, raw=None): """ List a page of matching results of a query on files :param query: parameters of the query. It must only contains the keys 'name', 'hash' an 'tags' (default None ie. no filter) :param offset: offset for pagination (default None) :param limit: custom limit for pagination (default None) :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the queried page of the list of files :raises: IrmaError """ if query and isinstance(query.get("tags"), list): query["tags"] = ','.join(str(apiid(i)) for i in query["tags"]) query = self._askpage(offset, limit, query) try: res = await self._get("/files", session, query) schema = Paginated( FileExtSchema, exclude=('probe_results',) )(exclude=('data',)) return self._format(res, raw, schema=schema) except aiohttp.ClientResponseError as e: logger.warning(e) raise IrmaError("Bad resquest")
async def cancel(self, scan, session=None, raw=None): """ Cancel a running scan :param scan: uuid or scan to cancel :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the canceled scan :raises: aiohttp.ClientResponseError :raises: IrmaError if the scan is already finished """ route = "/scans/{}/cancel".format(apiid(scan)) try: res = await self._post(route, session) return self._format(res, raw, schema=ScanSchema()) except aiohttp.ClientResponseError as e: if e.status == 400: raise IrmaError( "Scan {} finished, cannot cancel it".format(apiid(scan))) raise
async def get(self, srcode, session=None, raw=None): """ Get a scan by srcode :param srcode: scan retrieval code value :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the scan associated with the srcode """ route = "/scan_retrieval_codes/{}".format(apiid(srcode)) res = await self._get(route, session) return self._format(res, raw, schema=SRScanSchema())
async def new(self, scan, session=None, raw=None): """ Create a new scan retrieval code :param scan: scan or scan id :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: a newly created srcode """ data = {"scan_id": apiid(scan)} res = await self._post("/scan_retrieval_codes", session, data=data) return self._format(res, raw, schema=ScanRetrievalCodeSchema())
async def remove_tag( self, file, tag, quiet=False, session=None): """ Remove a tag from a file :param file: file or sha256 to remove the tag from :param tag: tag or id to remove :param quiet: bool, do not raise an exception if the file is not tagged with this tag (default False) :param session: custom session to use (default None) :raises: aiohttp.ClientResponseError :raises: IrmaError when tag cant be removed """ route = "/files/{}/tags/{}/remove".format(apiid(file), apiid(tag)) try: await self._get(route, session) except aiohttp.ClientResponseError as e: logger.warning(e) if not (quiet and e.status == 400): raise IrmaError("File {} is already NOT tagged with tag {}." .format(file, tag))
async def get(self, scan, session=None, raw=None): """ Query a scan :param scan: uuid or scan to query :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the queried scan :raises: aiohttp.ClientResponseError """ route = "/scans/{}".format(apiid(scan)) res = await self._get(route, session) return self._format(res, raw, schema=ScanSchema())
async def download( self, file, dstpath, session=None): """ Download a file from the API :param file: file or sha256 to download :param dstpath: path to write the downloaded file on :param session: custom session to use (default None) :raises: aiohttp.ClientResponseError """ route = '/files/{}/download'.format(apiid(file)) with dstpath.open('wb') as fd: await self._get(route, session, stream=fd)
async def add_tag( self, file, tag, quiet=False, session=None): """ Add a tag to a file :param file: file or sha256 to add the tag to :param tag: tag or id to add :param quiet: bool, do not raise an exception if the file is already tagged with this tag (default False) :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :raises: aiohttp.ClientResponseError :raises: IrmaError when tag is already present """ route = "/files/{}/tags/{}/add".format(apiid(file), apiid(tag)) try: await self._get(route, session) except aiohttp.ClientResponseError as e: logger.warning(e) if not (quiet and e.status == 400): raise IrmaError("File {} is already tagged with tag {}." .format(file, tag))
async def download_file( self, srcode, file, dstpath, session=None): """ Download a file from the API :param srcode: scan retrieval code value :param file: file id to download :param dstpath: path to write the downloaded file on :param session: custom session to use (default None) :raises: aiohttp.ClientResponseError :raises: IrmaError on wrong srcode, scan not finished or file potentially harmful """ try: route = '/scan_retrieval_codes/{}/files_ext/{}/download'.format( apiid(srcode), apiid(file)) with dstpath.open('wb') as fd: await self._get(route, session, stream=fd) except aiohttp.ClientResponseError as e: logger.warning(e) if e.status == 403: raise IrmaError("Download forbidden")
async def result(self, fileext, full=False, session=None, raw=None): """ Get detailed results on a specific scanned file :param fileext: fileext or uuid to get results of :param full: bool, get full results or shortened ones (default False) :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the detailed results """ route = "/files_ext/{}".format(apiid(fileext)) query = {"formatted": "no"} if full else {} res = await self._get(route, session, query) return self._format(res, raw, schema=FileExtSchema.dynschema)
async def results( self, file, offset=None, limit=None, session=None, raw=None): """ List a page of the results associated to file :param file: file or sha256 :param offset: offset for pagination (default None) :param limit: custom limit for pagination (default None) :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :returns: the queried page of the list of results :raises: aiohttp.ClientResponseError """ route = "/files/{}".format(apiid(file)) query = self._askpage(offset, limit) res = await self._get(route, session, query) return self._format(res, raw, schema=FileResultSchema())
async def launch( self, fileexts, session=None, raw=None, linger=False, *, probes=None, force=None, mimetype_filtering=None, resubmit_files=None): """ Create and launch a scan on already uploaded files :param fileexts: list of fileexts or uuids to enclose :param session: custom session to use (default None) :param raw: bool, return unprocessed bytes (default None) :param linger: bool, wait for the scan to complete (default False) :param probes: probes to run on (default None ie. all) :param force, mimetype_filtering, resubmit_files: scan options (default None) :returns: a newly created scan :raises: aiohttp.ClientResponseError """ options = {} if force is not None: options['force'] = force if probes is not None: options['probes'] = probes if resubmit_files is not None: options['resubmit_files'] = resubmit_files if mimetype_filtering is not None: options['mimetype_filtering'] = mimetype_filtering data = { "files": [apiid(fe) for fe in fileexts], "options": options, } res = await self._post("/scans", session, json=data) if linger: scan = self._format(res, raw=False, schema=ScanSchema()) return await self.waitfor(scan, session, raw) else: return self._format(res, raw, schema=ScanSchema())