<commit_before>commonfields:
  id: Joe Security
  version: -1
name: Joe Security
display: Joe Security
category: Forensics & Malware Analysis
image: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKQAAACkCAYAAAAZtYVBAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAABOeSURBVHhe7ZwJdFRVmsdLhQQcNxZJ6r1XlVZxVBSUISriEslCgoJbG4WktiQkYRFs3MaxR9KsSW3ZWULcGudog7ROq2237ULDdHtEcZl2wUEHFXAZBETEjSVv/v9br8pUNpIUttLn+53zP6Tuu++9W+9+77vfd+8tbIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgxNE/e4aWnF02FXqib3bptn65Nx3sm1U21zosCH8fki91nZKUPe3e5NwZZvL4mWZyTummpKyyFUdfcfMvbXmzzreqCcIhCUGPQb/tRKutf/8Z6pDkrPLp/WiIudP2J+eUVyaNnXqGdeiQGK7wUMNTdYH1saccC10LLYH+DL0FvQE9C/F7ZUNHQ8IRwjWQ2U1dArUjKWdac7+r7jCTxk1/8NgMb6pVbGux2YYftNmegt6HdkHboHXQfFxslFXNZniCLzimNBww3JUFVlF3mQG9B7VtZ1u9Bt0A9Y<KEY>//<KEY>EQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQYhis/0/VhaCCNDliOwAAAAASUVORK5CYII=
description: Sandbox Cloud
configuration:
- display: API Key
  name: api_key
  defaultvalue: ""
  type: 0
  required: true
- display: Do not validate server certificate (insecure)
  name: insecure
  defaultvalue: ""
  type: 8
  required: false
- display: Use system proxy settings
  name: useproxy
  defaultvalue: ""
  type: 8
  required: false
script:
  script: |
    ''' IMPORTS '''
    import time
    import requests
    from distutils.util import strtobool
    # disable insecure warnings
    requests.packages.urllib3.disable_warnings()

    ''' GLOBAL VARS '''
    BASE_URL = 'https://jbxcloud.joesecurity.org/api/'
    USE_SSL = not demisto.params().get('insecure')

    ''' HELPER FUNCTIONS '''
    def http_post(url_suffix, data=None, files=None):
        data = {} if data is None else data

        data.setdefault('apikey', demisto.params()['api_key'])
        LOG('running request with url=%s\tdata=%s\tfiles=%s' % (BASE_URL + url_suffix,
            data, files, ))
        try:
            res = requests.post(BASE_URL + url_suffix,
                verify=USE_SSL,
                data=data,
                files=files
            )
        except Exception, e:
            LOG(e)
            return 'Error! ' + e.message

        return res.json()


    def webid_to_entry(title, web_ids):
        return createEntry(web_ids, {
            'contextPath' : 'Joe.Analysis(val.WebID && val.WebID == obj.WebID)',
            'title' : title,
            'data' : [
                {'to' : 'WebID', 'from' : u'webid'},
            ],
        })


    def analysis_to_entry(title, info):
        return createEntry(info, {
            'contextPath' : 'Joe.Analysis(val.WebID && val.WebID == obj.WebID)',
            'title' : title,
            'data' : [
                {'to' : 'WebID', 'from' : u'webid'},
                {'to' : 'FileName', 'from' : u'filename'},
                {'to' : 'Status', 'from' : u'status'},
                {'to' : 'Comments', 'from' : u'comments'},
                {'to' : 'Time', 'from' : u'time'},
                {'to' : 'Runs', 'from' : u'runs', 'humanReadable' : False},
                {'to' : 'Result', 'from' : u'runs.detection'},
            ],
        })


    def poll_webid(web_id):
        result = {'data' : {'status' : 'pending'}}
        max_polls = 100;

        while (max_polls >=0) and result['data']['status'] != 'finished':
            if result['data']['status'] != 'pending':
                LOG('error while polling: result is %s' % (result, ))
            result = info_request(web_id)
            time.sleep(2);
            max_polls -= 1

        LOG('reached max_polls #%d' % (max_polls, ))
        if max_polls < 0:
            return analysis_to_entry('Polling timeout on Analysis #' + web_id, result['data'])
        else:
            return analysis_to_entry('Analysis #' + web_id, result['data'])


    ''' FUNCTIONS '''
    def is_online():
        cmd_url = 'v2/server/online'
        res = http_post(cmd_url)
        return res['data']['online']


    def list_analysis():
        cmd_url = 'v2/analysis/list'
        res = http_post(cmd_url)
        return webid_to_entry('Web IDs:', res['data'])


    def analysis_info():
        web_id = demisto.args().get('webid')
        LOG('info: web_id = %s' % (web_id, ))
        res = info_request(web_id)
        return analysis_to_entry('Analysis #' + web_id, res['data'])


    def info_request(web_id):
        cmd_url = 'v2/analysis/info'
        return http_post(cmd_url, data={'webid' : web_id})


    def analyse_url():
        args = demisto.args()
        url = args.get('url')
        should_wait = bool(strtobool(demisto.get(args, 'should_wait')))
        return analyse_url_request(url, should_wait)


    def analyse_url_request(url, should_wait):
        res = http_post('v2/analysis/submit',
            data={'accept-tac': 1, 'url' : url})

        if 'errors' in res:
            LOG('Error! in command analyse_url: url=%s' % (url, ))
            LOG('got the following errors:\n' + '\n'.join(e['message'] for e in res['errors']))
            return 'Failure'

        if should_wait:
            return poll_webid(res['data']['webids'][0])

        info = [{'webid' : i} for i in res['data']['webids']]
        return webid_to_entry('Web ID:', info)


    def analyse_sample():
        args = demisto.args()
        file_entry = args.get('sample')
        sample_url = args.get('sample_url')
        should_wait = bool(strtobool(demisto.get(args, 'should_wait')))

        if (file_entry is None and sample_url is None) or (None not in [file_entry, sample_url]):
            return 'You must specify one (and only one) of the following: sample_url, sample.'

        LOG('analysing sample')
        if file_entry is not None:
            return analyse_sample_file_request(file_entry, should_wait)
        else:
            return analyse_sample_url_request(sample_url, should_wait)


    def analyse_sample_file_request(file_entry, should_wait):
        with open(demisto.getFilePath(file_entry)['path'], 'rb') as f:
            res = http_post('v2/analysis/submit',
                data={'accept-tac': 1},
                files={'sample':f})

            if 'errors' in res:
                LOG('Error! in command sample file: file_entry=%s' % (file_entry, ))
                LOG('got the following errors:\n' + '\n'.join(e['message'] for e in res['errors']))
                return 'Failure'

        if should_wait:
            return poll_webid(res['data']['webids'][0])

        info = [{'webid' : i} for i in res['data']['webids']]
        return webid_to_entry('Web ID:', info)


    def analyse_sample_url_request(sample_url, should_wait):
        res = http_post('v2/analysis/submit',
                data={'accept-tac': 1, 'sample-url' : sample_url})

        if 'errors' in res:
            LOG('Error! in command sample file: file url=%s' % (sample_url, ))
            LOG('got the following errors:\n' + '\n'.join(e['message'] for e in res['errors']))
            return 'Failure'

        if should_wait:
            return poll_webid(res['data']['webids'][0])

        info = [{'webid' : i} for i in res['data']['webids']]
        return webid_to_entry('Web ID:', info)


    ''' EXECUTION CODE '''
    LOG('command is %s' % (demisto.command(), ))
    try:
        if demisto.command() in ['test-module', 'joe-is-online']:
            # This is the call made when pressing the integration test button.
            if is_online():
                demisto.results('ok')
            else:
                demisto.results('not online')
        elif demisto.command() == 'joe-list-analysis':
            demisto.results(list_analysis())
        elif demisto.command() == 'joe-analysis-info':
            demisto.results(analysis_info())<commit_msg>updated code for new integration template<commit_after>commonfields:
  id: <NAME>
  version: -1
name: <NAME>
display: Joe Security
category: Forensics & Malware Analysis
image: data:image/png;base64,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<KEY>K<KEY>xEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQYhis/0/VhaCCNDliOwAAAAASUVORK5CYII=
description: Sandbox Cloud
configuration:
- display: API Key
  name: api_key
  defaultvalue: ""
  type: 0
  required: true
- display: Do not validate server certificate (insecure)
  name: insecure
  defaultvalue: ""
  type: 8
  required: false
script:
  script: |
    ''' IMPORTS '''
    import time
    import requests
    from distutils.util import strtobool
    # disable insecure warnings
    requests.packages.urllib3.disable_warnings()

    ''' GLOBAL VARS '''
    BASE_URL = 'https://jbxcloud.joesecurity.org/api/'
    USE_SSL = not demisto.params().get('insecure', False)

    ''' HELPER FUNCTIONS '''
    def http_post(url_suffix, data=None, files=None):
        data = {} if data is None else data

        data.setdefault('apikey', demisto.params()['api_key'])
        LOG('running request with url=%s\tdata=%s\tfiles=%s' % (BASE_URL + url_suffix,
            data, files, ))
        try:
            res = requests.post(BASE_URL + url_suffix,
                verify=USE_SSL,
                data=data,
                files=files
            )

            if res.status_code != 200:
                raise Exception('Your request failed with the following error: ' + r.reason)

        except Exception, e:
            LOG(e)
            raise

        return res.json()


    def webid_to_entry(title, web_ids):
        return createEntry(web_ids, {
            'contextPath' : 'Joe.Analysis(val.WebID && val.WebID == obj.WebID)',
            'title' : title,
            'data' : [
                {'to' : 'WebID', 'from' : u'webid'},
            ],
        })


    def analysis_to_entry(title, info):
        return createEntry(info, {
            'contextPath' : 'Joe.Analysis(val.WebID && val.WebID == obj.WebID)',
            'title' : title,
            'data' : [
                {'to' : 'WebID', 'from' : u'webid'},
                {'to' : 'FileName', 'from' : u'filename'},
                {'to' : 'Status', 'from' : u'status'},
                {'to' : 'Comments', 'from' : u'comments'},
                {'to' : 'Time', 'from' : u'time'},
                {'to' : 'Runs', 'from' : u'runs', 'humanReadable' : False},
                {'to' : 'Result', 'from' : u'runs.detection'},
            ],
        })


    def poll_webid(web_id):
        result = {'data' : {'status' : 'pending'}}
        max_polls = 100;

        while (max_polls >=0) and result['data']['status'] != 'finished':
            if result['data']['status'] != 'pending':
                LOG('error while polling: result is %s' % (result, ))
            result = info_request(web_id)
            time.sleep(2);
            max_polls -= 1

        LOG('reached max_polls #%d' % (max_polls, ))
        if max_polls < 0:
            return analysis_to_entry('Polling timeout on Analysis #' + web_id, result['data'])
        else:
            return analysis_to_entry('Analysis #' + web_id, result['data'])


    ''' FUNCTIONS '''
    def is_online():
        cmd_url = 'v2/server/online'
        res = http_post(cmd_url)
        return res['data']['online']


    def list_analysis():
        cmd_url = 'v2/analysis/list'
        res = http_post(cmd_url)
        return webid_to_entry('Web IDs:', res['data'])


    def analysis_info():
        web_id = demisto.args().get('webid')
        LOG('info: web_id = %s' % (web_id, ))
        res = info_request(web_id)
        return analysis_to_entry('Analysis #' + web_id, res['data'])


    def info_request(web_id):
        cmd_url = 'v2/analysis/info'
        return http_post(cmd_url, data={'webid' : web_id})


    def analyse_url():
        args = demisto.args()
        url = args.get('url')
        should_wait = bool(strtobool(demisto.get(args, 'should_wait')))
        return analyse_url_request(url, should_wait)


    def analyse_url_request(url, should_wait):
        res = http_post('v2/analysis/submit',
            data={'accept-tac': 1, 'url' : url})

        if 'errors' in res:
            LOG('Error! in command analyse_url: url=%s' % (url, ))
            LOG('got the following errors:\n' + '\n'.join(e['message'] for e in res['errors']))
            raise Exception('command failed to run.')

        if should_wait:
            return poll_webid(res['data']['webids'][0])

        info = [{'webid' : i} for i in res['data']['webids']]
        return webid_to_entry('Web ID:', info)


    def analyse_sample():
        args = demisto.args()
        file_entry = args.get('sample')
        sample_url = args.get('sample_url')
        should_wait = bool(strtobool(demisto.get(args, 'should_wait')))

        if (file_entry is None and sample_url is None) or (None not in [file_entry, sample_url]):
            raise ValueError('You must specify one (and only one) of the following: sample_url, sample.')

        LOG('analysing sample')
        if file_entry is not None:
            return analyse_sample_file_request(file_entry, should_wait)
        else:
            return analyse_sample_url_request(sample_url, should_wait)


    def analyse_sample_file_request(file_entry, should_wait):
        with open(demisto.getFilePath(file_entry)['path'], 'rb') as f:
            res = http_post('v2/analysis/submit',
                data={'accept-tac': 1},
                files={'sample':f})

            if 'errors' in res:
                LOG('Error! in command sample file: file_entry=%s' % (file_entry, ))
                LOG('got the following errors:\n' + '\n'.join(e['message'] for e in res['errors']))
                raise Exception('command failed to run.')

        if should_wait:
            return poll_webid(res['data']['webids'][0])

        info = [{'webid' : i} for i in res['data']['webids']]
        return webid_to_entry('Web ID:', info)


    def analyse_sample_url_request(sample_url, should_wait):
        res = http_post('v2/analysis/submit',
                data={'accept-tac': 1, 'sample-url' : sample_url})

        if 'errors' in res:
            LOG('Error! in command sample file: file url=%s' % (sample_url, ))
            LOG('got the following errors:\n' + '\n'.join(e['message'] for e in res['errors']))
            raise Exception('command failed to run.')

        if should_wait:
            return poll_webid(res['data']['webids'][0])

        info = [{'webid' : i} for i in res['data']['webids']]
        return webid_to_entry('Web ID:', info)


    ''' EXECUTION CODE '''
    LOG('command is %s' % (demisto.command(), ))
    try:
        if demisto.command() in ['test-module', 'joe-is-online']:
            # This is the call made when pressing the integration test button.
            if is_online():
                demisto.results('ok')
            else:
                demisto.results('not online')
        elif demisto.command() == 'joe-list-analysis':
            demisto.results(list_analysis())
        elif demisto.command() == 'joe-analysis-info':
            demisto.results(analysis_info())
{'fraction_non_alphanumeric': 0.10937960869137744, 'fraction_numerical': 0.04561989971487563, 'mean_word_length': 3.5972881355932205, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3734228', 'n_tokens_mistral': 9394, 'n_tokens_neox': 8848, 'n_words': 1028}