Пример #1
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """

    __version__ = "1.1.0"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        super().__init__(redis, logger, console_logger)

    # async def run_analyzer(self, apikey, url, title_query):
    #    self.thehive = TheHiveApi(url, apikey, cert=False)

    #    response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
    #    return response.text

    def __connect_thehive(self, url, apikey, organisation):
        if organisation:
            self.thehive = TheHiveApi(url,
                                      apikey,
                                      cert=False,
                                      organisation=organisation)
        else:
            self.thehive = TheHiveApi(url, apikey, cert=False)

    async def search_case_title(self, apikey, url, organisation, title_query):
        self.__connect_thehive(url, apikey, organisation)

        response = self.thehive.find_cases(query=ContainsString(
            "title", title_query),
                                           range="all",
                                           sort=[])

        return response.text

    async def custom_search(self,
                            apikey,
                            url,
                            organisation,
                            search_for,
                            custom_query,
                            range="all"):
        self.__connect_thehive(url, apikey, organisation)

        try:
            custom_query = json.loads(custom_query)
        except:
            # raise IOError("Invalid JSON payload received.")
            pass

        if search_for == "alert":
            response = self.thehive.find_alerts(query=custom_query,
                                                range="all",
                                                sort=[])
        else:
            response = self.thehive.find_cases(query=custom_query,
                                               range="all",
                                               sort=[])

        if (response.status_code == 200 or response.status_code == 201
                or response.status_code == 202):
            return response.text
        else:
            raise IOError(response.text)

    async def add_case_artifact(
        self,
        apikey,
        url,
        organisation,
        case_id,
        data,
        datatype,
        tags=None,
        tlp=None,
        ioc=None,
        sighted=None,
        description="",
    ):
        self.__connect_thehive(url, apikey, organisation)

        tlp = int(tlp) if tlp else 2
        ioc = True if ioc.lower() == "true" else False
        sighted = True if sighted.lower() == "true" else False
        if not description:
            description = "Created by shuffle"

        tags = (tags.split(", ")
                if ", " in tags else tags.split(",") if "," in tags else [])

        item = thehive4py.models.CaseObservable(
            dataType=datatype,
            data=data,
            tlp=tlp,
            ioc=ioc,
            sighted=sighted,
            tags=tags,
            message=description,
        )

        return self.thehive.create_case_observable(case_id, item).text

    async def search_alert_title(self,
                                 apikey,
                                 url,
                                 organisation,
                                 title_query,
                                 search_range="0-25"):
        self.__connect_thehive(url, apikey, organisation)

        # Could be "all" too
        if search_range == "":
            search_range = "0-25"

        response = self.thehive.find_alerts(query=ContainsString(
            "title", title_query),
                                            range=search_range,
                                            sort=[])

        return response.text

    async def create_case(
        self,
        apikey,
        url,
        organisation,
        template,
        title,
        description="",
        tlp=1,
        severity=1,
        tags="",
    ):
        self.__connect_thehive(url, apikey, organisation)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        Casetemplate = template if template else None

        case = thehive4py.models.Case(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            template=Casetemplate,
        )

        try:
            ret = self.thehive.create_case(case)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert(
        self,
        apikey,
        url,
        organisation,
        type,
        source,
        sourceref,
        title,
        description="",
        tlp=1,
        severity=1,
        tags="",
        artifacts="",
    ):
        self.__connect_thehive(url, apikey, organisation)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-3, not %s" % tlp

            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 1-3, not %s" % severity

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 3 or severity < 1:
            return "Severity needs to be a number from 1-3, not %d" % severity

        all_artifacts = []
        if artifacts != "":
            # print("ARTIFACTS: %s" % artifacts)
            if isinstance(artifacts, str):
                # print("ITS A STRING!")
                try:
                    artifacts = json.loads(artifacts)
                except:
                    print("[ERROR] Error in parsing artifacts!")

            # print("ART HERE: %s" % artifacts)
            # print("ART: %s" % type(artifacts))
            if isinstance(artifacts, list):
                print("ITS A LIST!")
                for item in artifacts:
                    print("ITEM: %s" % item)
                    try:
                        artifact = thehive4py.models.AlertArtifact(
                            dataType=item["data_type"],
                            data=item["data"],
                        )

                        try:
                            artifact["message"] = item["message"]
                        except:
                            pass

                        if item["data_type"] == "ip":
                            try:
                                if item["is_private_ip"]:
                                    message += " IP is private."
                            except:
                                pass

                        all_artifacts.append(artifact)
                    except KeyError as e:
                        print("Error in artifacts: %s" % e)

        alert = thehive4py.models.Alert(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            type=type,
            source=source,
            sourceRef=sourceref,
            artifacts=all_artifacts,
        )

        try:
            ret = self.thehive.create_alert(alert)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert_artifact(
        self,
        apikey,
        url,
        organisation,
        alert_id,
        dataType,
        data,
        message=None,
        tlp="2",
        ioc="False",
        sighted="False",
        ignoreSimilarity="False",
        tags=None,
    ):
        self.__connect_thehive(url, apikey, organisation, version=4)

        if tlp:
            tlp = int(tlp)
        else:
            tlp = 2

        ioc = ioc.lower().strip() == "true"
        sighted = sighted.lower().strip() == "true"
        ignoreSimilarity = ignoreSimilarity.lower().strip() == "true"

        if tags:
            tags = [x.strip() for x in tags.split(",")]
        else:
            tags = []

        alert_artifact = thehive4py.models.AlertArtifact(
            dataType=dataType,
            data=data,
            message=message,
            tlp=tlp,
            ioc=ioc,
            sighted=sighted,
            ignoreSimilarity=ignoreSimilarity,
            tags=tags,
        )

        try:
            ret = self.thehive.create_alert_artifact(alert_id, alert_artifact)
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

        if ret.status_code > 299:
            raise ConnectionError(ret.text)

        return ret.text

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, apikey, url, organisation, field_type, cur_id):
        self.__connect_thehive(url, apikey, organisation)

        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id + "?similarity=1")
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/shuffle-apps for more info."
                % field_type)

        return ret.text

    async def close_alert(self, apikey, url, organisation, alert_id):
        self.__connect_thehive(url, apikey, organisation)
        return self.thehive.mark_alert_as_read(alert_id).text

    async def reopen_alert(self, apikey, url, organisation, alert_id):
        self.__connect_thehive(url, apikey, organisation)
        return self.thehive.mark_alert_as_unread(alert_id).text

    async def create_case_from_alert(self,
                                     apikey,
                                     url,
                                     organisation,
                                     alert_id,
                                     case_template=None):
        self.__connect_thehive(url, apikey, organisation)
        response = self.thehive.promote_alert_to_case(
            alert_id=alert_id, case_template=case_template)
        return response.text

    async def merge_alert_into_case(self, apikey, url, organisation, alert_id,
                                    case_id):
        self.__connect_thehive(url, apikey, organisation)
        req = url + f"/api/alert/{alert_id}/merge/{case_id}"
        ret = requests.post(req, auth=self.thehive.auth)
        return ret.text

    # Not sure what the data should be
    async def update_field(self, apikey, url, organisation, field_type, cur_id,
                           field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"):
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass

                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored":
                    url = "%s/markAsRead" % url

                ret = requests.post(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                )
            else:
                ret = requests.patch(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                    json=newdata,
                )

            return str(ret.status_code)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info."
                % field_type)

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def delete_alert_artifact(self, apikey, url, organisation,
                                    artifact_id):
        self.__connect_thehive(url, apikey, organisation, version=4)
        return self.thehive.delete_alert_artifact(artifact_id).text

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def run_analyzer(self, apikey, url, organisation, cortex_id,
                           analyzer_id, artifact_id):
        self.__connect_thehive(url, apikey, organisation)
        return self.thehive.run_analyzer(cortex_id, artifact_id,
                                         analyzer_id).text

    # Creates a task log in TheHive with file
    async def create_task_log(self,
                              apikey,
                              url,
                              organisation,
                              task_id,
                              message,
                              filedata={}):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        data = {"_json": """{"message": "%s"}""" % message}
        response = requests.post(
            "%s/api/case/task/%s/log" % (url, task_id),
            headers=headers,
            files=files,
            data=data,
        )
        return response.text

    # Creates an observable as a file in a case
    async def create_case_file_observable(self, apikey, url, organisation,
                                          case_id, tags, filedata):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        outerarray = {"dataType": "file", "tags": tags}
        data = {"_json": """%s""" % json.dumps(outerarray)}
        response = requests.post(
            "%s/api/case/%s/artifact" % (url, case_id),
            headers=headers,
            files=files,
            data=data,
            verify=False,
        )
        return response.text

    # Get all artifacts of a given case
    async def get_case_artifacts(
        self,
        apikey,
        url,
        organisation,
        case_id,
        dataType,
    ):
        self.__connect_thehive(url, apikey, organisation)

        query = And(Eq("dataType", dataType)) if dataType else {}

        # Call the API
        response = self.thehive.get_case_observables(
            case_id, query=query, sort=["-startDate", "+ioc"], range="all")

        # Display the result
        if response.status_code == 200:
            # Get response data
            list = response.json()

            # Display response data
            return (json.dumps(list, indent=4, sort_keys=True)
                    if list else json.dumps(
                        {
                            "status": 200,
                            "message": "No observable results"
                        },
                        indent=4,
                        sort_keys=True,
                    ))
        else:
            return f"Failure: {response.status_code}/{response.text}"

    async def close_case(
        self,
        apikey,
        url,
        organisation,
        id,
        resolution_status="",
        impact_status="",
        summary="",
    ):

        self.__connect_thehive(url, apikey, organisation)
        case = self.thehive.case(id)
        case.status = "Resolved"
        case.summary = summary
        case.resolutionStatus = resolution_status
        case.impactStatus = impact_status

        result = self.thehive.update_case(
            case,
            fields=[
                "status",
                "summary",
                "resolutionStatus",
                "impactStatus",
            ],
        )

        return json.dumps(result.json(), indent=4, sort_keys=True)

    # Update TheHive Case
    async def update_case(
        self,
        apikey,
        url,
        organisation,
        id,
        title="",
        description="",
        severity=None,
        owner="",
        flag=None,
        tlp=None,
        pap=None,
        tags="",
        status="",
        custom_fields=None,
        custom_json=None,
    ):
        self.__connect_thehive(url, apikey, organisation)

        # Get current case data and update fields if new data exists
        case = self.thehive.get_case(id).json()
        print(case)

        case_title = title if title else case["title"]
        case_description = description if description else case["description"]
        case_severity = int(severity) if severity else case["severity"]
        case_owner = owner if owner else case["owner"]
        case_flag = ((False if flag.lower() == "false" else True)
                     if flag else case["flag"])
        case_tlp = int(tlp) if tlp else case["tlp"]
        case_pap = int(pap) if pap else case["pap"]
        case_tags = tags.split(",") if tags else case["tags"]
        case_tags = tags.split(",") if tags else case["tags"]

        case_status = status if status else case["status"]
        case_customFields = case["customFields"]

        # Prepare the customfields
        customfields = CustomFieldHelper()
        if case_customFields:
            for key, value in case_customFields.items():
                if list(value)[0] == "integer":
                    customfields.add_integer(key, list(value.items())[0][1])
                elif list(value)[0] == "string":
                    customfields.add_string(key, list(value.items())[0][1])
                elif list(value)[0] == "boolean":
                    customfields.add_boolean(key, list(value.items())[0][1])
                elif list(value)[0] == "float":
                    customfields.add_float(key, list(value.items())[0][1])
                else:
                    print(
                        f'The value type "{value}" of the field {key} is not suported by the function.'
                    )

        custom_fields = json.loads(custom_fields) if custom_fields else {}
        for key, value in custom_fields.items():
            if type(value) == int:
                customfields.add_integer(key, value)
            elif type(value) == str:
                customfields.add_string(key, value)
            elif type(value) == bool:
                customfields.add_boolean(key, value)
            elif type(value) == float:
                customfields.add_float(key, value)
            else:
                print(
                    f'The value type "{value}" of the field {key} is not suported by the function.'
                )

        customfields = customfields.build()

        custom_json = json.loads(custom_json) if custom_json else {}

        # Prepare the fields to be updated
        case = Case(
            id=id,
            title=case_title,
            description=case_description,
            severity=case_severity,
            owner=case_owner,
            flag=case_flag,
            tlp=case_tlp,
            pap=case_pap,
            tags=case_tags,
            status=case_status,
            customFields=customfields,
            json=custom_json,
        )

        # resolutionStatus=case_resolutionStatus,

        result = self.thehive.update_case(
            case,
            fields=[
                "title",
                "description",
                "severity",
                "owner",
                "flag",
                "tlp",
                "pap",
                "tags",
                "customFields",
                "status",
            ],
        )

        return json.dumps(result.json(), indent=4, sort_keys=True)

    # Get TheHive Organisations
    async def get_organisations(
        self,
        apikey,
        url,
        organisation,
    ):
        headers = {
            "Authorization": f"Bearer {apikey}",
            "Content-Type": "application/json",
        }

        response = requests.get(
            f"{url}/api/organisation",
            headers=headers,
            verify=False,
        )

        return response.text

    # Create TheHive Organisation
    async def create_organisation(
        self,
        apikey,
        url,
        organisation,
        name,
        description,
    ):
        headers = {
            "Authorization": f"Bearer {apikey}",
            "Content-Type": "application/json",
        }

        data = {"name": f"{name}", "description": f"{description}"}

        response = requests.post(
            f"{url}/api/organisation",
            headers=headers,
            json=data,
            verify=False,
        )

        return response.text

    # Create User in TheHive
    async def create_user(
        self,
        apikey,
        url,
        organisation,
        login,
        name,
        profile,
    ):
        headers = {
            "Authorization": f"Bearer {apikey}",
            "Content-Type": "application/json",
        }

        data = {
            "login": f"{login}",
            "name": f"{name}",
            "profile": f"{profile}",
            "organisation": f"{organisation}",
        }

        response = requests.post(
            f"{url}/api/v1/user",
            headers=headers,
            json=data,
            verify=False,
        )

        return response.text
Пример #2
0
class Reporter(Responder):
    def __init__(self):
        Responder.__init__(self)
        self.thehive_instance = self.get_param('config.thehive_instance',
                                               'localhost:9000')
        self.thehive_api = self.get_param('config.thehive_api',
                                          'YOUR_KEY_HERE')
        self.api = TheHiveApi(self.thehive_instance, self.thehive_api)
        self.tmpPath = self.get_param('config.tmp_file_location')

    def getSummary(self, severity):

        # Summary Fields - Severity
        if (severity == 1):
            severity = "Low"
        elif (severity == 2):
            severity = "Medium"
        elif (severity == 3):
            severity = "High"
        else:
            severity = "unknown"

        return severity

    def getTLP(self, tlp):

        # Summary Fields - TLP
        if (tlp == 0):
            tlp = [
                '![TLP:WHITE](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5M0JERkQzMDg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5M0JERkQzMTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjkzQkRGRDJFODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjkzQkRGRDJGODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+49AQNQAACDpJREFUeNrsmWdo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)',
                '**TLP:WHITE - Disclosure is not limited.**'
            ]
        elif (tlp == 1):
            tlp = [
                '![TLP:GREEN](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4NjQ1RkVGRDg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4NjQ1RkVGRTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2NDVGRUZCODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjg2NDVGRUZDODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+I9OQdgAAB7xJREFUeNrsWWts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)',
                '**TLP:GREEN - Limited disclosure, restricted to the community.**'
            ]
        elif (tlp == 2):
            tlp = [
                '![TLP:AMBER](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4NjQ1RkVGOTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4NjQ1RkVGQTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2NDVGRUY3ODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjg2NDVGRUY4ODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+11CCTgAAB/hJREFUeNrsWnts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)',
                '**TLP:AMBER - Limited disclosure, restricted to participants’ organizations.**'
            ]
        elif (tlp == 3):
            tlp = [
                '![TLP:RED](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5M0JERkQyQzg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5M0JERkQyRDg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2NDVGRUZGODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjg2NDVGRjAwODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+gJJ1+QAAB8xJREFUeNrsWWts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)',
                '**TLP:RED - Not for disclosure, restricted to participants only.**'
            ]
        else:
            tlp = "unknown"

        return tlp

    def getCaseSummary(self, data):

        startDate = time.strftime(
            '%Y-%m-%dT%H:%M:%SZ',
            time.localtime(data['startDate'] /
                           1000))  #Convert epoch ms to sec then human readable
        severity = self.getSummary(data['severity'])

        if (data['tags'].__len__() == 0):
            tags = ["No tags found"]

        else:
            tags = (data['tags'])

        caseSummary = [
            ' ', ' ', '**Severity** ',
            str(severity), '**Created By** ',
            str(data['createdBy']), '**Assignee** ',
            str(data['owner']), '**Tags** ',
            str(', '.join(tags))
        ]

        if data['status'] == 'Resolved':
            closeDate = time.strftime(
                '%Y-%m-%dT%H:%M:%SZ', time.localtime(
                    data['endDate'] /
                    1000))  #Convert epoch ms to sec then human readable
            caseSummary.extend([
                '**Case status:** ', 'Closed', '**Start Date**', startDate,
                '**Close Date:** ', closeDate, '**Resolution:** ',
                data['resolutionStatus'], '**Summary:** <br>', data['summary']
            ])

        else:
            caseSummary.extend(
                ['**Case status:** ', 'Open', '**Start Date**', startDate])

        return caseSummary

    def getCaseObservables(self, case_observables):

        case_observables_sorted = sorted(case_observables,
                                         key=lambda k: k['createdAt'])
        caseObservables = [
            'Created At', 'Data Type', 'Data', 'Sighted', 'IOC', 'Tags'
        ]

        for observable in case_observables_sorted:

            createdAt = time.strftime(
                '%Y-%m-%dT%H:%M:%SZ',
                time.localtime(
                    observable['createdAt'] /
                    1000))  #Convert epoch ms to sec then human readable
            caseObservables.append(createdAt)
            caseObservables.append(str(observable['dataType']))

            if (observable['dataType'] == 'file'):
                caseObservables.append(str(observable['attachment']['name']))
            else:
                caseObservables.append(
                    str(observable['data'].replace('\n', '<br>').replace(
                        '.', '[.]').replace('http', 'hxxp')))

            caseObservables.append(str(observable['sighted']))
            caseObservables.append(str(observable['ioc']))
            caseObservables.append(str(', '.join(observable['tags'])))

        return caseObservables

    def getCaseTasks(self, caseId):

        response = self.api.get_case_tasks(caseId)
        caseTasks = (json.dumps(response.json(), indent=4, sort_keys=True))
        allTaskIds = {}

        # Build a list of tasks that we want to get the details for
        for task in json.loads(caseTasks):

            if (task['title'] == 'Autogenerated Report') or (task['status']
                                                             == 'Cancel'):
                continue

            else:
                taskId = task['id']

                try:
                    if (task['description']):
                        allTaskIds[taskId] = {
                            'taskGroup': task['group'],
                            'taskTitle': task['title'],
                            'createdAt': task['createdAt'],
                            'createdBy': task['createdBy'],
                            'owner': task['owner'],
                            'status': task['status'],
                            'description': task['description']
                        }

                except KeyError:
                    allTaskIds[taskId] = {
                        'taskGroup': task['group'],
                        'taskTitle': task['title'],
                        'createdAt': task['createdAt'],
                        'createdBy': task['createdBy'],
                        'owner': task['owner'],
                        'status': task['status'],
                        'description': 'No description specified'
                    }

        return allTaskIds

    def getCaseTaskLog(self, taskLogId):

        response = self.api.get_task_logs(taskLogId)
        caseTaskLog = (json.dumps(response.json(), indent=4, sort_keys=True))

        return caseTaskLog

    def getTlpFooter(self):

        tlpFooter = [
            'Color', 'When should it be used?', 'How may it be shared',
            'TLP:RED   <br> ![TLP:RED](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5M0JERkQyQzg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5M0JERkQyRDg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2NDVGRUZGODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjg2NDVGRjAwODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+gJJ1+QAAB8xJREFUeNrsWWts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)',
            "Sources may use TLP\:RED when information cannot be effectively acted upon by additional parties, and could lead to impacts on a party's privacy, reputation, or operations if misused.",
            "Recipients may not share TLP\:RED information with any parties outside of the specific exchange, meeting, or conversation in which it was originally disclosed. In the context of a meeting, for example, TLP\:RED information is limited to those present at the meeting. In most circumstances, TLP\:RED should be exchanged verbally or in person.",
            'TLP:AMBER <br> ![TLP:AMBER](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4NjQ1RkVGOTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4NjQ1RkVGQTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2NDVGRUY3ODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjg2NDVGRUY4ODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+11CCTgAAB/hJREFUeNrsWnts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)',
            "Sources may use TLP\:AMBER when information requires support to be effectively acted upon, yet carries risks to privacy, reputation, or operations if shared outside of the organizations involved.",
            "Recipients may only share TLP\:AMBER information with members of their own organization, and with clients or customers who need to know the information to protect themselves or prevent further harm. **Sources are at liberty to specify additional intended limits of the sharing\: these must be adhered to.**",
            'TLP:GREEN <br> ![TLP:GREEN](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4NjQ1RkVGRDg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4NjQ1RkVGRTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2NDVGRUZCODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjg2NDVGRUZDODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+I9OQdgAAB7xJREFUeNrsWWts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)',
            "Sources may use TLP\:GREEN when information is useful for the awareness of all participating organizations as well as with peers within the broader community or sector.",
            "Recipients may share TLP\:GREEN information with peers and partner organizations within their sector or community, but not via publicly accessible channels. Information in this category can be circulated widely within a particular community. TLP\:GREEN information may not be released outside of the community.",
            'TLP:WHITE <br> ![TLP:WHITE](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAAAeCAYAAABpE5PpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5M0JERkQzMDg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5M0JERkQzMTg4MEYxMUU2OUVDQkM2MTBGMkFBMjRDRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjkzQkRGRDJFODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjkzQkRGRDJGODgwRjExRTY5RUNCQzYxMEYyQUEyNENEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+49AQNQAACDpJREFUeNrsmWdo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)',
            "Sources may use TLP\:WHITE when information carries minimal or no foreseeable risk of misuse, in accordance with applicable rules and procedures for public release.",
            "Subject to standard copyright rules, TLP\:WHITE information may be distributed without restriction."
        ]

        return tlpFooter

    def addTask(self, caseId):

        response = self.api.create_case_task(
            caseId,
            CaseTask(title='Autogenerated Report',
                     startDate=int(time.time()) * 1000))
        if response.status_code == 201:
            return (json.dumps(response.json(), indent=4, sort_keys=True))

        else:
            self.error('ko: {}/{}'.format(response.status_code, response.text))

    def addTaskLog(self, taskId, filename):

        response = self.api.create_task_log(
            taskId, CaseTaskLog(message='Autogenerated report', file=filename))
        if response.status_code == 201:
            return (json.dumps(response.json(), indent=4, sort_keys=True))

        else:
            self.error('ko: {}/{}'.format(response.status_code, response.text))

    def run(self):
        Responder.run(self)

        caseNumber = self.get_param('data.caseId')  #Friendly case number
        caseId = self.get_param('data.id')  #Raw case number
        case_observables = self.api.get_case_observables(caseId).json()
        title = self.get_param('data.title', None, 'title is missing')
        description = self.get_param('data.description', None,
                                     'description is missing')
        tags = self.get_param('data.tags')
        data = self.get_param('data')
        tlp = self.getTLP(data['tlp'])

        # Title
        #mdFile = MdUtils(file_name=str(caseNumber),title=tlp[0] + ' Case #' + str(caseNumber) + ': ' + title)
        mdFile = MdUtils(file_name=str(self.tmpPath) + str(caseNumber),
                         title=tlp[0] + ' Case #' + str(caseNumber) + ': ' +
                         title)

        # Case Summary
        caseSummary = self.getCaseSummary(data)
        mdFile.new_header(level=1, title='Case Summary')
        mdFile.new_line(str(tlp[1]))

        mdFile.new_table(columns=2,
                         rows=int(caseSummary.__len__() / 2),
                         text=caseSummary,
                         text_align='left')

        # Case Description
        mdFile.new_line('<div style="page-break-after: always;"></div>')
        mdFile.new_line(' ')
        mdFile.new_header(level=1, title='Case Description')
        mdFile.new_line(str(data['description']))
        mdFile.new_line(' ')

        # Task Log
        allTaskIds = self.getCaseTasks(caseId)
        allTaskIds_sorted = sorted(allTaskIds.items(),
                                   key=lambda x: x[1]['createdAt'])
        mdFile.new_header(level=1, title='Task Log Entries')

        for task in allTaskIds_sorted:
            title = str(task[1]['taskGroup'] + ' \: ' + task[1]['taskTitle'])
            createdAt = time.strftime(
                '%Y-%m-%dT%H:%M:%SZ',
                time.localtime(
                    task[1]['createdAt'] /
                    1000))  #Convert epoch ms to sec then human readable
            mdFile.new_header(level=2, title=title)
            mdFile.new_line(str('**Created At:** ') + str(createdAt))
            mdFile.new_line(
                str('**Created By:** ') + str(task[1]['createdBy']))
            mdFile.new_line(str('**Assigned To:** ') + str(task[1]['owner']))
            mdFile.new_line(str('**Case Status:** ') + str(task[1]['status']))
            mdFile.new_line(' ')
            mdFile.new_line(str('**Description:** '))
            mdFile.new_line(str(task[1]['description']))
            mdFile.new_line(' ')

            caseTaskLog = self.getCaseTaskLog(task[0])
            caseTaskLogEntries = (json.loads(caseTaskLog))
            caseTaskLogEntries_sorted = sorted(caseTaskLogEntries,
                                               key=lambda k: k['createdAt'])

            for caseTaskLogEntry in caseTaskLogEntries_sorted:

                createdAt = time.strftime(
                    '%Y-%m-%dT%H:%M:%SZ',
                    time.localtime(
                        caseTaskLogEntry['createdAt'] /
                        1000))  #Convert epoch ms to sec then human readable
                mdFile.new_line(
                    str(createdAt) + ' : ' + str(caseTaskLogEntry['message']))

        # Case Observables
        mdFile.new_header(level=1, title='Case Observables')
        caseObservables = self.getCaseObservables(case_observables)
        mdFile.new_table(columns=6,
                         rows=int(caseObservables.__len__() / 6),
                         text=caseObservables,
                         text_align='left')

        # TLP Protocol description
        mdFile.new_line('<div style="page-break-after: always;"></div>')
        mdFile.new_line(' ')
        mdFile.new_header(
            level=1,
            title='Traffic Light Protocol (TLP) Definitions and Usage')
        tlpFooter = self.getTlpFooter()
        mdFile.new_table(columns=3, rows=5, text=tlpFooter, text_align='left')

        # Build TOC
        mdFile.new_table_of_contents(table_title='Table of Contents', depth=2)

        # Compile the report
        mdFile.create_md_file()

        # Add the report to the case
        addTask = json.loads(self.addTask(caseId))
        taskId = addTask['_id']

        # Add the MD file to the task
        addTaskLog = json.loads(
            self.addTaskLog(taskId,
                            str(self.tmpPath) + str(caseNumber) + '.md'))

        # Cleanup the MD file
        os.remove(str(self.tmpPath) + str(caseNumber) + '.md')

        self.report({'report': 'created'})
Пример #3
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """
    __version__ = "1.0.0"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        super().__init__(redis, logger, console_logger)

    #async def run_analyzer(self, apikey, url, title_query):
    #    self.thehive = TheHiveApi(url, apikey)

    #    response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
    #    return response.text


    async def search_cases(self, apikey, url, title_query):
        self.thehive = TheHiveApi(url, apikey)

        response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
        return response.text

    async def add_observable(self, apikey, url, case_id, data, datatype, tags):
        self.thehive = TheHiveApi(url, apikey)

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = []
        else:
            tags = []

        item = thehive4py.models.CaseObservable(
            dataType=datatype,
            data=data,
            tlp=1,
            ioc=False,
            sighted=False,
            tags=["Shuffle"],
            message="Created by shuffle",
        )

        return self.thehive.create_case_observable(case_id, item).text

    async def search_alerts(self, apikey, url, title_query, search_range="0-25"):
        self.thehive = TheHiveApi(url, apikey)

        # Could be "all" too
        if search_range == "":
            search_range = "0-25"

        response = self.thehive.find_alerts(query=String("title:'%s'" % title_query), range=search_range, sort=[])
        return response.text

    async def create_case(self, apikey, url, title, description="", tlp=1, severity=1, tags=""):
        self.thehive = TheHiveApi(url, apikey)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = []
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        case = thehive4py.models.Case(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
        )

        try:
            ret = self.thehive.create_case(case)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert(self, apikey, url, type, source, sourceref, title, description="", tlp=1, severity=1, tags=""):
        self.thehive = TheHiveApi(url, apikey)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = []
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 2 or tlp < 0:
            return "TLP needs to be a number from 0-2, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        alert = thehive4py.models.Alert(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            type=type,
            source=source,
            sourceRef=sourceref,
        )

        try:
            ret = self.thehive.create_alert(alert)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, apikey, url, field_type, cur_id): 
        self.thehive = TheHiveApi(url, apikey)

        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id + "?similarity=1") 
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return "%s is not implemented. See https://github.com/frikky/shuffle-apps for more info." % field_type

        return ret.text

    async def close_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey)
        return self.thehive.mark_alert_as_read(alert_id).text

    async def reopen_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey)
        return self.thehive.mark_alert_as_unread(alert_id).text

    async def create_case_from_alert(self, apikey, url, alert_id, case_template=None):
        self.thehive = TheHiveApi(url, apikey)
        response = self.thehive.promote_alert_to_case(alert_id=alert_id, case_template=case_template)
        return response.text

    async def merge_alert_into_case(self, apikey, url, alert_id, case_id):
        self.thehive = TheHiveApi(url, apikey)
        req = url + f"/api/alert/{alert_id}/merge/{case_id}"
        ret = requests.post(req, auth=self.thehive.auth)
        return ret.text

    # Not sure what the data should be
    async def update_field(self, apikey, url, field_type, cur_id, field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"): 
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass 
            
                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored": 
                    url = "%s/markAsRead" % url

                ret = requests.post(
                    url,
                    headers={
                        'Content-Type': 'application/json',
                        'Authorization': 'Bearer %s' % apikey
                    }
                )
            else:
                ret = requests.patch(
                    url,
                    headers={
                        'Content-Type': 'application/json',
                        'Authorization': 'Bearer %s' % apikey
                    }, 
                    json=newdata,
                )

            return str(ret.status_code)
        else:
            return "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info." % field_type

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def run_analyzer(self, apikey, url, cortex_id, analyzer_id, artifact_id):
        self.thehive = TheHiveApi(url, apikey)
        return self.thehive.run_analyzer(cortex_id, artifact_id, analyzer_id).text
Пример #4
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """

    __version__ = "1.0.0"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        super().__init__(redis, logger, console_logger)

    # async def run_analyzer(self, apikey, url, title_query):
    #    self.thehive = TheHiveApi(url, apikey, cert=False)

    #    response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
    #    return response.text

    async def search_cases(self, apikey, url, title_query):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        response = self.thehive.find_cases(query=ContainsString(
            "title", title_query),
                                           range="all",
                                           sort=[])
        return response.text

    async def search_query(self, apikey, url, search_for, custom_query):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        try:
            query = json.loads(custom_query)
        except:
            raise IOError("Invalid JSON payload received.")

        if search_for == "alert":
            response = self.thehive.find_alerts(query=query,
                                                range="all",
                                                sort=[])
        else:
            response = self.thehive.find_cases(query=query,
                                               range="all",
                                               sort=[])

        if response.status_code == 200:
            return response.text
        else:
            raise IOError(response.text)

    async def add_observable(self, apikey, url, case_id, data, datatype, tags):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        item = thehive4py.models.CaseObservable(
            dataType=datatype,
            data=data,
            tlp=1,
            ioc=False,
            sighted=False,
            tags=["Shuffle"],
            message="Created by shuffle",
        )

        return self.thehive.create_case_observable(case_id, item).text

    async def search_alerts(self,
                            apikey,
                            url,
                            title_query,
                            search_range="0-25"):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        # Could be "all" too
        if search_range == "":
            search_range = "0-25"

        response = self.thehive.find_alerts(query=ContainsString(
            "title", title_query),
                                            range=search_range,
                                            sort=[])
        return response.text

    async def create_case(self,
                          apikey,
                          url,
                          title,
                          description="",
                          tlp=1,
                          severity=1,
                          tags=""):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        case = thehive4py.models.Case(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
        )

        try:
            ret = self.thehive.create_case(case)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert(
        self,
        apikey,
        url,
        type,
        source,
        sourceref,
        title,
        description="",
        tlp=1,
        severity=1,
        tags="",
    ):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-3, not %s" % tlp

            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 1-3, not %s" % severity

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 3 or severity < 1:
            return "Severity needs to be a number from 1-3, not %d" % severity

        alert = thehive4py.models.Alert(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            type=type,
            source=source,
            sourceRef=sourceref,
        )

        try:
            ret = self.thehive.create_alert(alert)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert_artifact(self,
                                    apikey,
                                    url,
                                    alert_id,
                                    dataType,
                                    data,
                                    message=None,
                                    tlp="2",
                                    ioc="False",
                                    sighted="False",
                                    ignoreSimilarity="False",
                                    tags=None):
        self.thehive = TheHiveApi(url, apikey, cert=False, version=4)

        if tlp:
            tlp = int(tlp)
        else:
            tlp = 2

        ioc = ioc.lower().strip() == "true"
        sighted = sighted.lower().strip() == "true"
        ignoreSimilarity = ignoreSimilarity.lower().strip() == "true"

        if tags:
            tags = [x.strip() for x in tags.split(",")]
        else:
            tags = []

        alert_artifact = thehive4py.models.AlertArtifact(
            dataType=dataType,
            data=data,
            message=message,
            tlp=tlp,
            ioc=ioc,
            sighted=sighted,
            ignoreSimilarity=ignoreSimilarity,
            tags=tags)

        try:
            ret = self.thehive.create_alert_artifact(alert_id, alert_artifact)
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e
        if ret.status_code > 299:
            raise ConnectionError(ret.text)

        return ret.text

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, apikey, url, field_type, cur_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id + "?similarity=1")
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/shuffle-apps for more info."
                % field_type)

        return ret.text

    async def close_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        return self.thehive.mark_alert_as_read(alert_id).text

    async def reopen_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        return self.thehive.mark_alert_as_unread(alert_id).text

    async def create_case_from_alert(self,
                                     apikey,
                                     url,
                                     alert_id,
                                     case_template=None):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        response = self.thehive.promote_alert_to_case(
            alert_id=alert_id, case_template=case_template)
        return response.text

    async def merge_alert_into_case(self, apikey, url, alert_id, case_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        req = url + f"/api/alert/{alert_id}/merge/{case_id}"
        ret = requests.post(req, auth=self.thehive.auth)
        return ret.text

    # Not sure what the data should be
    async def update_field(self, apikey, url, field_type, cur_id, field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"):
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass

                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored":
                    url = "%s/markAsRead" % url

                ret = requests.post(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                )
            else:
                ret = requests.patch(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                    json=newdata,
                )

            return str(ret.status_code)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info."
                % field_type)

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def run_analyzer(self, apikey, url, cortex_id, analyzer_id,
                           artifact_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        return self.thehive.run_analyzer(cortex_id, artifact_id,
                                         analyzer_id).text

    # Creates a task log in TheHive with file
    async def create_task_log(self,
                              apikey,
                              url,
                              task_id,
                              message,
                              filedata={}):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        data = {"_json": """{"message": "%s"}""" % message}
        response = requests.post(
            "%s/api/case/task/%s/log" % (url, task_id),
            headers=headers,
            files=files,
            data=data,
        )
        return response.text

    # Creates an observable as a file in a case
    async def create_case_file_observable(self, apikey, url, case_id, tags,
                                          filedata):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        outerarray = {"dataType": "file", "tags": tags}
        data = {"_json": """%s""" % json.dumps(outerarray)}
        response = requests.post(
            "%s/api/case/%s/artifact" % (url, case_id),
            headers=headers,
            files=files,
            data=data,
        )
        return response.text
Пример #5
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """
    __version__ = "0.0.3"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        self.thehive = TheHiveApi(secret.url, secret.apikey)
        super().__init__(redis, logger, console_logger)

    async def show_secret(self):
        return "url=%s, apikey=%s" % (secret.url, secret.apikey)

    async def get_case_count(self, title_query):
        response = self.thehive.find_cases(query=String("title:'%s'" %
                                                        title_query),
                                           range='all',
                                           sort=[])
        casecnt = len(response.json())
        return casecnt

    async def string_contains(self, field, string_check):
        if string_check in field.lower():
            return True

        return False

    async def string_startswith(self, field, string_check):
        if field.lower().startswith(string_check):
            return True

        return False

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, field_type, cur_id):
        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id)
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info." % field_type

        newstr = str(ret.json()).replace("\'", "\"")
        newstr = newstr.replace("True", "true")
        newstr = newstr.replace("False", "false")
        return newstr

    # Not sure what the data should be
    async def update_field_string(self, field_type, cur_id, field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"):
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass

                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (secret.url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored":
                    url = "%s/markAsRead" % url

                ret = requests.post(url,
                                    headers={
                                        'Content-Type':
                                        'application/json',
                                        'Authorization':
                                        'Bearer %s' % secret.apikey
                                    })
            else:
                ret = requests.patch(
                    url,
                    headers={
                        'Content-Type': 'application/json',
                        'Authorization': 'Bearer %s' % secret.apikey
                    },
                    json=newdata,
                )

            return ret.status_code
        else:
            return 0