2016-07-25 18:48:08 +02:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
import collections
2016-07-28 11:54:14 +02:00
import re
2016-07-25 18:48:08 +02:00
2016-07-28 16:01:27 +02:00
try :
import requests
HAS_REQUESTS = True
except ImportError :
HAS_REQUESTS = False
2016-07-25 18:48:08 +02:00
class Entry ( ) :
2016-10-12 14:22:19 +02:00
def __init__ ( self , value , expanded , colour , description ) :
2016-07-25 18:48:08 +02:00
self . value = value
2016-10-12 14:22:19 +02:00
self . expanded = expanded
self . colour = colour
2016-07-26 10:56:40 +02:00
self . description = None
if description :
2016-10-12 14:22:19 +02:00
self . description = description
2016-07-25 18:48:08 +02:00
2016-07-26 10:30:25 +02:00
def __str__ ( self ) :
return self . value
2016-07-25 18:48:08 +02:00
class Predicate ( collections . Mapping ) :
2016-10-12 14:22:19 +02:00
def __init__ ( self , predicate , description , colour , entries ) :
2016-07-25 18:48:08 +02:00
self . predicate = predicate
2016-07-26 10:56:40 +02:00
self . description = None
2016-10-12 14:22:19 +02:00
self . colour = colour
2016-07-26 10:56:40 +02:00
if description :
2016-10-12 14:22:19 +02:00
self . description = description
2016-07-25 18:48:08 +02:00
self . entries = { }
if entries :
self . __init_entries ( entries )
def __init_entries ( self , entries ) :
for e in entries :
self . entries [ e [ ' value ' ] ] = Entry ( e [ ' value ' ] , e [ ' expanded ' ] ,
2016-10-12 14:22:19 +02:00
e . get ( ' colour ' ) , e . get ( ' description ' ) )
2016-07-25 18:48:08 +02:00
2016-07-26 10:30:25 +02:00
def __str__ ( self ) :
return self . predicate
2016-07-25 18:48:08 +02:00
def __getitem__ ( self , entry ) :
return self . entries [ entry ]
def __iter__ ( self ) :
return iter ( self . entries )
def __len__ ( self ) :
2016-10-05 18:10:23 +02:00
return len ( self . entries . keys ( ) )
2016-07-25 18:48:08 +02:00
class Taxonomy ( collections . Mapping ) :
def __init__ ( self , taxonomy ) :
self . taxonomy = taxonomy
self . name = self . taxonomy [ ' namespace ' ]
self . description = self . taxonomy [ ' description ' ]
self . version = self . taxonomy [ ' version ' ]
2016-10-05 18:10:23 +02:00
self . expanded = self . taxonomy . get ( ' expanded ' )
2016-10-12 14:22:19 +02:00
self . refs = self . taxonomy . get ( ' refs ' )
2016-07-25 18:48:08 +02:00
self . __init_predicates ( )
def __init_predicates ( self ) :
self . predicates = { }
entries = { }
if self . taxonomy . get ( ' values ' ) :
for v in self . taxonomy [ ' values ' ] :
if not entries . get ( v [ ' predicate ' ] ) :
entries [ v [ ' predicate ' ] ] = [ ]
entries [ v [ ' predicate ' ] ] + = v [ ' entry ' ]
for p in self . taxonomy [ ' predicates ' ] :
self . predicates [ p [ ' value ' ] ] = Predicate ( p [ ' value ' ] , p . get ( ' expanded ' ) ,
2016-10-12 14:22:19 +02:00
p . get ( ' colour ' ) , entries . get ( p [ ' value ' ] ) )
2016-07-25 18:48:08 +02:00
2016-10-05 18:10:23 +02:00
def has_entries ( self ) :
if self . predicates . values ( ) and list ( self . predicates . values ( ) ) [ 0 ] . entries :
return True
return False
2016-07-25 18:48:08 +02:00
def __str__ ( self ) :
2016-07-28 11:54:14 +02:00
return ' \n ' . join ( self . machinetags ( ) )
2016-07-26 10:30:25 +02:00
2016-10-05 18:10:23 +02:00
def make_machinetag ( self , predicate , entry = None ) :
if entry :
return ' {} : {} = " {} " ' . format ( self . name , predicate , entry )
else :
return ' {} : {} ' . format ( self . name , predicate )
2016-07-26 10:30:25 +02:00
def machinetags ( self ) :
2016-07-28 11:54:14 +02:00
to_return = [ ]
2016-07-25 18:48:08 +02:00
for p , content in self . predicates . items ( ) :
if content :
for k in content . keys ( ) :
2016-07-28 11:54:14 +02:00
to_return . append ( ' {} : {} = " {} " ' . format ( self . name , p , k ) )
2016-07-25 18:48:08 +02:00
else :
2016-07-28 11:54:14 +02:00
to_return . append ( ' {} : {} ' . format ( self . name , p ) )
2016-07-25 18:48:08 +02:00
return to_return
def __getitem__ ( self , predicate ) :
return self . predicates [ predicate ]
def __iter__ ( self ) :
return iter ( self . predicates )
def __len__ ( self ) :
return len ( self . predicates )
def amount_entries ( self ) :
2016-10-05 18:10:23 +02:00
if self . has_entries ( ) :
return sum ( [ len ( e ) for e in self . predicates . values ( ) ] )
else :
return len ( self . predicates . keys ( ) )
2016-07-25 18:48:08 +02:00
2016-07-26 10:30:25 +02:00
def machinetags_expanded ( self ) :
2016-07-28 11:54:14 +02:00
to_return = [ ]
2016-07-25 18:48:08 +02:00
for p , content in self . predicates . items ( ) :
if content :
for k , entry in content . items ( ) :
2016-07-28 11:54:14 +02:00
to_return . append ( ' {} : {} = " {} " ' . format ( self . name , p , entry . expanded . decode ( ) ) )
2016-07-25 18:48:08 +02:00
else :
2016-07-28 11:54:14 +02:00
to_return . append ( ' {} : {} ' . format ( self . name , p ) )
2016-07-25 18:48:08 +02:00
return to_return
class Taxonomies ( collections . Mapping ) :
def __init__ ( self , manifest_url = ' https://raw.githubusercontent.com/MISP/misp-taxonomies/master/MANIFEST.json ' ,
manifest_path = None ) :
if manifest_path :
self . loader = self . __load_path
self . manifest = self . loader ( manifest_path )
else :
self . loader = self . __load_url
self . manifest = self . loader ( manifest_url )
if manifest_path :
self . url = os . path . dirname ( os . path . realpath ( manifest_path ) )
2016-07-25 19:38:17 +02:00
else :
self . url = self . manifest [ ' url ' ]
2016-07-25 18:48:08 +02:00
self . version = self . manifest [ ' version ' ]
self . license = self . manifest [ ' license ' ]
self . description = self . manifest [ ' description ' ]
self . __init_taxonomies ( )
def __load_path ( self , path ) :
with open ( path , ' r ' ) as f :
return json . load ( f )
def __load_url ( self , url ) :
2016-07-28 16:01:27 +02:00
if not HAS_REQUESTS :
raise Exception ( " Python module ' requests ' isn ' t installed, unable to fetch the taxonomies. " )
2016-07-25 18:48:08 +02:00
return requests . get ( url ) . json ( )
def __make_uri ( self , taxonomy_name ) :
2016-07-25 19:38:17 +02:00
return ' {} / {} / {} ' . format ( self . url , taxonomy_name , self . manifest [ ' path ' ] )
2016-07-25 18:48:08 +02:00
def __init_taxonomies ( self ) :
self . taxonomies = { }
for t in self . manifest [ ' taxonomies ' ] :
uri = self . __make_uri ( t [ ' name ' ] )
tax = self . loader ( uri )
self . taxonomies [ t [ ' name ' ] ] = Taxonomy ( tax )
2016-10-05 18:10:23 +02:00
if t [ ' name ' ] != self . taxonomies [ t [ ' name ' ] ] . name :
raise Exception ( " The name of the taxonomy in the manifest ( {} ) doesn ' t match with the name in the taxonomy ( {} ) " . format ( t [ ' name ' ] , self . taxonomies [ t [ ' name ' ] ] . name ) )
2016-07-25 18:48:08 +02:00
def __getitem__ ( self , name ) :
return self . taxonomies [ name ]
def __iter__ ( self ) :
return iter ( self . taxonomies )
def __len__ ( self ) :
return len ( self . taxonomies )
def __str__ ( self ) :
2016-07-28 11:54:14 +02:00
to_print = ' '
2016-07-29 11:28:16 +02:00
for taxonomy in self . taxonomies . values ( ) :
to_print + = " {} \n \n " . format ( str ( taxonomy ) )
2016-07-28 11:54:14 +02:00
return to_print
def search ( self , query , expanded = False ) :
query = query . lower ( )
to_return = [ ]
for taxonomy in self . taxonomies . values ( ) :
if expanded :
machinetags = taxonomy . machinetags_expanded ( )
else :
machinetags = taxonomy . machinetags ( )
for mt in machinetags :
entries = [ e . lower ( ) for e in re . findall ( ' [^:= " ]* ' , mt ) if e ]
for e in entries :
if e . startswith ( query ) or e . endswith ( query ) :
to_return . append ( mt )
2016-07-25 18:48:08 +02:00
return to_return
2016-07-28 11:54:14 +02:00
2016-10-05 18:10:23 +02:00
def revert_machinetag ( self , machinetag ) :
if ' = ' in machinetag :
name , predicat , entry = re . findall ( ' ^([^:]*):([^=]*)= " ([^ " ]*) " $ ' , machinetag ) [ 0 ]
else :
name , predicat = re . findall ( ' ^([^:]*):([^=]*)$ ' , machinetag ) [ 0 ]
entry = None
if entry :
return self . taxonomies [ name ] , self . taxonomies [ name ] [ predicat ] , self . taxonomies [ name ] [ predicat ] [ entry ]
else :
return self . taxonomies [ name ] , self . taxonomies [ name ] [ predicat ]
2016-07-28 11:54:14 +02:00
def all_machinetags ( self , expanded = False ) :
if expanded :
return [ taxonomy . machinetags_expanded ( ) for taxonomy in self . taxonomies . values ( ) ]
return [ taxonomy . machinetags ( ) for taxonomy in self . taxonomies . values ( ) ]