quarkslab/irma

Support endpoint similar to Virus Total Api to launch a scan

Closed this issue · 4 comments

It would be good if opensource IRMA tool supports an Endpoint which is similar to Virtus total Api endpoints. So that people can use their existing automated scritps to work with IRMA also.

support for following 3 url's: https://www.virustotal.com/en/documentation/public-api/

To start a scan:
https://www.virustotal.com/vtapi/v2/file/scan (Which should upload a file + do a scan)

To do rescan
Which is force scan in our case

https://www.virustotal.com/vtapi/v2/file/rescan

To get reports:
https://www.virustotal.com/vtapi/v2/file/report

We can add new url's and try to call same functions in our code base which supports VT api endpoints.

@ch0k0bn can you assign this ticket to my name ?

we got already something developped but it is for a more recent version

@ch0k0bn Please suggest to write unit test with Mock module.
My method to support VT Api as below:

@hug.post("/scan", versions=2)
def launch_vtapi_v2(request, body,
                    probes: comma_separated_list=None,
                    force: smart_boolean=False,
                    mimetype_filtering: smart_boolean=True,
                    resubmit_files: smart_boolean=True,
                    ):
    """ Launch a scam after adding the file Version 2.
        The request should be performed using a POST request method.
        The sample curl command is as below
        {
            curl -v -F 'file=@/home/vagrant/test.log' \
              http://127.0.0.1/vtapi/v2/file/scan/
            options:
               probes: list of probes or None for all available, }
               force: boolean (default False),
               mimetype_filtering: boolean (default True),
               resubmit_files: boolean (default True),
        }
    """
    log.info("Entering version2 scan method")
    session = db.session
    ip = request.remote_addr
    scan = Scan(compat.timestamp(), ip)
    session.add(scan)
    log.info("Session created and scan added")
    scan.set_status(IrmaScanStatus.empty)
    session.commit()
    log.info("scan %s: created", scan.external_id)
    msg = str(type(scan.external_id))
    msg = str(scan.external_id)
    scan_id = uuid(scan.external_id)
    log.info(str(scan_id))
    add_files_v2(request, scan_id)
    launch_v1(scan_id, probes, force)
    time.sleep(5)
    session.refresh(scan)
    results_check = scan_schema.dump(scan).data
    return {
        "response_code": status_code(results_check['force'],
                                     results_check['probes_finished'],
                                     results_check['probes_total']),
        "scan_id": str(scan_id),
        "sha256": scan.files[0].sha256,
        "permalink": "http;//frontend.irma/scan/"+str(scan_id),
        "verbose_msg": status_msg(results_check['force'],
                                  results_check['probes_finished'],
                                  results_check['probes_total']),
        "resource": scan.files[0].md5
    }

However its failing in unit test when converting to uuid when running nosetest.

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/opt/irma/irma-frontend/releases/20180208084337/branchut/core/frontend/tests/api/scans/test_controllers.py", line 387, in test_launch_vtapi_v2
    result = api_scans.launch_vtapi_v2(m_request, m_body)
  File "/opt/irma/irma-frontend/releases/20180208084337/branchut/core/frontend/api/scans/controllers.py", line 346, in launch_vtapi_v2
    scan_id = uuid(scan.external_id)
  File "/usr/local/lib/python3.4/dist-packages/hug/types.py", line 88, in __call__
    raise ValueError(error_text)
nose.proxy.ValueError: Invalid UUID provided
-------------------- >> begin captured logging << --------------------
api.scans.controllers: INFO: Entering version2 scan method
api.scans.controllers: INFO: Session created and scan added
api.scans.controllers: INFO: scan <MagicMock name='Scan().external_id' id='139742417979320'>: created
--------------------- >> end captured logging << ---------------------

This is what is happening:

  • mocking both request and body object
  • Trying to call launch_vtapi_v2 method using the mocked object
  • When its trying to convert the scan.external_id to uuid in the method we are facing the above issue.
  • Our test code is as below
@patch("api.scans.controllers.File")
    @patch("api.scans.controllers.celery_frontend")
    @patch("api.scans.controllers.FileExt")
    @patch("api.scans.controllers.Scan")
    def test_launch_vtapi_v2(self, m_scan, m_FileExt, m_celery_frontend, m_file):
        m_request= MagicMock()
        m_body = {
            "files": ["file_vtapi"]
            }
        m_file_ext = MagicMock()
        m_file_ext.scan = None
        m_FileExt.load_from_ext_id.return_value = m_file_ext
        result = api_scans.launch_vtapi_v2(m_request, m_body)
        m_scan.launch_vtapi_v2.assert_called_with(m_request, m_body)
        m_celery_frontend.scan_launch.assert_called_once()
        self.assertIsScan(result)

latest v2 version support a similar api endpoint called /scans/quick where you could upload a file and it is automatically scanned