New: use new CSV interface, add test cases

pull/277/head
Raphaël Vinot 2018-09-17 18:37:07 -07:00
parent ceedb6e95c
commit cd1de8c6bf
4 changed files with 98 additions and 3 deletions

View File

@ -32,7 +32,7 @@ def deprecated(func):
try: try:
from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError # noqa from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse # noqa
from .api import PyMISP # noqa from .api import PyMISP # noqa
from .abstract import AbstractMISP, MISPEncode, MISPTag, Distribution, ThreatLevel, Analysis # noqa from .abstract import AbstractMISP, MISPEncode, MISPTag, Distribution, ThreatLevel, Analysis # noqa
from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting # noqa from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting # noqa

View File

@ -1,11 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .exceptions import MISPServerError, NewEventError, UpdateEventError, UpdateAttributeError from .exceptions import MISPServerError, NewEventError, UpdateEventError, UpdateAttributeError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse
from .api import PyMISP, everything_broken, MISPEvent, MISPAttribute from .api import PyMISP, everything_broken, MISPEvent, MISPAttribute
from typing import TypeVar, Optional, Tuple, List, Dict from typing import TypeVar, Optional, Tuple, List, Dict
from datetime import date, datetime from datetime import date, datetime
import json import json
import csv
import logging import logging
from urllib.parse import urljoin from urllib.parse import urljoin
@ -194,5 +195,76 @@ class ExpandedPyMISP(PyMISP):
ma.from_dict(**a) ma.from_dict(**a)
to_return.append(ma) to_return.append(ma)
elif controller == 'objects': elif controller == 'objects':
raise Exception('Not implemented yet') raise PyMISPNotImplementedYet('Not implemented yet')
return to_return return to_return
def get_csv(self,
eventid: Optional[SearchType]=None,
ignore: Optional[bool]=None,
tags: Optional[SearchParameterTypes]=None,
category: Optional[SearchParameterTypes]=None,
type_attribute: Optional[SearchParameterTypes]=None,
include_context: Optional[bool]=None, includeContext: Optional[bool]=None,
date_from: Optional[DateTypes]=None, date_to: Optional[DateTypes]=None,
publish_timestamp: Optional[DateInterval]=None, # converted internally to last (consistent with search)
headerless: Optional[bool]=None,
enforce_warninglist: Optional[bool]=None, enforceWarninglist: Optional[bool]=None,
pythonify: Optional[bool]=False,
**kwargs):
# Add all the parameters in kwargs are aimed at modules, or other 3rd party components, and cannot be sanitized.
# They are passed as-is.
query = kwargs
if eventid is not None:
query['eventid'] = eventid
if ignore is not None:
query['ignore'] = ignore
if tags is not None:
query['tags'] = tags
if category is not None:
query['category'] = category
if type_attribute is not None:
query['type'] = type_attribute
if include_context is not None:
query['includeContext'] = include_context
if includeContext is not None:
query['includeContext'] = includeContext
if date_from is not None:
query['from'] = self.make_timestamp(date_from)
if date_to is not None:
query['to'] = self.make_timestamp(date_to)
if publish_timestamp is not None:
if isinstance(publish_timestamp, (list, tuple)):
query['last'] = (self.make_timestamp(publish_timestamp[0]), self.make_timestamp(publish_timestamp[1]))
else:
query['last'] = self.make_timestamp(publish_timestamp)
if headerless is not None:
query['headerless'] = headerless
if enforce_warninglist is not None:
query['enforceWarninglist'] = enforce_warninglist
if enforceWarninglist is not None:
# Alias for enforce_warninglist
query['enforceWarninglist'] = enforceWarninglist
url = urljoin(self.root_url, '/events/csv/download/')
response = self._prepare_request('POST', url, data=json.dumps(query))
normalized_response = self._check_response(response)
if isinstance(normalized_response, str):
if pythonify:
# Make it a list of dict
fieldnames, lines = normalized_response.split('\n', 1)
fieldnames = fieldnames.split(',')
to_return = []
for line in csv.reader(lines.split('\n')):
if line:
to_return.append({fname: value for fname, value in zip(fieldnames, line)})
return to_return
return normalized_response
elif isinstance(normalized_response, dict):
# The server returned a dictionary, it contains the error message.
logger.critical(f'The server should have returned a CSV file as text. instead it returned an error message:\n{normalized_response}')
return normalized_response
else:
# Should not happen...
raise PyMISPUnexpectedResponse(f'The server should have returned a CSV file as text. instead it returned:\n{normalized_response}')

View File

@ -59,3 +59,11 @@ class PyMISPInvalidFormat(PyMISPError):
class MISPServerError(PyMISPError): class MISPServerError(PyMISPError):
pass pass
class PyMISPNotImplementedYet(PyMISPError):
pass
class PyMISPUnexpectedResponse(PyMISPError):
pass

View File

@ -487,6 +487,21 @@ class TestComprehensive(unittest.TestCase):
# Delete event # Delete event
self.admin_misp_connector.delete_event(first.id) self.admin_misp_connector.delete_event(first.id)
def test_get_csv(self):
first = self.create_simple_event()
try:
first.attributes[0].comment = 'This is the original comment'
first = self.user_misp_connector.add_event(first)
response = self.user_misp_connector.fast_publish(first.id, alert=False)
self.assertEqual(response['errors'][0][1]['message'], 'You do not have permission to use this functionality.')
self.admin_misp_connector.fast_publish(first.id, alert=False)
csv = self.user_misp_connector.get_csv(publish_timestamp=first.timestamp.timestamp() - 5, pythonify=True)
self.assertEqual(csv[0]['value'], first.attributes[0].value)
finally:
# Delete event
self.admin_misp_connector.delete_event(first.id)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()