new: Improve python3.6+ lib

pull/382/head
Raphaël Vinot 2019-04-11 23:13:15 +02:00
parent e8334be9ca
commit 633f75db24
5 changed files with 83 additions and 4 deletions

View File

@ -35,7 +35,7 @@ try:
from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse, PyMISPEmptyResponse # noqa from .exceptions import PyMISPError, NewEventError, NewAttributeError, MissingDependency, NoURL, NoKey, InvalidMISPObject, UnknownMISPObjectTemplate, PyMISPInvalidFormat, MISPServerError, PyMISPNotImplementedYet, PyMISPUnexpectedResponse, PyMISPEmptyResponse # 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, MISPLog # noqa from .mispevent import MISPEvent, MISPAttribute, MISPObjectReference, MISPObjectAttribute, MISPObject, MISPUser, MISPOrganisation, MISPSighting, MISPLog, MISPShadowAttribute # noqa
from .tools import AbstractMISPObjectGenerator # noqa from .tools import AbstractMISPObjectGenerator # noqa
from .tools import Neo4j # noqa from .tools import Neo4j # noqa
from .tools import stix # noqa from .tools import stix # noqa

View File

@ -164,7 +164,7 @@ class PyMISP(object):
if isinstance(data, dict): if isinstance(data, dict):
# Remove None values. # Remove None values.
data = {k: v for k, v in data.items() if v is not None} data = {k: v for k, v in data.items() if v is not None}
data = json.dumps(data) data = json.dumps(data, cls=MISPEncode)
req = requests.Request(request_type, url, data=data) req = requests.Request(request_type, url, data=data)
if self.asynch and background_callback is not None: if self.asynch and background_callback is not None:
local_session = FuturesSession local_session = FuturesSession

View File

@ -3,7 +3,7 @@
from .exceptions import MISPServerError, PyMISPUnexpectedResponse, PyMISPNotImplementedYet from .exceptions import MISPServerError, PyMISPUnexpectedResponse, PyMISPNotImplementedYet
from .api import PyMISP, everything_broken from .api import PyMISP, everything_broken
from .mispevent import MISPEvent, MISPAttribute, MISPSighting, MISPLog, MISPObject, MISPUser, MISPOrganisation from .mispevent import MISPEvent, MISPAttribute, MISPSighting, MISPLog, MISPObject, MISPUser, MISPOrganisation, MISPShadowAttribute
from typing import TypeVar, Optional, Tuple, List, Dict, Union from typing import TypeVar, Optional, Tuple, List, Dict, Union
from datetime import date, datetime from datetime import date, datetime
import csv import csv
@ -151,6 +151,36 @@ class ExpandedPyMISP(PyMISP):
e.load(updated_event) e.load(updated_event)
return e return e
def get_attribute(self, attribute_id: int):
attribute = super().get_attribute(attribute_id)
a = MISPAttribute()
a.from_dict(**attribute)
return a
def add_attribute(self, event_id: int, attribute: MISPAttribute):
url = urljoin(self.root_url, 'attributes/add/{}'.format(event_id))
response = self._prepare_request('POST', url, data=attribute)
new_attribute = self._check_response(response)
if isinstance(new_attribute, str):
raise PyMISPUnexpectedResponse(f'Unexpected response from server: {new_attribute}')
elif 'errors' in new_attribute:
return new_attribute
a = MISPAttribute()
a.from_dict(**new_attribute)
return a
def add_attribute_proposal(self, event_id: int, attribute: MISPAttribute):
url = urljoin(self.root_url, 'shadow_attributes/add/{}'.format(event_id))
response = self._prepare_request('POST', url, attribute)
new_attribute_proposal = self._check_response(response)
if isinstance(new_attribute_proposal, str):
raise PyMISPUnexpectedResponse(f'Unexpected response from server: {new_attribute_proposal}')
elif 'errors' in new_attribute_proposal:
return new_attribute_proposal
a = MISPShadowAttribute()
a.from_dict(**new_attribute_proposal)
return a
def update_attribute(self, attribute: MISPAttribute): def update_attribute(self, attribute: MISPAttribute):
updated_attribute = super().update_attribute(attribute.uuid, attribute) updated_attribute = super().update_attribute(attribute.uuid, attribute)
if isinstance(updated_attribute, str): if isinstance(updated_attribute, str):
@ -161,6 +191,48 @@ class ExpandedPyMISP(PyMISP):
a.from_dict(**updated_attribute) a.from_dict(**updated_attribute)
return a return a
def update_attribute_proposal(self, attribute_id: int, attribute: MISPAttribute):
url = urljoin(self.root_url, 'shadow_attributes/edit/{}'.format(attribute_id))
# FIXME: Inconsistency on MISP side
attribute = {'ShadowAttribute': attribute}
response = self._prepare_request('POST', url, attribute)
attribute_proposal = self._check_response(response)
if isinstance(attribute_proposal, str):
raise PyMISPUnexpectedResponse(f'Unexpected response from server: {attribute_proposal}')
elif 'errors' in attribute_proposal:
return attribute_proposal
a = MISPShadowAttribute()
a.from_dict(**attribute_proposal)
return a
def get_attribute_proposal(self, proposal_id: int):
url = urljoin(self.root_url, 'shadow_attributes/view/{}'.format(proposal_id))
response = self._prepare_request('GET', url)
attribute_proposal = self._check_response(response)
if isinstance(attribute_proposal, str):
raise PyMISPUnexpectedResponse(f'Unexpected response from server: {attribute_proposal}')
elif 'errors' in attribute_proposal:
return attribute_proposal
a = MISPShadowAttribute()
a.from_dict(**attribute_proposal)
return a
def accept_attribute_proposal(self, proposal_id: int):
url = urljoin(self.root_url, 'shadow_attributes/accept/{}'.format(proposal_id))
response = self._prepare_request('POST', url)
r = self._check_response(response)
if isinstance(r, str):
raise PyMISPUnexpectedResponse(f'Unexpected response from server: {r}')
return r
def discard_attribute_proposal(self, proposal_id: int):
url = urljoin(self.root_url, 'shadow_attributes/discard/{}'.format(proposal_id))
response = self._prepare_request('POST', url)
r = self._check_response(response)
if isinstance(r, str):
raise PyMISPUnexpectedResponse(f'Unexpected response from server: {r}')
return r
def add_user(self, user: MISPUser): def add_user(self, user: MISPUser):
user = super().add_user(user) user = super().add_user(user)
if isinstance(user, str): if isinstance(user, str):

View File

@ -916,11 +916,17 @@ class MISPObjectAttribute(MISPAttribute):
return '<{self.__class__.__name__}(NotInitialized)'.format(self=self) return '<{self.__class__.__name__}(NotInitialized)'.format(self=self)
class MISPShadowAttribute(MISPAttribute): class MISPShadowAttribute(AbstractMISP):
# NOTE: Kindof a MISPAttribute, but can be lot more lightweight (just one key for example)
def __init__(self): def __init__(self):
super(MISPShadowAttribute, self).__init__() super(MISPShadowAttribute, self).__init__()
def from_dict(self, **kwargs):
if kwargs.get('ShadowAttribute'):
kwargs = kwargs.get('ShadowAttribute')
super(MISPShadowAttribute, self).from_dict(**kwargs)
class MISPObject(AbstractMISP): class MISPObject(AbstractMISP):

View File

@ -137,6 +137,7 @@ class TestMISPEvent(unittest.TestCase):
ref_json = json.load(f) ref_json = json.load(f)
self.assertEqual(self.mispevent.to_json(), json.dumps(ref_json, sort_keys=True, indent=2)) self.assertEqual(self.mispevent.to_json(), json.dumps(ref_json, sort_keys=True, indent=2))
@unittest.skip("Not supported on MISP.")
def test_shadow_attributes(self): def test_shadow_attributes(self):
self.init_event() self.init_event()
p = self.mispevent.add_proposal(type='filename', value='baz.jpg') p = self.mispevent.add_proposal(type='filename', value='baz.jpg')