#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 
# Copy Emerging Threats Block IPs list to several MISP events
# Because of the large size of the list the first run will take a minute
# Running it again will update the MISP events if changes are detected
#
# This script requires PyMISP 2.4.50 or later

import sys, json, time, requests
from pymisp import PyMISP
from keys import misp_url, misp_key, misp_verifycert

et_url = 'https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt'
et_str = 'Emerging Threats '

def init_misp():
    global mymisp
    mymisp = PyMISP(misp_url, misp_key, misp_verifycert)

def load_misp_event(eid):
    global et_attr
    global et_drev
    global et_event
    et_attr = {}
    et_drev = {}
    
    et_event = mymisp.get(eid)
    echeck(et_event)
    for a in et_event['Event']['Attribute']:
        if a['category'] == 'Network activity':
            et_attr[a['value']] = a['id']
            continue
        if a['category'] == 'Internal reference':
            et_drev = a;

def init_et():
    global et_data
    global et_rev
    requests.packages.urllib3.disable_warnings()
    s = requests.Session()
    r = s.get(et_url)
    if r.status_code != 200:
        raise Exception('Error getting ET data: {}'.format(r.text))
    name = ''
    et_data = {}
    et_rev = 0
    for line in r.text.splitlines():
        if line.startswith('# Rev '):
            et_rev = int(line[6:])
            continue
        if line.startswith('#'):
            name = line[1:].strip()
            if et_rev and not et_data.get(name):
                et_data[name] = {}
            continue
        l = line.rstrip()
        if l:
            et_data[name][l] = name

def update_et_event(name):
    if et_drev and et_rev and int(et_drev['value']) < et_rev:
        # Copy MISP attributes to new dict
        et_ips = dict.fromkeys(et_attr.keys())

        # Weed out attributes still in ET data
        for k,v in et_data[name].items():
            et_attr.pop(k, None)
        
        # Delete the leftover attributes from MISP
        for k,v in et_attr.items():
            r = mymisp.delete_attribute(v)
            if r.get('errors'):
                print "Error deleting attribute {} ({}): {}\n".format(v,k,r['errors'])

        # Weed out ips already in the MISP event
        for k,v in et_ips.items():
            et_data[name].pop(k, None)

        # Add new attributes to MISP event
        ipdst = []
        for i,k in enumerate(et_data[name].items(), 1-len(et_data[name])):
            ipdst.append(k[0])
            if i % 100 == 0:
                r = mymisp.add_ipdst(et_event, ipdst)
                echeck(r, et_event['Event']['id'])
                ipdst = []

        # Update revision number
        et_drev['value'] = et_rev
        et_drev.pop('timestamp', None)
        attr = []
        attr.append(et_drev)

        # Publish updated MISP event 
        et_event['Event']['Attribute'] = attr
        et_event['Event']['published'] = False
        et_event['Event']['date'] = time.strftime('%Y-%m-%d')
        r = mymisp.publish(et_event)
        echeck(r, et_event['Event']['id'])

def echeck(r, eid=None):
    if r.get('errors'):
        if eid:
            print "Processing event {} failed: {}".format(eid, r['errors'])
        else:
            print r['errors']
        sys.exit(1)

if __name__ == '__main__':
    init_misp()
    init_et()

    for et_type in set(et_data.keys()):
        info = et_str + et_type
        r = mymisp.search_index(eventinfo=info)
        if r['response']:
            eid=r['response'][0]['id']
        else: # event not found, create it
            new_event = mymisp.new_event(info=info, distribution=3, threat_level_id=4, analysis=1)
            echeck(new_event)
            eid=new_event['Event']['id']
            r = mymisp.add_internal_text(new_event, 1, comment='Emerging Threats revision number')
            echeck(r, eid)
        load_misp_event(eid)
        update_et_event(et_type)