Beispiel #1
0
    def _wait_for_download(self, path, resource, resource_id, file_id, **kw):
        '''
        A simple method to centralize waiting for an export to enter a
        completed state.  The initial request will be made and then we will
        recheck every two and a half seconds after that.  Once the status
        returns one of the completed states, we will return the status.
        '''
        status = self._api.get(path, **kw).json()['status']
        while status not in ['error', 'ready']:
            time.sleep(2.5)
            status = self._api.get(path, **kw).json()['status']

        # If the status that has been reported back is "error", then we will
        # need to throw the appropriate error back to the user.
        if status == 'error':
            raise FileDownloadError(resource, resource_id, file_id)

        # Return the status to the caller.
        return status
Beispiel #2
0
    def _fetch(self, token: str, **kwargs) -> BytesIO:
        '''
        Waits for the download to become available and then downloads

        Args:
            token (str): The token to download.
            **kwargs (dict): keyword args to pass on to the download method.

        Returns:
            BytesIO:
                The downloaded file object.

        Example:

            >>> fobj = nessus.tokens._fetch('1234567890')
        '''
        status = self.status(token)
        while status['status'] != 'ready':
            if status['status'] == 'error':
                raise FileDownloadError('token', token, f'token:{token}')
            time.sleep(0.5)
            status = self.status(token)
        return self.download(token, **kwargs)
Beispiel #3
0
    def export(self, scan_id, *filters, **kw):
        '''
        Export the scan report.

        `scans: export <https://cloud.tenable.com/api#/resources/scans/export-request>`_

        Args:
            scan_id (int): The unique identifier of the scan.
            *filters (tuple, optional):
                A list of tuples detailing the filters that wish to be applied
                the response data.  Each tuple is constructed as 
                ('filter', 'operator', 'value') and would look like the 
                following example: `('plugin.id', 'eq', '19506')`.  For a
                complete list of the available filters and options, please
                refer to the API documentation linked above.
            history_id (int, optional): 
                The unique identifier for the instance of the scan.
            format (str, optional):
                What format would you like the resulting data to be in.  The
                default would be nessus output.  Available options are `nessus`,
                `csv`, `html`, `pdf`, `db`.  Default is `nessus`.
            password (str, optional):
                If the export format is `db`, then what is the password used to
                encrypt the NessusDB file.  This is a require parameter for
                NessusDB exports.
            chapters (list, optional):
                A list of the chapters to write for the report.  The chapters
                list is only required for PDF and HTML exports.  Available
                chapters are `vuln_hosts_summary`, `vuln_by_host`, 
                `compliance_exec`, `remediations`, `vuln_by_plugin`, and
                `compliance`.  List order will denote output order.  Default is
                `vuln_by_host`.
            filter_type (str, optional):
                Are the filters exclusive (this AND this AND this) or inclusive
                (this OR this OR this).  Valid values are `and` and `or`.  The
                default setting is `and`.
            fobj (FileObject, optional):
                The file-like object to be returned with the exported data.  If
                no object is specified, a BytesIO object is returned with the
                data.  While this is an optional parameter, it is highly
                recommended to use this parameter as exported files can be quite
                large, and BytesIO objects are stored in memory, not on disk.

        Returns:
            FileObject: The file-like object of the requested export.

        Examples:
            Export the full report of the latest instance of the scan:

            >>> with open('example.nessus', 'wb') as reportobj:
            ...     tio.scans.export(1, fobj=reportobj)

            Export a specific instance of the scan:

            >>> with open('example.nessus', 'wb') as reportobj:
            ...     tio.scans.export(1, history_id=1, fobj=reportobj)
        '''

        # initiate the payload and parameters dictionaries.
        payload = self._parse_filters(filters,
                                      self._api.filters.scan_filters(),
                                      rtype='sjson')
        params = dict()

        if 'history_id' in kw:
            params['history_id'] = self._check('history_id', kw['history_id'],
                                               int)

        if 'password' in kw:
            payload['password'] = self._check('password', kw['password'], str)

        payload['format'] = self._check(
            'format',
            kw['format'] if 'format' in kw else None,
            str,
            choices=['nessus', 'html', 'pdf', 'csv', 'db'],
            default='nessus')

        # The chapters are sent to us in a list, and we need to collapse that
        # down to a comma-delimited string.
        payload['chapters'] = ';'.join(
            self._check('chapters',
                        kw['chapters'] if 'chapters' in kw else None,
                        list,
                        choices=[
                            'vuln_hosts_summary', 'vuln_by_host',
                            'vuln_by_plugin', 'compliance_exec', 'compliance',
                            'remediations'
                        ],
                        default=['vuln_by_host']))

        if 'filter_type' in kw:
            payload['filter.search_type'] = self._check('filter_type',
                                                        kw['filter_type'],
                                                        str,
                                                        choices=['and', 'or'])

        # Now we need to set the FileObject.  If one was passed to us, then lets
        # just use that, otherwise we will need to instantiate a BytesIO object
        # to push the data into.
        if 'fobj' in kw:
            fobj = kw['fobj']
        else:
            fobj = BytesIO()

        # The first thing that we need to do is make the request and get the
        # File id for the job.
        fid = self._api.post('scans/{}/export'.format(
            self._check('scan_id', scan_id, int)),
                             params=params,
                             json=payload).json()['file']
        self._api._log.debug('Initiated scan export {}'.format(fid))

        # Next we will wait for the status of the export request to become
        # ready.  We will query the API every half a second until we get the
        # response we're looking for.
        status = self._api.get('scans/{}/export/{}/status'.format(
            scan_id, fid)).json()['status']
        while status not in ['error', 'ready']:
            time.sleep(0.5)
            status = self._api.get('scans/{}/export/{}/status'.format(
                scan_id, fid)).json()['status']

        # If the status that has been reported back is "error", then we will
        # need to throw the appropriate error back to the user.
        if status == 'error':
            raise FileDownloadError('scans', scan_id, fid)

        # Now that the status has reported back as "ready", we can actually
        # download the file.
        resp = self._api.get('scans/{}/export/{}/download'.format(
            scan_id, fid),
                             stream=True)

        # Lets stream the file into the file-like object...
        for chunk in resp.iter_content(chunk_size=1024):
            if chunk:
                fobj.write(chunk)
        fobj.seek(0)

        # Lastly lets return the FileObject to the caller.
        return fobj