async def create_case_task(self, case_id, url, api_key, data=None): self.logger.info(f'Creating task for {case_id} in TheHive...') if not url.startswith("http"): url = f"http://{url}" api = TheHiveApi(url, api_key) results = {} for item in data: try: title = item["title"] description = item["description"] startDate = time.time_ns() // 1000000 task = CaseTask(title=title, description=description, startDate=startDate) r = api.create_case_task(case_id, task) if r.status_code == 201: results[title] = r.json() else: raise IOError(r.text) except Exception as e: self.console_logger.info(f"Failed to create task with input {item} because: {e}") return results
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) # 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, version=3): if organisation: self.thehive = TheHiveApi(url, apikey, cert=False, organisation=organisation, version=version) else: self.thehive = TheHiveApi(url, apikey, cert=False, version=version) 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 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) 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 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 def create_case( self, apikey, url, organisation, template, title, description="", tlp=None, pap=None, severity=None, flag=None, tags="", custom_fields=None, custom_json=None, ): self.__connect_thehive(url, apikey, organisation) flag = False if flag.lower() == "false" else True pap = int(pap) if pap else 2 tlp = int(tlp) if tlp else 2 severity = int(severity) if severity else 2 tags = tags.split(",") if tags else [] if tlp > 3 or tlp < 0: return f"TLP needs to be a number from 0-3, not {tlp}" if severity > 4 or severity < 1: return f"Severity needs to be a number from 1-4, not {severity}" Casetemplate = template if template else None # Prepare the customfields customfields = CustomFieldHelper() try: custom_fields = json.loads(custom_fields) if custom_fields else {} except json.decoder.JSONDecodeError: return "Custom fields need to be valid json" 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.' ) # Fields in JSON customfields = customfields.build() custom_json = json.loads(custom_json) if custom_json else {} case = thehive4py.models.Case( title=title, tlp=tlp, pap=pap, severity=severity, flag=flag, tags=tags, description=description, template=Casetemplate, customFields=customfields, json=custom_json, ) try: ret = self.thehive.create_case(case) return ret.text except requests.exceptions.ConnectionError as e: return "ConnectionError: %s" % e 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 def add_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 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 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 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 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 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 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) elif field_type.lower() == 'case': return 'Use update_case action for updating a case.' 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 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 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 def add_task_log( self, apikey, url, organisation, task_id, message, filedata={}, mime_type=None, ): try: if filedata["success"] == False: return "No file to upload. Skipping message." except Exception as e: print(f"[WARNING] Error in filedata handler for {filedata}: {e}") headers = { "Authorization": f"Bearer {apikey}", } organisation = organisation.strip() if organisation: headers["X-Organisation"] = organisation files = {} try: if len(filedata["data"]) > 0: files = { "attachment": (filedata["filename"], filedata["data"], mime_type), } except Exception as e: print(f"[WARNING] Error in file handler for {filedata} (2): {e}") data = {"message": f"{message}"} response = requests.post( f"{url}/api/case/task/{task_id}/log", headers=headers, files=files, data=data, ) return response.text # Creates an artifact as a file in a case def create_case_file_artifact(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 # Create an observable as a file for an alert def create_alert_file_observable(self, apikey, url, organisation, alert_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/alert/%s/artifact" % (url, alert_id), headers=headers, files=files, data=data, verify=False, ) return response.text # Get all artifacts of a given case 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}" 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 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_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.' ) try: custom_fields = json.loads(custom_fields) if custom_fields else {} except json.decoder.JSONDecodeError: return "Custom fields need to be valid json" 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 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 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 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 # Update TheHive case Artifact def update_case_artifact( self, apikey, url, organisation, id, description=None, tlp=None, ioc=None, sighted=None, tags=None, custom_json=None, ): self.__connect_thehive(url, apikey, organisation) # Get Artifact Data artifact = self.thehive.get_case_observable(id).json() # Prepare fields to be updated ## Message (description): artifact_message = ( (artifact["message"] + " " + description[1:] if "*" == description[0] else description) if description else artifact["message"]) ## TLP, PAP, IOC, Sighted artifact_tlp = int(tlp) if tlp else artifact["tlp"] artifact_ioc = ((False if ioc.lower() == "false" else True) if ioc else artifact["ioc"]) artifact_sighted = ((False if sighted.lower() == "false" else True) if sighted else artifact["sighted"]) ## Tags: if tags: if "*" == tags[0]: artifact_tags = tags[1:].split(",") artifact_tags.extend(artifact["tags"]) else: artifact_tags = tags.split(",") else: artifact_tags = artifact["tags"] ## Custom Json: custom_json = json.loads(custom_json) if custom_json else {} artifact = CaseObservable( id=id, message=artifact_message, tlp=artifact_tlp, ioc=artifact_ioc, sighted=artifact_sighted, tags=artifact_tags, json=custom_json, ) response = self.thehive.update_case_observables( artifact, fields=["message", "tlp", "ioc", "sighted", "tags"]) return response.text # Create TheHive case Task def create_task( self, apikey, url, organisation, case_id, title, description=None, status=None, flag=None, group=None, custom_json=None, ): self.__connect_thehive(url, apikey, organisation) # Prepare flag field flag = False if flag.lower() == "false" else True start_date = (round(time.time() * 1000) if status.lower() == "inprogress" else None) case_task = CaseTask( title=title, description=description, status=status, startDate=start_date, flag=flag, group=group, json=custom_json, ) response = self.thehive.create_case_task(case_id, case_task) return response.text # Close TheHive case Task def update_task(self, apikey, url, organisation, task_id, status): if status == "Completed": # Add EndDate Time before close headers = { "Authorization": f"Bearer {apikey}", } if organisation: headers["X-Organisation"] = organisation data = {"endDate": round(time.time() * 1000)} requests.patch( f"{url}/api/case/task/{task_id}", headers=headers, data=data, ) task = CaseTask( id=task_id, status="Completed", ) else: task = CaseTask( id=task_id, status=status, ) response = self.thehive.update_case_task(task, fields=["status"]) return response.text
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'})
id = response.json()['id'] else: print('ko: {}/{}'.format(response.status_code, response.text)) sys.exit(0) # Get all the details of the created case print('Get created case {}'.format(id)) print('-----------------------------') response = api.get_case(id) if response.status_code == requests.codes.ok: print(json.dumps(response.json(), indent=4, sort_keys=True)) print('') else: print('ko: {}/{}'.format(response.status_code, response.text)) # Add a new task to the created case print('Add a task {}'.format(id)) print('-----------------------------') response = api.create_case_task( id, CaseTask(title='Yet Another Task', status='InProgress', owner='nabil', flag=True, startDate=int(time.time()) * 1000)) if response.status_code == 201: print(json.dumps(response.json(), indent=4, sort_keys=True)) print('') else: print('ko: {}/{}'.format(response.status_code, response.text))