2014-03-19 19:10:36 +01:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
2016-08-26 14:19:19 +02:00
""" Python API using the REST interface of MISP """
2014-03-19 19:10:36 +01:00
2016-11-03 21:01:48 +01:00
import sys
2015-02-16 14:31:29 +01:00
import json
import datetime
2015-08-04 16:24:55 +02:00
import os
import base64
2015-09-18 12:03:56 +02:00
import re
2016-10-19 18:46:47 +02:00
import warnings
2015-09-18 12:03:56 +02:00
2015-09-02 13:56:08 +02:00
try :
from urllib . parse import urljoin
except ImportError :
from urlparse import urljoin
2016-11-17 17:29:54 +01:00
warnings . warn ( " You ' re using python 2, it is strongly recommended to use python >=3.4 " )
2015-09-12 23:08:06 +02:00
from io import BytesIO
2015-08-07 17:24:03 +02:00
import zipfile
2014-04-14 10:55:20 +02:00
2015-09-18 12:03:56 +02:00
try :
import requests
HAVE_REQUESTS = True
except ImportError :
HAVE_REQUESTS = False
from . import __version__
2016-09-28 18:20:37 +02:00
from . exceptions import PyMISPError , SearchError , MissingDependency , NoURL , NoKey
2016-09-27 19:47:22 +02:00
from . mispevent import MISPEvent , MISPAttribute , EncodeUpdate
2015-09-18 12:03:56 +02:00
2016-09-28 18:20:37 +02:00
2015-09-02 13:56:08 +02:00
# Least dirty way to support python 2 and 3
try :
basestring
2016-11-17 17:29:54 +01:00
warnings . warn ( " You ' re using python 2, it is strongly recommended to use python >=3.4 " )
2015-09-02 13:56:08 +02:00
except NameError :
basestring = str
2015-08-05 16:01:57 +02:00
2016-08-16 16:51:35 +02:00
class distributions ( object ) :
""" Enumeration of the available distributions. """
your_organization = 0
this_community = 1
connected_communities = 2
all_communities = 3
2017-01-09 16:19:20 +01:00
sharing_group = 4
2016-08-16 16:51:35 +02:00
2017-01-16 20:47:43 +01:00
2016-08-16 16:51:35 +02:00
class threat_level ( object ) :
""" Enumeration of the available threat levels. """
high = 1
medium = 2
low = 3
undefined = 4
class analysis ( object ) :
""" Enumeration of the available analysis statuses. """
initial = 0
ongoing = 1
completed = 2
2014-04-11 18:45:52 +02:00
class PyMISP ( object ) :
2017-01-16 15:27:44 +01:00
""" Python API for MISP
: param url : URL of the MISP instance you want to connect to
: param key : API key of the user you want to use
: param ssl : can be True or False ( to check ot not the validity
of the certificate . Or a CA_BUNDLE in case of self
signed certiifcate ( the concatenation of all the
* . crt of the chain )
: param out_type : Type of object ( json ) NOTE : XML output isn ' t supported anymore, keeping the flag for compatibility reasons.
: param debug : print all the messages received from the server
: param proxies : Proxy dict as describes here : http : / / docs . python - requests . org / en / master / user / advanced / #proxies
: param cert : Client certificate , as described there : http : / / docs . python - requests . org / en / master / user / advanced / #ssl-cert-verification
2014-04-16 14:09:56 +02:00
"""
2016-08-16 16:51:35 +02:00
# So it can may be accessed from the misp object.
distributions = distributions
threat_level = threat_level
analysis = analysis
2016-08-26 09:11:01 +02:00
def __init__ ( self , url , key , ssl = True , out_type = ' json ' , debug = False , proxies = None , cert = None ) :
2015-09-18 17:48:10 +02:00
if not url :
raise NoURL ( ' Please provide the URL of your MISP instance. ' )
if not key :
raise NoKey ( ' Please provide your authorization key. ' )
2015-08-07 17:24:03 +02:00
self . root_url = url
2014-04-11 18:45:52 +02:00
self . key = key
2014-04-16 14:09:56 +02:00
self . ssl = ssl
2016-07-28 09:49:40 +02:00
self . proxies = proxies
2016-08-26 09:11:01 +02:00
self . cert = cert
2016-10-11 11:22:31 +02:00
self . ressources_path = os . path . join ( os . path . abspath ( os . path . dirname ( __file__ ) ) , ' data ' )
2016-08-09 13:58:54 +02:00
if out_type != ' json ' :
raise PyMISPError ( ' The only output type supported by PyMISP is JSON. If you still rely on XML, use PyMISP v2.4.49 ' )
2015-11-25 09:51:22 +01:00
self . debug = debug
2014-04-11 18:45:52 +02:00
2015-09-21 14:40:06 +02:00
try :
# Make sure the MISP instance is working and the URL is valid
2016-12-14 15:42:43 +01:00
response = self . get_version ( )
misp_version = response [ ' version ' ] . split ( ' . ' )
pymisp_version = __version__ . split ( ' . ' )
for a , b in zip ( misp_version , pymisp_version ) :
if a == b :
continue
elif a < b :
warnings . warn ( " Remote MISP instance (v {} ) older than PyMISP (v {} ). You should update your MISP instance, or install an older PyMISP version. " . format ( response [ ' version ' ] , __version__ ) )
else : # a > b
# NOTE: That can happen and should not be blocking
warnings . warn ( " Remote MISP instance (v {} ) newer than PyMISP (v {} ). Please check if a newer version of PyMISP is available. " . format ( response [ ' version ' ] , __version__ ) )
continue
2015-09-21 14:40:06 +02:00
except Exception as e :
raise PyMISPError ( ' Unable to connect to MISP ( {} ). Please make sure the API key and the URL are correct (http/https is required): {} ' . format ( self . root_url , e ) )
2016-10-10 12:24:17 +02:00
try :
session = self . __prepare_session ( )
response = session . get ( urljoin ( self . root_url , ' attributes/describeTypes.json ' ) )
describe_types = self . _check_response ( response )
if describe_types . get ( ' error ' ) :
for e in describe_types . get ( ' error ' ) :
raise PyMISPError ( ' Failed: {} ' . format ( e ) )
self . describe_types = describe_types [ ' result ' ]
if not self . describe_types . get ( ' sane_defaults ' ) :
raise PyMISPError ( ' The MISP server your are trying to reach is outdated (<2.4.52). Please use PyMISP v2.4.51.1 (pip install -I PyMISP==v2.4.51.1) and/or contact your administrator. ' )
except :
describe_types = json . load ( open ( os . path . join ( self . ressources_path , ' describeTypes.json ' ) , ' r ' ) )
self . describe_types = describe_types [ ' result ' ]
self . categories = self . describe_types [ ' categories ' ]
self . types = self . describe_types [ ' types ' ]
self . category_type_mapping = self . describe_types [ ' category_type_mappings ' ]
self . sane_default = self . describe_types [ ' sane_defaults ' ]
2016-04-14 10:29:36 +02:00
2016-08-11 17:45:32 +02:00
def __prepare_session ( self , output = ' json ' ) :
2017-01-16 15:27:44 +01:00
""" Prepare the headers of the session """
2015-09-18 12:03:56 +02:00
if not HAVE_REQUESTS :
raise MissingDependency ( ' Missing dependency, install requests (`pip install requests`) ' )
2014-04-11 18:45:52 +02:00
session = requests . Session ( )
2014-04-16 14:09:56 +02:00
session . verify = self . ssl
2016-07-28 09:49:40 +02:00
session . proxies = self . proxies
2016-08-26 09:11:01 +02:00
session . cert = self . cert
2014-04-14 10:55:20 +02:00
session . headers . update (
{ ' Authorization ' : self . key ,
2016-08-11 17:45:32 +02:00
' Accept ' : ' application/ {} ' . format ( output ) ,
2016-10-07 16:50:57 +02:00
' content-type ' : ' application/ {} ' . format ( output ) ,
2016-11-03 21:01:48 +01:00
' User-Agent ' : ' PyMISP {} - Python {} . {} . {} ' . format ( __version__ , * sys . version_info ) } )
2014-04-11 18:45:52 +02:00
return session
2015-12-19 17:57:29 +01:00
def flatten_error_messages ( self , response ) :
messages = [ ]
if response . get ( ' error ' ) :
if isinstance ( response [ ' error ' ] , list ) :
for e in response [ ' errors ' ] :
messages . append ( e [ ' error ' ] [ ' value ' ] [ 0 ] )
else :
messages . append ( [ ' error ' ] )
elif response . get ( ' errors ' ) :
if isinstance ( response [ ' errors ' ] , dict ) :
for where , errors in response [ ' errors ' ] . items ( ) :
2016-08-26 18:22:41 +02:00
if isinstance ( errors , dict ) :
for where , msg in errors . items ( ) :
2016-08-27 18:13:15 +02:00
if isinstance ( msg , list ) :
for m in msg :
messages . append ( ' Error in {} : {} ' . format ( where , m ) )
else :
messages . append ( ' Error in {} : {} ' . format ( where , msg ) )
2016-08-26 18:22:41 +02:00
else :
for e in errors :
2016-10-11 11:26:57 +02:00
if not e :
continue
2016-08-26 18:22:41 +02:00
if isinstance ( e , str ) :
messages . append ( e )
continue
for type_e , msgs in e . items ( ) :
for m in msgs :
messages . append ( ' Error in {} : {} ' . format ( where , m ) )
2015-12-19 17:57:29 +01:00
return messages
2015-09-23 18:47:47 +02:00
def _check_response ( self , response ) :
if response . status_code > = 500 :
response . raise_for_status ( )
2015-11-25 09:51:22 +01:00
try :
to_return = response . json ( )
except :
if self . debug :
print ( response . text )
raise PyMISPError ( ' Unknown error: {} ' . format ( response . text ) )
2015-12-19 17:57:29 +01:00
errors = [ ]
2016-04-04 18:34:08 +02:00
if isinstance ( to_return , list ) :
to_return = { ' response ' : to_return }
2015-12-19 17:57:29 +01:00
if to_return . get ( ' error ' ) :
if not isinstance ( to_return [ ' error ' ] , list ) :
errors . append ( to_return [ ' error ' ] )
else :
errors + = to_return [ ' error ' ]
2015-09-23 18:47:47 +02:00
if 400 < = response . status_code < 500 :
2015-12-19 17:57:29 +01:00
if to_return . get ( ' error ' ) is None and to_return . get ( ' message ' ) :
errors . append ( to_return [ ' message ' ] )
else :
errors . append ( basestring ( response . status_code ) )
errors + = self . flatten_error_messages ( to_return )
if errors :
to_return [ ' errors ' ] = errors
2015-11-25 09:51:22 +01:00
if self . debug :
print ( json . dumps ( to_return , indent = 4 ) )
2015-09-23 18:47:47 +02:00
return to_return
2015-09-01 10:31:22 +02:00
# ################################################
# ############### Simple REST API ################
# ################################################
2014-04-11 18:45:52 +02:00
2016-08-09 13:58:54 +02:00
def get_index ( self , filters = None ) :
2017-01-16 15:27:44 +01:00
""" Return the index.
2014-04-11 18:45:52 +02:00
2017-01-16 15:27:44 +01:00
Warning , there ' s a limit on the number of results
2014-04-11 18:45:52 +02:00
"""
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2016-03-01 16:20:10 +01:00
url = urljoin ( self . root_url , ' events/index ' )
2016-03-01 15:32:58 +01:00
if filters is not None :
filters = json . dumps ( filters )
2016-08-09 13:58:54 +02:00
response = session . post ( url , data = filters )
2016-03-01 15:32:58 +01:00
else :
2016-08-09 13:58:54 +02:00
response = session . get ( url )
return self . _check_response ( response )
2014-04-11 18:45:52 +02:00
2016-08-09 13:58:54 +02:00
def get_event ( self , event_id ) :
2017-01-16 15:27:44 +01:00
""" Get an event
2014-04-16 14:09:56 +02:00
2017-01-16 15:27:44 +01:00
: param event_id : Event id to get
2014-04-11 18:45:52 +02:00
"""
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2015-08-12 13:23:38 +02:00
url = urljoin ( self . root_url , ' events/ {} ' . format ( event_id ) )
2016-08-09 13:58:54 +02:00
response = session . get ( url )
return self . _check_response ( response )
2014-04-11 18:45:52 +02:00
2016-08-09 13:58:54 +02:00
def get_stix_event ( self , event_id = None , with_attachments = False , from_date = False , to_date = False , tags = False ) :
2017-01-16 15:27:44 +01:00
""" Get an event/events in STIX format """
2016-07-14 13:55:37 +02:00
if tags :
2016-07-28 09:50:46 +02:00
if isinstance ( tags , list ) :
tags = " && " . join ( tags )
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2016-07-28 09:50:46 +02:00
url = urljoin ( self . root_url , " /events/stix/download/ {} / {} / {} / {} / {} " . format (
event_id , with_attachments , tags , from_date , to_date ) )
2016-07-14 13:55:37 +02:00
if self . debug :
2016-07-28 09:50:46 +02:00
print ( " Getting STIX event from {} " . format ( url ) )
2016-08-09 13:58:54 +02:00
response = session . get ( url )
return self . _check_response ( response )
2016-07-28 09:50:46 +02:00
2016-08-09 13:58:54 +02:00
def add_event ( self , event ) :
2017-01-16 15:27:44 +01:00
""" Add a new event
2017-01-16 20:41:32 +01:00
2017-01-16 15:27:44 +01:00
: param event : Event as JSON object / string or XML to add
2014-04-11 18:45:52 +02:00
"""
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2015-08-10 11:58:20 +02:00
url = urljoin ( self . root_url , ' events ' )
2016-08-09 13:58:54 +02:00
if isinstance ( event , basestring ) :
response = session . post ( url , data = event )
2015-07-30 15:53:34 +02:00
else :
2016-08-09 13:58:54 +02:00
response = session . post ( url , data = json . dumps ( event ) )
return self . _check_response ( response )
2014-04-11 18:45:52 +02:00
2016-08-09 13:58:54 +02:00
def update_event ( self , event_id , event ) :
2017-01-16 15:27:44 +01:00
""" Update an event
2014-04-16 14:09:56 +02:00
2017-01-16 15:27:44 +01:00
: param event_id : Event id to update
: param event : Event as JSON object / string or XML to add
2014-04-11 18:45:52 +02:00
"""
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2015-08-12 13:23:38 +02:00
url = urljoin ( self . root_url , ' events/ {} ' . format ( event_id ) )
2016-08-09 13:58:54 +02:00
if isinstance ( event , basestring ) :
response = session . post ( url , data = event )
2015-07-30 15:53:34 +02:00
else :
2016-08-09 13:58:54 +02:00
response = session . post ( url , data = json . dumps ( event ) )
return self . _check_response ( response )
2014-04-11 18:45:52 +02:00
2016-08-09 13:58:54 +02:00
def delete_event ( self , event_id ) :
2017-01-16 15:27:44 +01:00
""" Delete an event
2014-04-16 14:09:56 +02:00
2017-01-16 15:27:44 +01:00
: param event_id : Event id to delete
2014-04-11 18:45:52 +02:00
"""
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2015-08-12 13:23:38 +02:00
url = urljoin ( self . root_url , ' events/ {} ' . format ( event_id ) )
2016-08-09 13:58:54 +02:00
response = session . delete ( url )
return self . _check_response ( response )
2014-04-11 18:45:52 +02:00
2016-08-09 13:58:54 +02:00
def delete_attribute ( self , attribute_id ) :
session = self . __prepare_session ( )
2015-08-28 17:03:35 +02:00
url = urljoin ( self . root_url , ' attributes/ {} ' . format ( attribute_id ) )
2016-08-09 13:58:54 +02:00
response = session . delete ( url )
return self . _check_response ( response )
2015-08-28 17:03:35 +02:00
2015-09-01 18:46:10 +02:00
# ##############################################
# ######### Event handling (Json only) #########
# ##############################################
2017-01-09 16:19:20 +01:00
def _prepare_full_event ( self , distribution , threat_level_id , analysis , info , date = None , published = False , orgc_id = None , org_id = None , sharing_group_id = None ) :
2016-10-10 12:24:17 +02:00
misp_event = MISPEvent ( self . describe_types )
2016-09-27 19:47:22 +02:00
misp_event . set_all_values ( info = info , distribution = distribution , threat_level_id = threat_level_id ,
2017-01-09 16:19:20 +01:00
analysis = analysis , date = date , orgc_id = orgc_id , org_id = org_id , sharing_group_id = sharing_group_id )
2016-09-26 00:26:09 +02:00
if published :
misp_event . publish ( )
2016-10-05 11:43:33 +02:00
return misp_event
2015-09-01 18:46:10 +02:00
2017-01-13 14:15:53 +01:00
def _prepare_full_attribute ( self , category , type_value , value , to_ids , comment = None , distribution = 5 , * * kwargs ) :
2016-10-10 12:24:17 +02:00
misp_attribute = MISPAttribute ( self . describe_types )
2016-09-27 19:47:22 +02:00
misp_attribute . set_all_values ( type = type_value , value = value , category = category ,
2017-01-13 14:15:53 +01:00
to_ids = to_ids , comment = comment , distribution = distribution , * * kwargs )
2016-09-28 18:20:37 +02:00
return misp_attribute
2015-09-01 18:46:10 +02:00
2016-08-16 11:44:08 +02:00
def _one_or_more ( self , value ) :
""" Returns a list/tuple of one or more items, regardless of input. """
return value if isinstance ( value , ( tuple , list ) ) else ( value , )
2015-09-01 18:46:10 +02:00
# ########## Helpers ##########
2017-01-16 20:47:43 +01:00
def _make_mispevent ( self , event ) :
if not isinstance ( event , MISPEvent ) :
e = MISPEvent ( self . describe_types )
e . load ( event )
else :
e = event
return e
2015-09-23 18:47:47 +02:00
def get ( self , eid ) :
2016-09-26 00:26:09 +02:00
return self . get_event ( eid )
2016-07-14 13:55:37 +02:00
def get_stix ( self , * * kwargs ) :
2016-09-26 00:26:09 +02:00
return self . get_stix_event ( * * kwargs )
2015-09-23 18:47:47 +02:00
def update ( self , event ) :
2017-01-16 20:47:43 +01:00
e = self . _make_mispevent ( event )
if e . uuid :
eid = e . uuid
2017-01-16 20:41:32 +01:00
else :
2017-01-16 20:47:43 +01:00
eid = e . id
return self . update_event ( eid , json . dumps ( e , cls = EncodeUpdate ) )
2015-09-01 18:46:10 +02:00
2015-09-17 00:51:45 +02:00
def publish ( self , event ) :
2017-01-16 20:47:43 +01:00
e = self . _make_mispevent ( event )
if e . published :
2015-09-23 18:47:47 +02:00
return { ' error ' : ' Already published ' }
2016-09-27 19:47:22 +02:00
e . publish ( )
2017-01-16 20:47:43 +01:00
return self . update ( event )
2016-09-26 00:26:09 +02:00
def change_threat_level ( self , event , threat_level_id ) :
2017-01-16 20:47:43 +01:00
e = self . _make_mispevent ( event )
2016-09-27 19:47:22 +02:00
e . threat_level_id = threat_level_id
2017-01-16 20:47:43 +01:00
return self . update ( event )
2016-09-26 00:26:09 +02:00
2017-01-09 16:19:20 +01:00
def change_sharing_group ( self , event , sharing_group_id ) :
2017-01-16 20:47:43 +01:00
e = self . _make_mispevent ( event )
2017-01-09 16:19:20 +01:00
e . distribution = 4 # Needs to be 'Sharing group'
e . sharing_group_id = sharing_group_id
2017-01-16 20:47:43 +01:00
return self . update ( event )
2017-01-09 16:19:20 +01:00
def new_event ( self , distribution = None , threat_level_id = None , analysis = None , info = None , date = None , published = False , orgc_id = None , org_id = None , sharing_group_id = None ) :
misp_event = self . _prepare_full_event ( distribution , threat_level_id , analysis , info , date , published , orgc_id , org_id , sharing_group_id )
2016-10-05 11:43:33 +02:00
return self . add_event ( json . dumps ( misp_event , cls = EncodeUpdate ) )
2015-09-17 00:51:45 +02:00
2017-01-18 00:20:24 +01:00
def add_tag ( self , event , tag , attribute = False ) :
# FIXME: this is dirty, this function needs to be deprecated with something tagging a UUID
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2017-01-18 00:20:24 +01:00
if attribute :
to_post = { ' request ' : { ' Attribute ' : { ' id ' : event [ ' id ' ] , ' tag ' : tag } } }
2017-01-18 01:03:38 +01:00
path = ' attributes/addTag '
2017-01-18 00:20:24 +01:00
else :
to_post = { ' request ' : { ' Event ' : { ' id ' : event [ ' id ' ] , ' tag ' : tag } } }
2017-01-18 01:03:38 +01:00
path = ' events/addTag '
response = session . post ( urljoin ( self . root_url , path ) , data = json . dumps ( to_post ) )
2016-03-11 16:53:31 +01:00
return self . _check_response ( response )
2017-01-18 00:20:24 +01:00
def remove_tag ( self , event , tag , attribute = False ) :
# FIXME: this is dirty, this function needs to be deprecated with something removing the tag to a UUID
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2017-01-18 00:20:24 +01:00
if attribute :
to_post = { ' request ' : { ' Attribute ' : { ' id ' : event [ ' id ' ] , ' tag ' : tag } } }
2017-01-18 01:03:38 +01:00
path = ' attributes/addTag '
2017-01-18 00:20:24 +01:00
else :
to_post = { ' request ' : { ' Event ' : { ' id ' : event [ ' Event ' ] [ ' id ' ] , ' tag ' : tag } } }
2017-01-18 01:03:38 +01:00
path = ' events/addTag '
response = session . post ( urljoin ( self . root_url , path ) , data = json . dumps ( to_post ) )
2016-07-11 17:57:16 +02:00
return self . _check_response ( response )
2017-01-16 20:41:32 +01:00
def _valid_uuid ( self , uuid ) :
2017-01-16 15:27:44 +01:00
""" Test if uuid is valid
Will test against CakeText ' s RFC 4122, i.e
" the third group must start with a 4,
and the fourth group must start with 8 , 9 , a or b . "
2017-01-04 11:23:18 +01:00
2017-01-16 15:27:44 +01:00
: param uuid : an uuid
2017-01-04 11:23:18 +01:00
"""
regex = re . compile ( ' ^[a-f0-9] {8} -?[a-f0-9] {4} -?4[a-f0-9] {3} -?[89ab][a-f0-9] {3} -?[a-f0-9] {12} \ Z ' , re . I )
match = regex . match ( uuid )
return bool ( match )
2015-09-02 11:50:15 +02:00
# ##### File attributes #####
2015-10-30 17:23:25 +01:00
def _send_attributes ( self , event , attributes , proposal = False ) :
if proposal :
response = self . proposal_add ( event [ ' Event ' ] [ ' id ' ] , attributes )
else :
2016-10-10 12:24:17 +02:00
e = MISPEvent ( self . describe_types )
2016-09-27 19:47:22 +02:00
e . load ( event )
2016-09-28 18:20:37 +02:00
e . attributes + = attributes
2017-01-16 20:47:43 +01:00
response = self . update ( event )
2016-08-11 19:30:31 +02:00
return response
2015-09-02 11:50:15 +02:00
2017-01-13 14:15:53 +01:00
def add_named_attribute ( self , event , type_value , value , category = None , to_ids = False , comment = None , distribution = None , proposal = False , * * kwargs ) :
2016-05-05 11:05:59 +02:00
attributes = [ ]
2016-09-28 18:20:37 +02:00
for value in self . _one_or_more ( value ) :
2017-01-13 14:15:53 +01:00
attributes . append ( self . _prepare_full_attribute ( category , type_value , value , to_ids , comment , distribution , * * kwargs ) )
2016-05-05 11:05:59 +02:00
return self . _send_attributes ( event , attributes , proposal )
2016-04-12 19:42:01 +02:00
def add_hashes ( self , event , category = ' Artifacts dropped ' , filename = None , md5 = None , sha1 = None , sha256 = None , ssdeep = None , comment = None , to_ids = True , distribution = None , proposal = False ) :
2015-09-01 18:46:10 +02:00
attributes = [ ]
type_value = ' {} '
value = ' {} '
if filename :
type_value = ' filename| {} '
value = filename + ' | {} '
if md5 :
attributes . append ( self . _prepare_full_attribute ( category , type_value . format ( ' md5 ' ) , value . format ( md5 ) ,
to_ids , comment , distribution ) )
if sha1 :
attributes . append ( self . _prepare_full_attribute ( category , type_value . format ( ' sha1 ' ) , value . format ( sha1 ) ,
to_ids , comment , distribution ) )
if sha256 :
attributes . append ( self . _prepare_full_attribute ( category , type_value . format ( ' sha256 ' ) , value . format ( sha256 ) ,
to_ids , comment , distribution ) )
2016-04-12 19:42:01 +02:00
if ssdeep :
attributes . append ( self . _prepare_full_attribute ( category , type_value . format ( ' ssdeep ' ) , value . format ( ssdeep ) ,
to_ids , comment , distribution ) )
2015-10-30 17:23:25 +01:00
return self . _send_attributes ( event , attributes , proposal )
2015-09-01 18:46:10 +02:00
2016-06-28 13:12:37 +02:00
def av_detection_link ( self , event , link , category = ' Antivirus detection ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' link ' , link , category , to_ids , comment , distribution , proposal )
2016-06-28 13:12:37 +02:00
2016-07-26 19:13:29 +02:00
def add_detection_name ( self , event , name , category = ' Antivirus detection ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' text ' , name , category , to_ids , comment , distribution , proposal )
2016-07-26 19:13:29 +02:00
2016-04-15 13:47:13 +02:00
def add_filename ( self , event , filename , category = ' Artifacts dropped ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' filename ' , filename , category , to_ids , comment , distribution , proposal )
2016-04-15 13:47:13 +02:00
2017-01-13 14:15:53 +01:00
def add_attachment ( self , event , filename , attachment = None , category = ' Artifacts dropped ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2017-01-16 20:41:32 +01:00
""" Add an attachment to the MISP event
2017-01-13 14:15:53 +01:00
: param event : The event to add an attachment to
: param filename : The name you want to store the file under
: param attachment : Either a file handle or a path to a file - will be uploaded
"""
2017-01-16 20:41:32 +01:00
2017-01-13 14:15:53 +01:00
if hasattr ( attachment , " read " ) :
# It's a file handle - we can read it
fileData = attachment . read ( )
elif isinstance ( attachment , str ) :
# It can either be the b64 encoded data or a file path
if os . path . exists ( attachment ) :
# It's a path!
with open ( attachment , " r " ) as f :
fileData = f . read ( )
else :
# We have to assume it's the actual data
fileData = attachment
# by now we have a string for the file
# we just need to b64 encode it and send it on its way
# also, just decode it to utf-8 to avoid the b'string' format
encodedData = base64 . b64encode ( fileData . encode ( " utf-8 " ) ) . decode ( " utf-8 " )
2017-01-16 20:41:32 +01:00
2017-01-13 14:15:53 +01:00
# Send it on its way
return self . add_named_attribute ( event , ' attachment ' , filename , category , to_ids , comment , distribution , proposal , data = encodedData )
2017-01-16 20:41:32 +01:00
2015-10-30 17:23:25 +01:00
def add_regkey ( self , event , regkey , rvalue = None , category = ' Artifacts dropped ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2015-09-01 18:46:10 +02:00
if rvalue :
type_value = ' regkey|value '
value = ' {} | {} ' . format ( regkey , rvalue )
else :
type_value = ' regkey '
value = regkey
attributes = [ ]
attributes . append ( self . _prepare_full_attribute ( category , type_value , value , to_ids , comment , distribution ) )
2015-10-30 17:23:25 +01:00
return self . _send_attributes ( event , attributes , proposal )
2015-09-01 18:46:10 +02:00
2016-08-16 11:44:08 +02:00
def add_regkeys ( self , event , regkeys_values , category = ' Artifacts dropped ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
attributes = [ ]
for regkey , rvalue in regkeys_values . items ( ) :
2016-12-01 10:49:12 +01:00
if rvalue is not None :
2016-08-16 11:44:08 +02:00
type_value = ' regkey|value '
value = ' {} | {} ' . format ( regkey , rvalue )
else :
type_value = ' regkey '
value = regkey
attributes . append ( self . _prepare_full_attribute ( category , type_value , value , to_ids , comment , distribution ) )
return self . _send_attributes ( event , attributes , proposal )
2015-10-30 17:23:25 +01:00
def add_pattern ( self , event , pattern , in_file = True , in_memory = False , category = ' Artifacts dropped ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-11-29 09:14:18 +01:00
if not ( in_file or in_memory ) :
raise PyMISPError ( ' Invalid pattern type: please use in_memory=True or in_file=True ' )
itemtype = ' pattern-in-file ' if in_file else ' pattern-in-memory '
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , itemtype , pattern , category , to_ids , comment , distribution , proposal )
2015-09-01 18:46:10 +02:00
2015-10-30 17:23:25 +01:00
def add_pipe ( self , event , named_pipe , category = ' Artifacts dropped ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-11-29 09:14:18 +01:00
def scrub ( s ) :
if not s . startswith ( ' \\ . \\ pipe \\ ' ) :
s = ' \\ . \\ pipe \\ {} ' . format ( s )
return s
2016-12-01 14:26:59 +01:00
attributes = list ( map ( scrub , self . _one_or_more ( named_pipe ) ) )
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' named pipe ' , attributes , category , to_ids , comment , distribution , proposal )
2015-09-01 18:46:10 +02:00
2015-10-30 17:23:25 +01:00
def add_mutex ( self , event , mutex , category = ' Artifacts dropped ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-11-29 09:14:18 +01:00
def scrub ( s ) :
if not s . startswith ( ' \\ BaseNamedObjects \\ ' ) :
s = ' \\ BaseNamedObjects \\ {} ' . format ( s )
2016-12-07 10:54:22 +01:00
return s
2016-12-01 14:26:59 +01:00
attributes = list ( map ( scrub , self . _one_or_more ( mutex ) ) )
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' mutex ' , attributes , category , to_ids , comment , distribution , proposal )
2015-10-06 16:57:28 +02:00
2016-04-20 10:16:44 +02:00
def add_yara ( self , event , yara , category = ' Payload delivery ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' yara ' , yara , category , to_ids , comment , distribution , proposal )
2016-04-20 10:16:44 +02:00
2015-09-02 11:50:15 +02:00
# ##### Network attributes #####
2015-10-30 17:23:25 +01:00
def add_ipdst ( self , event , ipdst , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' ip-dst ' , ipdst , category , to_ids , comment , distribution , proposal )
2015-09-02 11:50:15 +02:00
2015-11-05 09:35:43 +01:00
def add_ipsrc ( self , event , ipsrc , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' ip-src ' , ipsrc , category , to_ids , comment , distribution , proposal )
2015-11-05 09:35:43 +01:00
2015-10-30 17:23:25 +01:00
def add_hostname ( self , event , hostname , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' hostname ' , hostname , category , to_ids , comment , distribution , proposal )
2015-09-02 11:50:15 +02:00
2015-10-30 17:23:25 +01:00
def add_domain ( self , event , domain , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' domain ' , domain , category , to_ids , comment , distribution , proposal )
2015-09-02 11:50:15 +02:00
2016-06-27 16:53:13 +02:00
def add_domain_ip ( self , event , domain , ip , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 14:26:59 +01:00
composed = list ( map ( lambda x : ' %s | %s ' % ( domain , x ) , ip ) )
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' domain|ip ' , composed , category , to_ids , comment , distribution , proposal )
2016-06-27 16:53:13 +02:00
2016-08-16 11:44:08 +02:00
def add_domains_ips ( self , event , domain_ips , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 14:26:59 +01:00
composed = list ( map ( lambda x : ' %s | %s ' % ( x [ 0 ] , x [ 1 ] ) , domain_ips . items ( ) ) )
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' domain|ip ' , composed , category , to_ids , comment , distribution , proposal )
2016-08-16 11:44:08 +02:00
2015-10-30 17:23:25 +01:00
def add_url ( self , event , url , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' url ' , url , category , to_ids , comment , distribution , proposal )
2015-09-02 11:50:15 +02:00
2015-10-30 17:23:25 +01:00
def add_useragent ( self , event , useragent , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' user-agent ' , useragent , category , to_ids , comment , distribution , proposal )
2015-09-02 11:50:15 +02:00
2015-10-30 17:23:25 +01:00
def add_traffic_pattern ( self , event , pattern , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' pattern-in-traffic ' , pattern , category , to_ids , comment , distribution , proposal )
2015-09-02 11:50:15 +02:00
2015-10-30 17:23:25 +01:00
def add_snort ( self , event , snort , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' snort ' , snort , category , to_ids , comment , distribution , proposal )
2015-09-01 18:46:10 +02:00
2016-10-20 10:49:06 +02:00
def add_net_other ( self , event , netother , category = ' Network activity ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' other ' , netother , category , to_ids , comment , distribution , proposal )
2016-10-20 10:49:06 +02:00
2015-10-06 16:52:58 +02:00
# ##### Email attributes #####
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_email_src ( self , event , email , category = ' Payload delivery ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' email-src ' , email , category , to_ids , comment , distribution , proposal )
2015-10-06 16:52:58 +02:00
2015-10-30 17:23:25 +01:00
def add_email_dst ( self , event , email , category = ' Payload delivery ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' email-dst ' , email , category , to_ids , comment , distribution , proposal )
2015-10-06 16:52:58 +02:00
2016-11-29 09:14:18 +01:00
def add_email_subject ( self , event , email , category = ' Payload delivery ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' email-subject ' , email , category , to_ids , comment , distribution , proposal )
2015-10-06 16:52:58 +02:00
2016-11-29 09:14:18 +01:00
def add_email_attachment ( self , event , email , category = ' Payload delivery ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' email-attachment ' , email , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2015-10-06 16:52:58 +02:00
# ##### Target attributes #####
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_target_email ( self , event , target , category = ' Targeting data ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' target-email ' , target , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_target_user ( self , event , target , category = ' Targeting data ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' target-user ' , target , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_target_machine ( self , event , target , category = ' Targeting data ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' target-machine ' , target , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_target_org ( self , event , target , category = ' Targeting data ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' target-org ' , target , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_target_location ( self , event , target , category = ' Targeting data ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' target-location ' , target , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2016-11-29 09:14:18 +01:00
def add_target_external ( self , event , target , category = ' Targeting data ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' target-external ' , target , category , to_ids , comment , distribution , proposal )
2015-10-30 17:23:25 +01:00
2016-03-14 12:17:53 +01:00
# ##### Attribution attributes #####
2016-11-29 09:14:18 +01:00
def add_threat_actor ( self , event , target , category = ' Attribution ' , to_ids = True , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' threat-actor ' , target , category , to_ids , comment , distribution , proposal )
2016-04-14 10:29:36 +02:00
2016-04-13 21:40:31 +02:00
# ##### Internal reference attributes #####
2016-04-14 10:29:36 +02:00
2016-11-29 09:14:18 +01:00
def add_internal_link ( self , event , reference , category = ' Internal reference ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' link ' , reference , category , to_ids , comment , distribution , proposal )
2016-04-14 10:29:36 +02:00
2016-11-29 09:14:18 +01:00
def add_internal_comment ( self , event , reference , category = ' Internal reference ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' comment ' , reference , category , to_ids , comment , distribution , proposal )
2016-04-14 10:29:36 +02:00
2016-11-29 09:14:18 +01:00
def add_internal_text ( self , event , reference , category = ' Internal reference ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' text ' , reference , category , to_ids , comment , distribution , proposal )
2016-04-14 10:29:36 +02:00
2016-11-29 09:14:18 +01:00
def add_internal_other ( self , event , reference , category = ' Internal reference ' , to_ids = False , comment = None , distribution = None , proposal = False ) :
2016-12-01 10:49:12 +01:00
return self . add_named_attribute ( event , ' other ' , reference , category , to_ids , comment , distribution , proposal )
2016-03-14 12:17:53 +01:00
2015-09-01 10:31:22 +02:00
# ##################################################
# ######### Upload samples through the API #########
# ##################################################
2015-08-04 16:24:55 +02:00
2016-09-28 18:20:37 +02:00
def _prepare_upload ( self , event_id , distribution , to_ids , category , comment , info ,
analysis , threat_level_id ) :
2015-08-06 09:49:44 +02:00
to_post = { ' request ' : { } }
2015-09-01 18:46:10 +02:00
2015-09-13 00:31:27 +02:00
if event_id is not None :
try :
event_id = int ( event_id )
except :
pass
2015-08-04 16:24:55 +02:00
if not isinstance ( event_id , int ) :
# New event
2016-10-05 11:43:33 +02:00
misp_event = self . _prepare_full_event ( distribution , threat_level_id , analysis , info )
to_post [ ' request ' ] [ ' distribution ' ] = misp_event . distribution
to_post [ ' request ' ] [ ' info ' ] = misp_event . info
to_post [ ' request ' ] [ ' analysis ' ] = misp_event . analysis
to_post [ ' request ' ] [ ' threat_level_id ' ] = misp_event . threat_level_id
2015-08-04 16:24:55 +02:00
else :
2015-09-01 18:46:10 +02:00
to_post [ ' request ' ] [ ' event_id ' ] = int ( event_id )
2015-08-04 16:24:55 +02:00
2016-09-28 18:20:37 +02:00
default_values = self . sane_default [ ' malware-sample ' ]
if to_ids is None or not isinstance ( to_ids , bool ) :
to_ids = bool ( int ( default_values [ ' to_ids ' ] ) )
2015-09-01 18:46:10 +02:00
to_post [ ' request ' ] [ ' to_ids ' ] = to_ids
2015-08-04 16:24:55 +02:00
2016-09-28 18:20:37 +02:00
if category is None or category not in self . categories :
category = default_values [ ' default_category ' ]
2015-09-01 18:46:10 +02:00
to_post [ ' request ' ] [ ' category ' ] = category
2015-08-04 16:24:55 +02:00
2016-04-15 15:52:50 +02:00
to_post [ ' request ' ] [ ' comment ' ] = comment
2015-08-06 01:57:59 +02:00
return to_post
2015-08-28 17:03:35 +02:00
def _encode_file_to_upload ( self , path ) :
with open ( path , ' rb ' ) as f :
2016-07-27 13:30:46 +02:00
return str ( base64 . b64encode ( f . read ( ) ) )
2015-08-06 01:57:59 +02:00
2016-08-16 18:35:34 +02:00
def upload_sample ( self , filename , filepath , event_id , distribution = None ,
to_ids = True , category = None , comment = None , info = None ,
analysis = None , threat_level_id = None ) :
2016-09-28 18:20:37 +02:00
to_post = self . _prepare_upload ( event_id , distribution , to_ids , category ,
comment , info , analysis , threat_level_id )
2015-08-28 17:03:35 +02:00
to_post [ ' request ' ] [ ' files ' ] = [ { ' filename ' : filename , ' data ' : self . _encode_file_to_upload ( filepath ) } ]
2015-08-06 01:57:59 +02:00
return self . _upload_sample ( to_post )
2016-08-16 18:35:34 +02:00
def upload_samplelist ( self , filepaths , event_id , distribution = None ,
2016-10-05 11:07:40 +02:00
to_ids = True , category = None , comment = None , info = None ,
2016-08-16 18:35:34 +02:00
analysis = None , threat_level_id = None ) :
2016-09-28 18:20:37 +02:00
to_post = self . _prepare_upload ( event_id , distribution , to_ids , category ,
2016-10-05 11:07:40 +02:00
comment , info , analysis , threat_level_id )
2015-08-28 17:03:35 +02:00
files = [ ]
for path in filepaths :
if not os . path . isfile ( path ) :
continue
files . append ( { ' filename ' : os . path . basename ( path ) , ' data ' : self . _encode_file_to_upload ( path ) } )
to_post [ ' request ' ] [ ' files ' ] = files
2015-08-06 01:57:59 +02:00
return self . _upload_sample ( to_post )
2015-08-04 16:24:55 +02:00
2015-08-06 01:57:59 +02:00
def _upload_sample ( self , to_post ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-08-10 11:58:20 +02:00
url = urljoin ( self . root_url , ' events/upload_sample ' )
2015-09-23 18:47:47 +02:00
response = session . post ( url , data = json . dumps ( to_post ) )
return self . _check_response ( response )
2015-08-04 16:24:55 +02:00
2015-10-30 17:23:25 +01:00
# ############################
# ######## Proposals #########
# ############################
def __query_proposal ( self , session , path , id , attribute = None ) :
url = urljoin ( self . root_url , ' shadow_attributes/ {} / {} ' . format ( path , id ) )
if path in [ ' add ' , ' edit ' ] :
query = { ' request ' : { ' ShadowAttribute ' : attribute } }
2016-09-28 18:20:37 +02:00
response = session . post ( url , data = json . dumps ( query ) )
elif path == ' view ' :
2015-10-30 17:23:25 +01:00
response = session . get ( url )
2016-09-28 18:20:37 +02:00
else : # accept or discard
response = session . post ( url )
2015-10-30 17:23:25 +01:00
return self . _check_response ( response )
def proposal_view ( self , event_id = None , proposal_id = None ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-10-30 17:23:25 +01:00
if proposal_id is not None and event_id is not None :
return { ' error ' : ' You can only view an event ID or a proposal ID ' }
if event_id is not None :
id = event_id
else :
id = proposal_id
return self . __query_proposal ( session , ' view ' , id )
def proposal_add ( self , event_id , attribute ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-10-30 17:23:25 +01:00
return self . __query_proposal ( session , ' add ' , event_id , attribute )
def proposal_edit ( self , attribute_id , attribute ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-10-30 17:23:25 +01:00
return self . __query_proposal ( session , ' edit ' , attribute_id , attribute )
def proposal_accept ( self , proposal_id ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-10-30 17:23:25 +01:00
return self . __query_proposal ( session , ' accept ' , proposal_id )
def proposal_discard ( self , proposal_id ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-10-30 17:23:25 +01:00
return self . __query_proposal ( session , ' discard ' , proposal_id )
2016-12-09 11:42:07 +01:00
# ##############################
# ###### Attribute update ######
# ##############################
def change_toids ( self , attribute_uuid , to_ids ) :
if to_ids not in [ 0 , 1 ] :
raise Exception ( ' to_ids can only be 0 or 1 ' )
query = { " to_ids " : to_ids }
session = self . __prepare_session ( )
return self . __query ( session , ' edit/ {} ' . format ( attribute_uuid ) , query , controller = ' attributes ' )
2015-09-01 10:31:22 +02:00
# ##############################
2014-04-14 10:55:20 +02:00
# ######## REST Search #########
2015-09-01 10:31:22 +02:00
# ##############################
2014-04-11 18:45:52 +02:00
2016-08-04 13:21:28 +02:00
def __query ( self , session , path , query , controller = ' events ' ) :
2015-09-21 11:52:26 +02:00
if query . get ( ' error ' ) is not None :
return query
2016-08-04 13:21:28 +02:00
if controller not in [ ' events ' , ' attributes ' ] :
raise Exception ( ' Invalid controller. Can only be {} ' . format ( ' , ' . join ( [ ' events ' , ' attributes ' ] ) ) )
url = urljoin ( self . root_url , ' {} / {} ' . format ( controller , path . lstrip ( ' / ' ) ) )
2016-11-24 10:41:47 +01:00
if self . debug :
print ( ' URL: ' , url )
print ( ' Query: ' , query )
2015-09-23 18:47:47 +02:00
response = session . post ( url , data = json . dumps ( query ) )
return self . _check_response ( response )
2015-09-21 11:52:26 +02:00
2016-04-04 18:34:08 +02:00
def search_index ( self , published = None , eventid = None , tag = None , datefrom = None ,
dateto = None , eventinfo = None , threatlevel = None , distribution = None ,
2017-01-24 07:15:38 +01:00
analysis = None , attribute = None , org = None , to_ids = False , deleted = False ) :
2017-01-16 15:27:44 +01:00
""" Search only at the index level. Use ! infront of value as NOT, default OR
: param published : Published ( 0 , 1 )
: param eventid : Evend ID ( s ) | str or list
: param tag : Tag ( s ) | str or list
: param datefrom : First date , in format YYYY - MM - DD
: param dateto : Last date , in format YYYY - MM - DD
: param eventinfo : Event info ( s ) to match | str or list
: param threatlevel : Threat level ( s ) ( 1 , 2 , 3 , 4 ) | str or list
: param distribution : Distribution level ( s ) ( 0 , 1 , 2 , 3 ) | str or list
: param analysis : Analysis level ( s ) ( 0 , 1 , 2 ) | str or list
: param org : Organisation ( s ) | str or list
2017-01-24 07:15:38 +01:00
: param to_ids :
- false ( default ) : include all attributes , no matter the to_ids flag
- true : include only to_ids attributes
- " exclude " : exclude attributes marked to_ids
: param deleted :
- false ( default ) : only include non deleted attributes
- true : include deleted attributes
- " only " : ONLY include deleted attributes
2016-03-31 13:33:04 +02:00
"""
2016-04-04 18:34:08 +02:00
allowed = { ' published ' : published , ' eventid ' : eventid , ' tag ' : tag , ' Dateto ' : dateto ,
' Datefrom ' : datefrom , ' eventinfo ' : eventinfo , ' threatlevel ' : threatlevel ,
' distribution ' : distribution , ' analysis ' : analysis , ' attribute ' : attribute ,
2017-01-24 07:15:38 +01:00
' org ' : org , ' to_ids ' : to_ids , ' deleted ' : deleted }
2016-04-04 18:34:08 +02:00
rule_levels = { ' distribution ' : [ " 0 " , " 1 " , " 2 " , " 3 " , " !0 " , " !1 " , " !2 " , " !3 " ] ,
' threatlevel ' : [ " 1 " , " 2 " , " 3 " , " 4 " , " !1 " , " !2 " , " !3 " , " !4 " ] ,
2017-01-24 07:15:38 +01:00
' analysis ' : [ " 0 " , " 1 " , " 2 " , " !0 " , " !1 " , " !2 " ] ,
' to_ids ' : [ ' True ' , ' False ' , ' exclude ' ] ,
' deleted ' : [ ' True ' , ' False ' , ' only ' ] ,
}
2016-03-31 13:33:04 +02:00
buildup_url = " events/index "
for rule in allowed . keys ( ) :
2016-04-04 18:34:08 +02:00
if allowed [ rule ] is not None :
if not isinstance ( allowed [ rule ] , list ) :
allowed [ rule ] = [ allowed [ rule ] ]
2016-09-13 14:03:22 +02:00
allowed [ rule ] = [ x for x in map ( str , allowed [ rule ] ) ]
2016-03-31 13:33:04 +02:00
if rule in rule_levels :
if not set ( allowed [ rule ] ) . issubset ( rule_levels [ rule ] ) :
raise SearchError ( ' Values in your {} are invalid, has to be in {} ' . format ( rule , ' , ' . join ( str ( x ) for x in rule_levels [ rule ] ) ) )
if type ( allowed [ rule ] ) == list :
joined = ' | ' . join ( str ( x ) for x in allowed [ rule ] )
buildup_url + = ' /search {} : {} ' . format ( rule , joined )
else :
buildup_url + = ' /search {} : {} ' . format ( rule , allowed [ rule ] )
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2016-03-31 13:33:04 +02:00
url = urljoin ( self . root_url , buildup_url )
2016-03-18 09:38:04 +01:00
response = session . get ( url )
return self . _check_response ( response )
2015-08-06 17:42:41 +02:00
def search_all ( self , value ) :
query = { ' value ' : value , ' searchall ' : 1 }
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-08-06 17:42:41 +02:00
return self . __query ( session , ' restSearch/download ' , query )
2014-04-11 18:45:52 +02:00
def __prepare_rest_search ( self , values , not_values ) :
2017-01-16 15:27:44 +01:00
""" Prepare a search, generate the chain processed by the server
2014-04-16 14:09:56 +02:00
2017-01-16 15:27:44 +01:00
: param values : Values to search
: param not_values : Values that should not be in the response
2014-04-11 18:45:52 +02:00
"""
to_return = ' '
if values is not None :
2014-04-14 10:55:20 +02:00
if not isinstance ( values , list ) :
2014-04-11 18:45:52 +02:00
to_return + = values
else :
to_return + = ' && ' . join ( values )
if not_values is not None :
2014-04-14 10:55:20 +02:00
if len ( to_return ) > 0 :
2014-04-11 18:45:52 +02:00
to_return + = ' &&! '
else :
to_return + = ' ! '
2014-04-14 10:55:20 +02:00
if not isinstance ( values , list ) :
2014-04-11 18:45:52 +02:00
to_return + = not_values
else :
to_return + = ' &&! ' . join ( not_values )
return to_return
def search ( self , values = None , not_values = None , type_attribute = None ,
2015-02-16 14:31:29 +01:00
category = None , org = None , tags = None , not_tags = None , date_from = None ,
2017-01-04 17:21:51 +01:00
date_to = None , last = None , metadata = None , uuid = None , controller = ' events ' ) :
2017-01-16 15:27:44 +01:00
""" Search via the Rest API
: param values : values to search for
: param not_values : values * not * to search for
: param type_attribute : Type of attribute
: param category : Category to search
: param org : Org reporting the event
: param tags : Tags to search for
: param not_tags : Tags * not * to search for
: param date_from : First date
: param date_to : Last date
: param last : Last updated events ( for example 5 d or 12 h or 30 m )
: param metadata : return onlymetadata if True
: param uuid : a valid uuid
2014-04-11 18:45:52 +02:00
"""
2016-11-24 10:50:46 +01:00
val = self . __prepare_rest_search ( values , not_values )
tag = self . __prepare_rest_search ( tags , not_tags )
2015-02-16 14:31:29 +01:00
query = { }
if len ( val ) != 0 :
query [ ' value ' ] = val
if len ( tag ) != 0 :
query [ ' tags ' ] = tag
if type_attribute is not None :
query [ ' type ' ] = type_attribute
if category is not None :
query [ ' category ' ] = category
if org is not None :
query [ ' org ' ] = org
if date_from is not None :
if isinstance ( date_from , datetime . date ) or isinstance ( date_to , datetime . datetime ) :
query [ ' from ' ] = date_from . strftime ( ' % Y- % m- %d ' )
else :
query [ ' from ' ] = date_from
if date_to is not None :
if isinstance ( date_to , datetime . date ) or isinstance ( date_to , datetime . datetime ) :
query [ ' to ' ] = date_to . strftime ( ' % Y- % m- %d ' )
else :
query [ ' to ' ] = date_to
2015-08-05 17:20:59 +02:00
if last is not None :
query [ ' last ' ] = last
2016-10-13 11:48:17 +02:00
if metadata is not None :
query [ ' metadata ' ] = metadata
2017-01-04 11:23:18 +01:00
if uuid is not None :
if self . _valid_uuid ( uuid ) :
query [ ' uuid ' ] = uuid
else :
return { ' error ' : ' You must enter a valid uuid. ' }
2014-04-11 18:45:52 +02:00
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2016-08-04 13:21:28 +02:00
return self . __query ( session , ' restSearch/download ' , query , controller )
2014-04-11 18:45:52 +02:00
2017-01-16 15:27:44 +01:00
def get_attachment ( self , event_id ) :
""" Get attachement of an event (not sample)
2014-04-16 14:09:56 +02:00
2017-01-16 15:27:44 +01:00
: param event_id : Event id from where the attachements will be fetched
2014-04-11 18:45:52 +02:00
"""
2015-08-12 13:23:38 +02:00
attach = urljoin ( self . root_url , ' attributes/downloadAttachment/download/ {} ' . format ( event_id ) )
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2016-08-09 13:58:54 +02:00
response = session . get ( attach )
return self . _check_response ( response )
2014-04-11 18:45:52 +02:00
2015-08-19 10:42:24 +02:00
def get_yara ( self , event_id ) :
to_post = { ' request ' : { ' eventid ' : event_id , ' type ' : ' yara ' } }
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-08-19 10:42:24 +02:00
response = session . post ( urljoin ( self . root_url , ' attributes/restSearch ' ) , data = json . dumps ( to_post ) )
2015-09-23 18:47:47 +02:00
result = self . _check_response ( response )
if result . get ( ' error ' ) is not None :
return False , result . get ( ' error ' )
if not result . get ( ' response ' ) :
2015-08-19 10:42:24 +02:00
return False , result . get ( ' message ' )
rules = ' \n \n ' . join ( [ a [ ' value ' ] for a in result [ ' response ' ] [ ' Attribute ' ] ] )
return True , rules
2015-08-07 17:24:03 +02:00
def download_samples ( self , sample_hash = None , event_id = None , all_samples = False ) :
to_post = { ' request ' : { ' hash ' : sample_hash , ' eventID ' : event_id , ' allSamples ' : all_samples } }
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-08-07 17:24:03 +02:00
response = session . post ( urljoin ( self . root_url , ' attributes/downloadSample ' ) , data = json . dumps ( to_post ) )
2015-09-23 18:47:47 +02:00
result = self . _check_response ( response )
if result . get ( ' error ' ) is not None :
return False , result . get ( ' error ' )
if not result . get ( ' result ' ) :
2015-08-07 17:24:03 +02:00
return False , result . get ( ' message ' )
details = [ ]
for f in result [ ' result ' ] :
2015-09-12 23:08:06 +02:00
decoded = base64 . b64decode ( f [ ' base64 ' ] )
zipped = BytesIO ( decoded )
2015-08-24 12:05:49 +02:00
try :
2015-09-18 14:38:52 +02:00
archive = zipfile . ZipFile ( zipped )
try :
# New format
2016-07-21 13:43:04 +02:00
unzipped = BytesIO ( archive . open ( f [ ' md5 ' ] , pwd = b ' infected ' ) . read ( ) )
2015-09-18 14:38:52 +02:00
except KeyError :
# Old format
2016-07-21 13:43:04 +02:00
unzipped = BytesIO ( archive . open ( f [ ' filename ' ] , pwd = b ' infected ' ) . read ( ) )
2015-09-18 14:38:52 +02:00
details . append ( [ f [ ' event_id ' ] , f [ ' filename ' ] , unzipped ] )
except zipfile . BadZipfile :
# In case the sample isn't zipped
details . append ( [ f [ ' event_id ' ] , f [ ' filename ' ] , zipped ] )
2015-08-07 17:24:03 +02:00
return True , details
2015-08-05 17:20:59 +02:00
def download_last ( self , last ) :
2017-01-16 15:27:44 +01:00
""" Download the last updated events.
2015-08-05 17:20:59 +02:00
2017-01-16 15:27:44 +01:00
: param last : can be defined in days , hours , minutes ( for example 5 d or 12 h or 30 m )
2015-08-05 17:20:59 +02:00
"""
return self . search ( last = last )
2015-08-28 17:03:35 +02:00
# ############## Suricata ###############
2014-04-11 18:45:52 +02:00
2015-07-29 15:07:37 +02:00
def download_all_suricata ( self ) :
2017-01-16 15:27:44 +01:00
""" Download all suricata rules events. """
2015-08-10 11:58:20 +02:00
suricata_rules = urljoin ( self . root_url , ' events/nids/suricata/download ' )
2015-07-29 15:07:37 +02:00
session = self . __prepare_session ( ' rules ' )
2016-08-09 13:58:54 +02:00
response = session . get ( suricata_rules )
2016-08-11 17:50:47 +02:00
return response
2015-07-29 15:07:37 +02:00
def download_suricata_rule_event ( self , event_id ) :
2017-01-16 15:27:44 +01:00
""" Download one suricata rule event.
2015-07-29 15:07:37 +02:00
2017-01-16 15:27:44 +01:00
: param event_id : ID of the event to download ( same as get )
2015-07-29 15:07:37 +02:00
"""
2015-08-12 13:23:38 +02:00
template = urljoin ( self . root_url , ' events/nids/suricata/download/ {} ' . format ( event_id ) )
2015-07-29 15:07:37 +02:00
session = self . __prepare_session ( ' rules ' )
2016-08-09 13:58:54 +02:00
response = session . get ( template )
2016-08-11 17:50:47 +02:00
return response
2015-07-29 15:07:37 +02:00
2015-12-21 18:58:08 +01:00
# ########## Tags ##########
def get_all_tags ( self , quiet = False ) :
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2015-12-21 18:58:08 +01:00
url = urljoin ( self . root_url , ' tags ' )
response = session . get ( url )
r = self . _check_response ( response )
if not quiet or r . get ( ' errors ' ) :
return r
else :
to_return = [ ]
for tag in r [ ' Tag ' ] :
to_return . append ( tag [ ' name ' ] )
return to_return
2016-03-21 14:55:41 +01:00
def new_tag ( self , name = None , colour = " #00ace6 " , exportable = False ) :
to_post = { ' Tag ' : { ' name ' : name , ' colour ' : colour , ' exportable ' : exportable } }
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2016-03-14 12:17:53 +01:00
url = urljoin ( self . root_url , ' tags/add ' )
response = session . post ( url , data = json . dumps ( to_post ) )
return self . _check_response ( response )
2015-09-17 13:51:31 +02:00
# ########## Version ##########
2015-09-18 12:03:56 +02:00
def get_api_version ( self ) :
2017-01-16 15:27:44 +01:00
""" Returns the current version of PyMISP installed on the system """
2015-09-18 12:03:56 +02:00
return { ' version ' : __version__ }
def get_api_version_master ( self ) :
2017-01-16 15:27:44 +01:00
""" Get the most recent version of PyMISP from github """
2015-09-18 12:03:56 +02:00
r = requests . get ( ' https://raw.githubusercontent.com/MISP/PyMISP/master/pymisp/__init__.py ' )
if r . status_code == 200 :
version = re . findall ( " __version__ = ' (.*) ' " , r . text )
return { ' version ' : version [ 0 ] }
else :
2015-09-23 18:47:47 +02:00
return { ' error ' : ' Impossible to retrieve the version of the master branch. ' }
2015-09-18 12:03:56 +02:00
2015-09-17 13:51:31 +02:00
def get_version ( self ) :
2017-01-16 15:27:44 +01:00
""" Returns the version of the instance. """
2016-08-11 17:45:32 +02:00
session = self . __prepare_session ( )
2016-08-18 13:18:58 +02:00
url = urljoin ( self . root_url , ' servers/getVersion.json ' )
2015-09-23 18:47:47 +02:00
response = session . get ( url )
return self . _check_response ( response )
2015-09-17 13:51:31 +02:00
def get_version_master ( self ) :
2017-01-16 15:27:44 +01:00
""" Get the most recent version from github """
2016-06-15 02:44:36 +02:00
r = requests . get ( ' https://raw.githubusercontent.com/MISP/MISP/2.4/VERSION.json ' )
2015-09-17 13:51:31 +02:00
if r . status_code == 200 :
master_version = json . loads ( r . text )
return { ' version ' : ' {} . {} . {} ' . format ( master_version [ ' major ' ] , master_version [ ' minor ' ] , master_version [ ' hotfix ' ] ) }
else :
2015-09-23 18:47:47 +02:00
return { ' error ' : ' Impossible to retrieve the version of the master branch. ' }
2016-10-21 13:42:22 +02:00
2016-03-09 18:37:27 +01:00
# ############## Export Attributes in text ####################################
2015-09-17 13:51:31 +02:00
2016-03-09 18:37:27 +01:00
def get_all_attributes_txt ( self , type_attr ) :
2017-01-18 09:33:35 +01:00
""" Get all attributes from a specific type as plain text. Only published and IDS flagged attributes are exported. """
2016-03-09 18:37:27 +01:00
session = self . __prepare_session ( ' txt ' )
2016-03-21 14:55:41 +01:00
url = urljoin ( self . root_url , ' attributes/text/download/ %s ' % type_attr )
2016-03-09 18:37:27 +01:00
response = session . get ( url )
2016-08-11 17:50:47 +02:00
return response
2016-03-21 14:55:41 +01:00
2016-04-28 13:29:54 +02:00
# ############## Statistics ##################
2016-08-09 13:58:54 +02:00
def get_attributes_statistics ( self , context = ' type ' , percentage = None ) :
2017-01-16 15:27:44 +01:00
""" Get attributes statistics from the MISP instance """
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2016-04-28 13:29:54 +02:00
if ( context != ' category ' ) :
2016-04-28 14:45:02 +02:00
context = ' type '
2016-06-15 04:44:08 +02:00
if percentage is not None :
2016-04-28 13:29:54 +02:00
url = urljoin ( self . root_url , ' attributes/attributeStatistics/ {} / {} ' . format ( context , percentage ) )
else :
url = urljoin ( self . root_url , ' attributes/attributeStatistics/ {} ' . format ( context ) )
2016-08-09 13:58:54 +02:00
response = session . get ( url )
return self . _check_response ( response )
2016-04-28 13:29:54 +02:00
2016-08-09 13:58:54 +02:00
def get_tags_statistics ( self , percentage = None , name_sort = None ) :
2017-01-16 15:27:44 +01:00
""" Get tags statistics from the MISP instance """
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2016-06-15 04:44:08 +02:00
if percentage is not None :
2016-05-23 15:16:31 +02:00
percentage = ' true '
else :
percentage = ' false '
2016-06-15 04:44:08 +02:00
if name_sort is not None :
2016-05-23 15:16:31 +02:00
name_sort = ' true '
else :
name_sort = ' false '
url = urljoin ( self . root_url , ' tags/tagStatistics/ {} / {} ' . format ( percentage , name_sort ) )
2016-09-12 12:53:58 +02:00
response = session . get ( url )
2016-08-09 13:58:54 +02:00
return self . _check_response ( response )
2016-05-23 15:16:31 +02:00
2016-07-01 10:33:44 +02:00
# ############## Sightings ##################
2016-04-29 16:35:27 +02:00
2016-08-09 13:58:54 +02:00
def sighting_per_id ( self , attribute_id ) :
session = self . __prepare_session ( )
2016-05-23 15:16:31 +02:00
url = urljoin ( self . root_url , ' sightings/add/ {} ' . format ( attribute_id ) )
2016-08-09 13:58:54 +02:00
response = session . post ( url )
return self . _check_response ( response )
2016-04-29 16:35:27 +02:00
2016-08-09 13:58:54 +02:00
def sighting_per_uuid ( self , attribute_uuid ) :
session = self . __prepare_session ( )
2016-05-23 15:16:31 +02:00
url = urljoin ( self . root_url , ' sightings/add/ {} ' . format ( attribute_uuid ) )
2016-08-09 13:58:54 +02:00
response = session . post ( url )
return self . _check_response ( response )
2016-04-29 16:35:27 +02:00
2016-08-09 13:58:54 +02:00
def sighting_per_json ( self , json_file ) :
session = self . __prepare_session ( )
2016-04-29 16:35:27 +02:00
jdata = json . load ( open ( json_file ) )
2016-05-23 15:16:31 +02:00
url = urljoin ( self . root_url , ' sightings/add/ ' )
2016-08-09 13:58:54 +02:00
response = session . post ( url , data = json . dumps ( jdata ) )
return self . _check_response ( response )
2016-04-29 16:35:27 +02:00
2016-05-19 14:09:01 +02:00
# ############## Sharing Groups ##################
def get_sharing_groups ( self ) :
2016-08-09 13:58:54 +02:00
session = self . __prepare_session ( )
2017-01-16 20:47:43 +01:00
url = urljoin ( self . root_url , ' sharing_groups.json ' )
2016-06-15 04:44:08 +02:00
response = session . get ( url )
2017-01-11 20:29:20 +01:00
return self . _check_response ( response ) [ ' response ' ]
2016-11-03 11:23:48 +01:00
# ############## Users ##################
2016-11-15 10:59:29 +01:00
def _set_user_parameters ( self , email , org_id , role_id , password , external_auth_required ,
external_auth_key , enable_password , nids_sid , server_id ,
gpgkey , certif_public , autoalert , contactalert , disabled ,
change_pw , termsaccepted , newsread ) :
user = { }
if email is not None :
user [ ' email ' ] = email
if org_id is not None :
user [ ' org_id ' ] = org_id
if role_id is not None :
user [ ' role_id ' ] = role_id
if password is not None :
user [ ' password ' ] = password
if external_auth_required is not None :
user [ ' external_auth_required ' ] = external_auth_required
if external_auth_key is not None :
user [ ' external_auth_key ' ] = external_auth_key
if enable_password is not None :
user [ ' enable_password ' ] = enable_password
if nids_sid is not None :
user [ ' nids_sid ' ] = nids_sid
if server_id is not None :
user [ ' server_id ' ] = server_id
if gpgkey is not None :
user [ ' gpgkey ' ] = gpgkey
if certif_public is not None :
user [ ' certif_public ' ] = certif_public
if autoalert is not None :
user [ ' autoalert ' ] = autoalert
if contactalert is not None :
user [ ' contactalert ' ] = contactalert
if disabled is not None :
user [ ' disabled ' ] = disabled
if change_pw is not None :
user [ ' change_pw ' ] = change_pw
if termsaccepted is not None :
user [ ' termsaccepted ' ] = termsaccepted
if newsread is not None :
user [ ' newsread ' ] = newsread
return user
2016-11-03 11:23:48 +01:00
def get_users_list ( self ) :
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users ' )
response = session . get ( url )
return self . _check_response ( response ) [ ' response ' ]
def get_user ( self , user_id ) :
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users/view/ {} ' . format ( user_id ) )
response = session . get ( url )
return self . _check_response ( response )
2016-11-04 11:58:21 +01:00
def add_user ( self , email , org_id , role_id , password = None ,
external_auth_required = None , external_auth_key = None ,
enable_password = None , nids_sid = None , server_id = None ,
gpgkey = None , certif_public = None , autoalert = None ,
contactalert = None , disabled = None , change_pw = None ,
termsaccepted = None , newsread = None ) :
2016-11-15 10:59:29 +01:00
new_user = self . _set_user_parameters ( email , org_id , role_id , password ,
external_auth_required , external_auth_key ,
enable_password , nids_sid , server_id ,
gpgkey , certif_public , autoalert ,
contactalert , disabled , change_pw ,
termsaccepted , newsread )
2016-11-04 11:58:21 +01:00
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users/add/ ' )
response = session . post ( url , data = json . dumps ( new_user ) )
return self . _check_response ( response )
def add_user_json ( self , json_file ) :
2016-11-03 11:23:48 +01:00
session = self . __prepare_session ( )
jdata = json . load ( open ( json_file ) )
url = urljoin ( self . root_url , ' admin/users/add/ ' )
response = session . post ( url , data = json . dumps ( jdata ) )
return self . _check_response ( response )
def get_add_user_fields_list ( self ) :
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users/add/ ' )
response = session . get ( url )
return self . _check_response ( response )
2016-11-04 11:58:21 +01:00
def edit_user ( self , user_id , email = None , org_id = None , role_id = None ,
password = None , external_auth_required = None ,
external_auth_key = None , enable_password = None , nids_sid = None ,
server_id = None , gpgkey = None , certif_public = None ,
autoalert = None , contactalert = None , disabled = None ,
change_pw = None , termsaccepted = None , newsread = None ) :
2016-11-15 10:59:29 +01:00
edit_user = self . _set_user_parameters ( email , org_id , role_id , password ,
external_auth_required , external_auth_key ,
enable_password , nids_sid , server_id ,
gpgkey , certif_public , autoalert ,
contactalert , disabled , change_pw ,
termsaccepted , newsread )
2016-11-04 11:58:21 +01:00
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users/edit/ {} ' . format ( user_id ) )
response = session . post ( url , data = json . dumps ( edit_user ) )
return self . _check_response ( response )
def edit_user_json ( self , json_file , user_id ) :
2016-11-03 11:23:48 +01:00
session = self . __prepare_session ( )
jdata = json . load ( open ( json_file ) )
url = urljoin ( self . root_url , ' admin/users/edit/ {} ' . format ( user_id ) )
response = session . post ( url , data = json . dumps ( jdata ) )
return self . _check_response ( response )
def get_edit_user_fields_list ( self , user_id ) :
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users/edit/ {} ' . format ( user_id ) )
response = session . get ( url )
return self . _check_response ( response )
def delete_user ( self , user_id ) :
session = self . __prepare_session ( )
url = urljoin ( self . root_url , ' admin/users/delete/ {} ' . format ( user_id ) )
response = session . post ( url )
return self . _check_response ( response )