mirror of https://github.com/MISP/misp-modules
				
				
				
			
		
			
				
	
	
		
			230 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			230 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
import json
 | 
						|
import requests
 | 
						|
import time
 | 
						|
 | 
						|
misperrors = {'error': 'Error'}
 | 
						|
mispattributes = {'input': ['btc'], 'output': ['text']}
 | 
						|
moduleinfo = {'version': '0.1', 'author': 'Sascha Rommelfangen',
 | 
						|
              'description': 'BTC expansion service to \
 | 
						|
                              get quick information from MISP attributes',
 | 
						|
              'module-type': ['hover']}
 | 
						|
 | 
						|
moduleconfig = []
 | 
						|
 | 
						|
blockchain_firstseen = 'https://blockchain.info/q/addressfirstseen/'
 | 
						|
blockchain_balance = 'https://blockchain.info/q/addressbalance/'
 | 
						|
blockchain_totalreceived = 'https://blockchain.info/q/getreceivedbyaddress/'
 | 
						|
blockchain_all = 'https://blockchain.info/rawaddr/{}?filter=5{}'
 | 
						|
converter = 'https://min-api.cryptocompare.com/data/pricehistorical?fsym=BTC&tsyms=USD,EUR&ts={}'
 | 
						|
converter_rls = 'https://min-api.cryptocompare.com/stats/rate/limit'
 | 
						|
result_text = ""
 | 
						|
g_rate_limit = 300
 | 
						|
start_time = 0
 | 
						|
conversion_rates = {}
 | 
						|
 | 
						|
 | 
						|
def get_consumption(output=False):
 | 
						|
    try:
 | 
						|
        req = requests.get(converter_rls)
 | 
						|
        jreq = req.json()
 | 
						|
        minute = str(jreq['Data']['calls_left']['minute'])
 | 
						|
        hour = str(jreq['Data']['calls_left']['hour'])
 | 
						|
    except Exception:
 | 
						|
        minute = str(-1)
 | 
						|
        hour = str(-1)
 | 
						|
    # Debug out for the console
 | 
						|
    print("Calls left this minute / hour: " + minute + " / " + hour)
 | 
						|
    return minute, hour
 | 
						|
 | 
						|
 | 
						|
def convert(btc, timestamp):
 | 
						|
    global g_rate_limit
 | 
						|
    global start_time
 | 
						|
    global now
 | 
						|
    global conversion_rates
 | 
						|
    date = time.strftime('%Y-%m-%d', time.localtime(timestamp))
 | 
						|
    # Lookup conversion rates in the cache:
 | 
						|
    if date in conversion_rates:
 | 
						|
        (usd, eur) = conversion_rates[date]
 | 
						|
    else:
 | 
						|
        # If not cached, we have to get the converion rates
 | 
						|
        # We have to be careful with rate limiting on the server side
 | 
						|
        if g_rate_limit == 300:
 | 
						|
            minute, hour = get_consumption()
 | 
						|
        g_rate_limit -= 1
 | 
						|
        now = time.time()
 | 
						|
        # delta = now - start_time
 | 
						|
        # print(g_rate_limit)
 | 
						|
        if g_rate_limit <= 10:
 | 
						|
            minute, hour = get_consumption(output=True)
 | 
						|
            if int(minute) <= 10:
 | 
						|
                # print(minute)
 | 
						|
                # get_consumption(output=True)
 | 
						|
                time.sleep(3)
 | 
						|
            else:
 | 
						|
                mprint(minute)
 | 
						|
                start_time = time.time()
 | 
						|
                g_rate_limit = int(minute)
 | 
						|
        try:
 | 
						|
            req = requests.get(converter.format(timestamp))
 | 
						|
            jreq = req.json()
 | 
						|
            usd = jreq['BTC']['USD']
 | 
						|
            eur = jreq['BTC']['EUR']
 | 
						|
            # Since we have the rates, store them in the cache
 | 
						|
            conversion_rates[date] = (usd, eur)
 | 
						|
        except Exception as ex:
 | 
						|
            mprint(ex)
 | 
						|
            get_consumption(output=True)
 | 
						|
    # Actually convert and return the values
 | 
						|
    u = usd * btc
 | 
						|
    e = eur * btc
 | 
						|
    return u, e
 | 
						|
 | 
						|
 | 
						|
def mprint(input):
 | 
						|
    # Prepare the final print
 | 
						|
    global result_text
 | 
						|
    result_text = result_text + "\n" + str(input)
 | 
						|
 | 
						|
 | 
						|
def handler(q=False):
 | 
						|
    global result_text
 | 
						|
    global conversion_rates
 | 
						|
    result_text = ""
 | 
						|
    # start_time = time.time()
 | 
						|
    # now = time.time()
 | 
						|
    if q is False:
 | 
						|
        return False
 | 
						|
    request = json.loads(q)
 | 
						|
    click = False
 | 
						|
    # This means the magnifying glass has been clicked
 | 
						|
    if request.get('persistent') == 1:
 | 
						|
        click = True
 | 
						|
    # Otherwise the attribute was only hovered over
 | 
						|
    if request.get('btc'):
 | 
						|
        btc = request['btc']
 | 
						|
    else:
 | 
						|
        return False
 | 
						|
    mprint("\nAddress:\t" + btc)
 | 
						|
    try:
 | 
						|
        req = requests.get(blockchain_all.format(btc, "&limit=50"))
 | 
						|
        jreq = req.json()
 | 
						|
    except Exception:
 | 
						|
        # print(e)
 | 
						|
        print(req.text)
 | 
						|
        result_text = "Not a valid BTC address"
 | 
						|
        r = {
 | 
						|
            'results': [
 | 
						|
                {
 | 
						|
                    'types': ['text'],
 | 
						|
                    'values':[
 | 
						|
                        str(result_text)
 | 
						|
                    ]
 | 
						|
                }
 | 
						|
            ]
 | 
						|
        }
 | 
						|
        return r
 | 
						|
 | 
						|
    n_tx = jreq['n_tx']
 | 
						|
    balance = float(jreq['final_balance'] / 100000000)
 | 
						|
    rcvd = float(jreq['total_received'] / 100000000)
 | 
						|
    sent = float(jreq['total_sent'] / 100000000)
 | 
						|
    output = 'Balance:\t{0:.10f} BTC (+{1:.10f} BTC / -{2:.10f} BTC)'
 | 
						|
    mprint(output.format(balance, rcvd, sent))
 | 
						|
    if click is False:
 | 
						|
        mprint("Transactions:\t" + str(n_tx) + "\t (previewing up to 5 most recent)")
 | 
						|
    else:
 | 
						|
        mprint("Transactions:\t" + str(n_tx))
 | 
						|
    if n_tx > 0:
 | 
						|
        mprint("======================================================================================")
 | 
						|
    i = 0
 | 
						|
    while i < n_tx:
 | 
						|
        if click is False:
 | 
						|
            try:
 | 
						|
                req = requests.get(blockchain_all.format(btc, "&limit=5&offset={}".format(i)))
 | 
						|
            except Exception as e:
 | 
						|
                # Lazy retry - cries for a function
 | 
						|
                print(e)
 | 
						|
                time.sleep(3)
 | 
						|
                req = requests.get(blockchain_all.format(btc, "&limit=5&offset={}".format(i)))
 | 
						|
            if n_tx > 5:
 | 
						|
                n_tx = 5
 | 
						|
        else:
 | 
						|
            try:
 | 
						|
                req = requests.get(blockchain_all.format(btc, "&limit=50&offset={}".format(i)))
 | 
						|
            except Exception as e:
 | 
						|
                # Lazy retry - cries for a function
 | 
						|
                print(e)
 | 
						|
                time.sleep(3)
 | 
						|
                req = requests.get(blockchain_all.format(btc, "&limit=50&offset={}".format(i)))
 | 
						|
        jreq = req.json()
 | 
						|
        if jreq['txs']:
 | 
						|
            for transactions in jreq['txs']:
 | 
						|
                sum = 0
 | 
						|
                sum_counter = 0
 | 
						|
                for tx in transactions['inputs']:
 | 
						|
                    script_old = tx['script']
 | 
						|
                    try:
 | 
						|
                        addr_in = tx['prev_out']['addr']
 | 
						|
                    except KeyError:
 | 
						|
                        addr_in = None
 | 
						|
                    try:
 | 
						|
                        prev_out = tx['prev_out']['value']
 | 
						|
                    except KeyError:
 | 
						|
                        prev_out = None
 | 
						|
                    if prev_out != 0 and addr_in == btc:
 | 
						|
                        datetime = time.strftime("%d %b %Y %H:%M:%S %Z", time.localtime(int(transactions['time'])))
 | 
						|
                        value = float(tx['prev_out']['value'] / 100000000)
 | 
						|
                        u, e = convert(value, transactions['time'])
 | 
						|
                        mprint("#" + str(n_tx - i) + "\t" + str(datetime) + "\t-{0:10.8f} BTC {1:10.2f} USD\t{2:10.2f} EUR".format(value, u, e).rstrip('0'))
 | 
						|
                        if script_old != tx['script']:
 | 
						|
                            i += 1
 | 
						|
                        else:
 | 
						|
                            sum_counter += 1
 | 
						|
                            sum += value
 | 
						|
                if sum_counter > 1:
 | 
						|
                    u, e = convert(sum, transactions['time'])
 | 
						|
                    mprint("\t\t\t\t\t----------------------------------------------")
 | 
						|
                    mprint("#" + str(n_tx - i) + "\t\t\t\t  Sum:\t-{0:10.8f} BTC {1:10.2f} USD\t{2:10.2f} EUR\n".format(sum, u, e).rstrip('0'))
 | 
						|
                for tx in transactions['out']:
 | 
						|
                    try:
 | 
						|
                        addr_out = tx['addr']
 | 
						|
                    except KeyError:
 | 
						|
                        addr_out = None
 | 
						|
                    try:
 | 
						|
                        prev_out = tx['prev_out']['value']
 | 
						|
                    except KeyError:
 | 
						|
                        prev_out = None
 | 
						|
                    if prev_out != 0 and addr_out == btc:
 | 
						|
                        datetime = time.strftime("%d %b %Y %H:%M:%S %Z", time.localtime(int(transactions['time'])))
 | 
						|
                        value = float(tx['value'] / 100000000)
 | 
						|
                        u, e = convert(value, transactions['time'])
 | 
						|
                        mprint("#" + str(n_tx - i) + "\t" + str(datetime) + "\t {0:10.8f} BTC {1:10.2f} USD\t{2:10.2f} EUR".format(value, u, e).rstrip('0'))
 | 
						|
                        # i += 1
 | 
						|
                i += 1
 | 
						|
 | 
						|
    r = {
 | 
						|
        'results': [
 | 
						|
            {
 | 
						|
                'types': ['text'],
 | 
						|
                'values':[
 | 
						|
                    str(result_text)
 | 
						|
                ]
 | 
						|
            }
 | 
						|
        ]
 | 
						|
    }
 | 
						|
    # Debug output on the console
 | 
						|
    print(result_text)
 | 
						|
    # Unset the result for the next request
 | 
						|
    result_text = ""
 | 
						|
    return r
 | 
						|
 | 
						|
 | 
						|
def introspection():
 | 
						|
    return mispattributes
 | 
						|
 | 
						|
 | 
						|
def version():
 | 
						|
    moduleinfo['config'] = moduleconfig
 | 
						|
    return moduleinfo
 |