Merge branch 'async'

pull/80/head
Hannah Ward 2017-05-03 09:43:45 +01:00
commit 36661439cc
No known key found for this signature in database
GPG Key ID: 6F3BAD60DE190290
1 changed files with 35 additions and 7 deletions

View File

@ -27,6 +27,13 @@ try:
except ImportError: except ImportError:
HAVE_REQUESTS = False HAVE_REQUESTS = False
try:
from requests_futures.sessions import FuturesSession
ASYNC_OK = True
except ImportError:
ASYNC_OK = False
from . import __version__ from . import __version__
from .exceptions import PyMISPError, SearchError, MissingDependency, NoURL, NoKey from .exceptions import PyMISPError, SearchError, MissingDependency, NoURL, NoKey
from .mispevent import MISPEvent, MISPAttribute, EncodeUpdate from .mispevent import MISPEvent, MISPAttribute, EncodeUpdate
@ -80,9 +87,10 @@ class PyMISP(object):
:param debug: print all the messages received from the server :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 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 :param cert: Client certificate, as described there: http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification
:param asynch: Use asynchronous processing where possible
""" """
def __init__(self, url, key, ssl=True, out_type='json', debug=False, proxies=None, cert=None): def __init__(self, url, key, ssl=True, out_type='json', debug=False, proxies=None, cert=None, asynch=False):
if not url: if not url:
raise NoURL('Please provide the URL of your MISP instance.') raise NoURL('Please provide the URL of your MISP instance.')
if not key: if not key:
@ -93,6 +101,11 @@ class PyMISP(object):
self.ssl = ssl self.ssl = ssl
self.proxies = proxies self.proxies = proxies
self.cert = cert self.cert = cert
self.asynch = asynch
if asynch and not ASYNC_OK:
warnings.warn("You turned on Async, but don't have requests_futures installed")
self.asynch = False
self.ressources_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data') self.ressources_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
if out_type != 'json': 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') raise PyMISPError('The only output type supported by PyMISP is JSON. If you still rely on XML, use PyMISP v2.4.49')
@ -137,12 +150,15 @@ class PyMISP(object):
self.category_type_mapping = self.describe_types['category_type_mappings'] self.category_type_mapping = self.describe_types['category_type_mappings']
self.sane_default = self.describe_types['sane_defaults'] self.sane_default = self.describe_types['sane_defaults']
def __prepare_session(self, output='json'): def __prepare_session(self, output='json', async_implemented=False):
"""Prepare the headers of the session""" """Prepare the headers of the session"""
if not HAVE_REQUESTS: if not HAVE_REQUESTS:
raise MissingDependency('Missing dependency, install requests (`pip install requests`)') raise MissingDependency('Missing dependency, install requests (`pip install requests`)')
session = requests.Session() if self.asynch and async_implemented:
session = FuturesSession()
else:
session = requests.Session()
session.verify = self.ssl session.verify = self.ssl
session.proxies = self.proxies session.proxies = self.proxies
session.cert = self.cert session.cert = self.cert
@ -774,8 +790,11 @@ class PyMISP(object):
def search_index(self, published=None, eventid=None, tag=None, datefrom=None, def search_index(self, published=None, eventid=None, tag=None, datefrom=None,
dateuntil=None, eventinfo=None, threatlevel=None, distribution=None, dateuntil=None, eventinfo=None, threatlevel=None, distribution=None,
analysis=None, attribute=None, org=None): analysis=None, attribute=None, org=None, async_callback=None):
"""Search only at the index level. Use ! infront of value as NOT, default OR """Search only at the index level. Use ! infront of value as NOT, default OR
If using async, give a callback that takes 2 args, session and response:
basic usage is
pymisp.search_index(..., async_callback=lambda ses,resp: print(resp.json()))
:param published: Published (0,1) :param published: Published (0,1)
:param eventid: Evend ID(s) | str or list :param eventid: Evend ID(s) | str or list
@ -787,6 +806,7 @@ class PyMISP(object):
:param distribution: Distribution level(s) (0,1,2,3) | 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 analysis: Analysis level(s) (0,1,2) | str or list
:param org: Organisation(s) | str or list :param org: Organisation(s) | str or list
:param async_callback: Function to call when the request returns (if running async)
""" """
allowed = {'published': published, 'eventid': eventid, 'tag': tag, 'Dateuntil': dateuntil, allowed = {'published': published, 'eventid': eventid, 'tag': tag, 'Dateuntil': dateuntil,
'Datefrom': datefrom, 'eventinfo': eventinfo, 'threatlevel': threatlevel, 'Datefrom': datefrom, 'eventinfo': eventinfo, 'threatlevel': threatlevel,
@ -799,6 +819,7 @@ class PyMISP(object):
to_post = {} to_post = {}
for rule in allowed.keys(): for rule in allowed.keys():
if allowed.get(rule) is None: if allowed.get(rule) is None:
continue continue
param = allowed[rule] param = allowed[rule]
@ -809,10 +830,17 @@ class PyMISP(object):
if not set(param).issubset(rule_levels[rule]): if not set(param).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]))) raise SearchError('Values in your {} are invalid, has to be in {}'.format(rule, ', '.join(str(x) for x in rule_levels[rule])))
to_post[rule] = '|'.join(str(x) for x in param) to_post[rule] = '|'.join(str(x) for x in param)
session = self.__prepare_session() session = self.__prepare_session(async_implemented=True)
url = urljoin(self.root_url, buildup_url) url = urljoin(self.root_url, buildup_url)
response = session.post(url, data=json.dumps(to_post))
return self._check_response(response) if self.asynch:
if not async_callback:
warnings.warn("You haven't provided a callback!")
response = session.get(url, background_callback=async_callback)
else:
response = session.post(url, data=json.dumps(to_post))
return self._check_response(response)
def search_all(self, value): def search_all(self, value):
query = {'value': value, 'searchall': 1} query = {'value': value, 'searchall': 1}