############################################################## TERMS OF USE #################################################################
# The following code is provided for demonstration purpose only, and should not be used without independent verification. Recorded Future   #
# makes no representations or warranties, express, implied, statutory, or otherwise, regarding this code, and provides it strictly "as-is". #
# Recorded Future shall not be liable for, and you assume all risk of using the foregoing.                                                  #
#############################################################################################################################################


import requests
import json
import datetime
from datetime import timedelta
import pandas as pd



def hour_rounder(t):
    # Rounds to nearest hour by adding a timedelta hour if minute >= 30
    return (t.replace(second=0, microsecond=0, minute=0, hour=t.hour)
               +timedelta(hours=t.minute//30))

def reason_to_tcode(reason):
    switcher = {
        "Password Spray": "T1110",
    }
 
    # get() method of dictionary data type returns
    # value of passed argument if it is present
    # in dictionary otherwise second argument will
    # be assigned as default value of passed argument
    return switcher.get(reason, "")

def queryOkta():

    # Set the API endpoint and your API key
    url = "https://1rf.okta.com/api/v1/logs/"
    api_key = "<insert_okta_api_key>"
    # Set the headers for the API request
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": "SSWS {}".format(api_key)
    }
    # Set the query parameters for the API request

    Previous_Date = datetime.datetime.today() - datetime.timedelta(days=1)
    # print ('Previous Date: ' + str(Previous_Date))
    nextCursor = None

    params = {
        #    "status": "active"
        "since": Previous_Date.isoformat(),
        "cursor": nextCursor,
        "q" : "security.threat.detected"
    }

    json_object = []
    data = []
    while True:
        if nextCursor:
                params['cursor'] = nextCursor
        response = requests.get(url, headers=headers, params=params)
        json_object = response.json()

        #okta hasn't seemed to be paginated yet - this would need further testing
#        print(json.dumps((json_object),indent=1))
#        if isinstance(json_object, list):
#                data.extend(json_object)
#        else:
#                data.append(json_object)
#        nextCursor = json_object.get('pagination', {}).get('nextCursor', None)

        if not nextCursor:
                break

    ioc_list = []

    #append the flags used for Collective Insights Submission
    # initially set with debug=bool(True), this means that the Collective Insights API will be 
    # called in debug mode, in which it will validate the API call but will NOT write data 
    # to the database.  Once testing is complete and data is intended to be written directly to 
    # the Recorded Future Collective Insights database, this should be changed to "debug=bool(False)"
    json_start = dict(options=dict(debug=bool(True), summary=bool(True)))

    for q in json_object:
        src=q['client']['ipAddress']
        timestamp = q['published']

        #Consider rounding timestamp to the hour so it could be de-duped somewhere in the pipeline
        #You'll notice a lot of events are picked up for a single IOC, causing a lot of duplicates
#        timestamp = dateutil.parser.isoparse(timestamp)
#        timestamp = hour_rounder(timestamp)
#        timestamp = timestamp.isoformat()

        threatId = q['debugContext']['debugData']['requestId']
        #build the comment field for detection.name in Collective Insights Submission
        comment = q['displayMessage'] + " - " + q['outcome']['result'] + " - " + q['outcome']['reason']
        
        #Append TCodes if mapped
        mitre_codes = []
        reason=q['outcome']['reason']
        tcode=reason_to_tcode(reason)
        mitre_codes.append(tcode)
        
        jsonBuilder = {
            'timestamp': timestamp,
            'ioc': {
                "type": "ip",
                "value": src,
                "source_type": "okta:systemlog-api"
            },
            'incident': {
                "id": threatId,
                "name": "Okta Threat Detection",
                "type": "okta-threat-detection"
            },
            "mitre_codes":
            mitre_codes,
            'detection': {
                "type": "correlation",
                "sub_type": "",
                "name" : "Okta - " + comment
            }
        }
        
        ioc_list.append(jsonBuilder)

    uploadJson = dict(json_start, data=ioc_list)
    # pretty print payload as json
    print(json.dumps((uploadJson),indent=1))
    # count submissions
    uploadCount = len(ioc_list)
    print(uploadCount)
    return uploadCount, uploadJson

def submitCollectiveInsights(collective_insights_upload):
    url = "https://api.recordedfuture.com/collective-insights/detections"
    api_key = "<insert_collective_insights_api_key_here>"
    # Set the headers for the API request
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "X-RFToken": "{}".format(api_key)
    }

    # assign data variable to the json payload submitted to this function
    data = collective_insights_upload

    # post data to collective insights using arguments created above
    response = requests.post(url, headers=headers, data=json.dumps(data))
    # print(response)
    return response        
        
try:
    resultCount, collective_insights_upload = queryOkta()
    print("Ran without Error - Generated " + str(resultCount) + " results")
    submitPayload = submitCollectiveInsights(collective_insights_upload)
    print(submitPayload)
except requests.exceptions.RequestException as e:  # This is the correct syntax
    raise SystemExit(e)