class GoAmlParser(): def __init__(self): self.misp_event = MISPEvent() def read_xml(self, data): self.tree = ET.fromstring(data) def parse_xml(self): self.first_itteration() for t in self.tree.findall('transaction'): self.itterate(t, 'transaction') def first_itteration(self): submission_date = self.tree.find('submission_date').text.split('+')[0] self.misp_event.timestamp = int( time.mktime(time.strptime(submission_date, "%Y-%m-%dT%H:%M:%S"))) for node in goAMLobjects['report']['nodes']: element = self.tree.find(node) if element is not None: self.itterate(element, element.tag) def itterate(self, tree, aml_type, referencing_uuid=None, relationship_type=None): objects = goAMLobjects[aml_type] referenced_uuid = referencing_uuid rel = relationship_type if aml_type not in nodes_to_ignore: try: mapping = goAMLmapping[aml_type] misp_object = MISPObject(name=mapping['misp_name']) for leaf in objects['leaves']: element = tree.find(leaf) if element is not None: object_relation = mapping[element.tag] attribute = { 'object_relation': object_relation, 'value': element.text } misp_object.add_attribute(**attribute) if aml_type == 'transaction': for node in objects['nodes']: element = tree.find(node) if element is not None: self.fill_transaction(element, element.tag, misp_object) self.misp_event.add_object(misp_object) last_object = self.misp_event.objects[-1] referenced_uuid = last_object.uuid if referencing_uuid and relationship_type: referencing_object = self.misp_event.get_object_by_uuid( referencing_uuid) referencing_object.add_reference(referenced_uuid, rel, None, **last_object) except KeyError: pass for node in objects['nodes']: element = tree.find(node) if element is not None: tag = element.tag if tag in relationship_to_keep: rel = tag[2:] if tag.startswith('t_') else tag self.itterate(element, element.tag, referencing_uuid=referenced_uuid, relationship_type=rel) @staticmethod def fill_transaction(element, tag, misp_object): if 't_from' in tag: from_funds = element.find('from_funds_code').text from_funds_attribute = { 'object_relation': 'from-funds-code', 'value': from_funds } misp_object.add_attribute(**from_funds_attribute) from_country = element.find('from_country').text from_country_attribute = { 'object_relation': 'from-country', 'value': from_country } misp_object.add_attribute(**from_country_attribute) if 't_to' in tag: to_funds = element.find('to_funds_code').text to_funds_attribute = { 'object_relation': 'to-funds-code', 'value': to_funds } misp_object.add_attribute(**to_funds_attribute) to_country = element.find('to_country').text to_country_attribute = { 'object_relation': 'to-country', 'value': to_country } misp_object.add_attribute(**to_country_attribute)
class GoAmlGeneration(object): def __init__(self, config): self.config = config self.parsed_uuids = defaultdict(list) def from_event(self, event): self.misp_event = MISPEvent() self.misp_event.load(event) def parse_objects(self): uuids = defaultdict(list) report_code = [] currency_code = [] for obj in self.misp_event.objects: obj_type = obj.name uuids[obj_type].append(obj.uuid) if obj_type == 'bank-account': try: report_code.append( obj.get_attributes_by_relation('report-code') [0].value.split(' ')[0]) currency_code.append( obj.get_attributes_by_relation('currency-code') [0].value) except: print('report_code or currency_code error') self.uuids, self.report_codes, self.currency_codes = uuids, report_code, currency_code def build_xml(self): self.xml = { 'header': "<report><rentity_id>{}</rentity_id><submission_code>E</submission_code>" .format(self.config), 'data': "" } if "STR" in self.report_codes: report_code = "STR" else: report_code = Counter(self.report_codes).most_common(1)[0][0] self.xml['header'] += "<report_code>{}</report_code>".format( report_code) submission_date = str(self.misp_event.timestamp).replace(' ', 'T') self.xml['header'] += "<submission_date>{}</submission_date>".format( submission_date) self.xml[ 'header'] += "<currency_code_local>{}</currency_code_local>".format( Counter(self.currency_codes).most_common(1)[0][0]) for trans_uuid in self.uuids.get('transaction'): self.itterate('transaction', 'transaction', trans_uuid, 'data') person_to_parse = [ person_uuid for person_uuid in self.uuids.get('person') if person_uuid not in self.parsed_uuids.get('person') ] if len(person_to_parse) == 1: self.itterate('person', 'reporting_person', person_to_parse[0], 'header') try: location_to_parse = [ location_uuid for location_uuid in self.uuids.get('geolocation') if location_uuid not in self.parsed_uuids.get('geolocation') ] if len(location_to_parse) == 1: self.itterate('geolocation', 'location', location_to_parse[0], 'header') except TypeError: pass self.xml['data'] += "</report>" def itterate(self, object_type, aml_type, uuid, xml_part): obj = self.misp_event.get_object_by_uuid(uuid) if object_type == 'transaction': self.xml[xml_part] += "<{}>".format(aml_type) self.fill_xml_transaction(object_type, obj.attributes, xml_part) self.parsed_uuids[object_type].append(uuid) if obj.ObjectReference: self.parseObjectReferences(object_type, xml_part, obj.ObjectReference) self.xml[xml_part] += "</{}>".format(aml_type) else: if 'to_' in aml_type or 'from_' in aml_type: relation_type = aml_type.split('_')[0] self.xml[ xml_part] += "<{0}_funds_code>{1}</{0}_funds_code>".format( relation_type, self.from_and_to_fields[relation_type] ['funds'].split(' ')[0]) self.itterate_normal_case(object_type, obj, aml_type, uuid, xml_part) self.xml[xml_part] += "<{0}_country>{1}</{0}_country>".format( relation_type, self.from_and_to_fields[relation_type]['country']) else: self.itterate_normal_case(object_type, obj, aml_type, uuid, xml_part) def itterate_normal_case(self, object_type, obj, aml_type, uuid, xml_part): self.xml[xml_part] += "<{}>".format(aml_type) self.fill_xml(object_type, obj, xml_part) self.parsed_uuids[object_type].append(uuid) if obj.ObjectReference: self.parseObjectReferences(object_type, xml_part, obj.ObjectReference) self.xml[xml_part] += "</{}>".format(aml_type) def parseObjectReferences(self, object_type, xml_part, references): for ref in references: next_uuid = ref.referenced_uuid next_object_type = ref.Object.get('name') relationship_type = ref.relationship_type self.parse_references(object_type, next_object_type, next_uuid, relationship_type, xml_part) def fill_xml_transaction(self, object_type, attributes, xml_part): from_and_to_fields = {'from': {}, 'to': {}} for attribute in attributes: object_relation = attribute.object_relation attribute_value = attribute.value if object_relation == 'date-posting': self.xml[xml_part] += "<late_deposit>True</late_deposit>" elif object_relation in ('from-funds-code', 'to-funds-code'): relation_type, field, _ = object_relation.split('-') from_and_to_fields[relation_type][field] = attribute_value continue elif object_relation in ('from-country', 'to-country'): relation_type, field = object_relation.split('-') from_and_to_fields[relation_type][field] = attribute_value continue try: self.xml[xml_part] += "<{0}>{1}</{0}>".format( goAMLmapping[object_type][object_relation], attribute_value) except KeyError: pass self.from_and_to_fields = from_and_to_fields def fill_xml(self, object_type, obj, xml_part): if obj.name == 'bank-account': for attribute in obj.attributes: if attribute.object_relation in ('personal-account-type', 'status-code'): attribute_value = attribute.value.split(' - ')[0] else: attribute_value = attribute.value try: self.xml[xml_part] += "<{0}>{1}</{0}>".format( goAMLmapping[object_type][attribute.object_relation], attribute_value) except KeyError: pass else: for attribute in obj.attributes: try: self.xml[xml_part] += "<{0}>{1}</{0}>".format( goAMLmapping[object_type][attribute.object_relation], attribute.value) except KeyError: pass def parse_references(self, object_type, next_object_type, uuid, relationship_type, xml_part): reference = referencesMapping[next_object_type] try: next_aml_type = reference[object_type].get('aml_type').format( relationship_type.split('_')[0]) try: bracket = reference[object_type].get('bracket').format( relationship_type) self.xml[xml_part] += "<{}>".format(bracket) self.itterate(next_object_type, next_aml_type, uuid, xml_part) self.xml[xml_part] += "</{}>".format(bracket) except KeyError: self.itterate(next_object_type, next_aml_type, uuid, xml_part) except KeyError: next_aml_type = reference.get('aml_type').format( relationship_type.split('_')[0]) bracket = reference.get('bracket').format(relationship_type) self.xml[xml_part] += "<{}>".format(bracket) self.itterate(next_object_type, next_aml_type, uuid, xml_part) self.xml[xml_part] += "</{}>".format(bracket)