Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoiding issues with analyst data objects #1307

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
110 changes: 87 additions & 23 deletions pymisp/mispevent.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,37 @@ def relationships(self) -> list[MISPRelationship]:

def add_note(self, note: str, language: str | None = None, **kwargs) -> MISPNote: # type: ignore[no-untyped-def]
the_note = MISPNote()
the_note.from_dict(note=note, language=language,
object_uuid=self.uuid, object_type=self.analyst_data_object_type,
**kwargs)
object_uuid = kwargs.pop('object_uuid', self.uuid)
object_type = kwargs.pop('object_type', self.analyst_data_object_type)
the_note.from_dict(
note=note, language=language, object_uuid=object_uuid,
object_type=object_type, contained=True, parent=self, **kwargs
)
self.notes.append(the_note)
self.edited = True
return the_note

def add_opinion(self, opinion: int, comment: str | None = None, **kwargs) -> MISPOpinion: # type: ignore[no-untyped-def]
the_opinion = MISPOpinion()
the_opinion.from_dict(opinion=opinion, comment=comment,
object_uuid=self.uuid, object_type=self.analyst_data_object_type,
**kwargs)
object_uuid = kwargs.pop('object_uuid', self.uuid)
object_type = kwargs.pop('object_type', self.analyst_data_object_type)
the_opinion.from_dict(
opinion=opinion, comment=comment, object_uuid=object_uuid,
object_type=object_type, contained=True, parent=self, **kwargs
)
self.opinions.append(the_opinion)
self.edited = True
return the_opinion

def add_relationship(self, related_object_type: AbstractMISP | str, related_object_uuid: str | None, relationship_type: str, **kwargs) -> MISPRelationship: # type: ignore[no-untyped-def]
the_relationship = MISPRelationship()
the_relationship.from_dict(related_object_type=related_object_type, related_object_uuid=related_object_uuid,
relationship_type=relationship_type,
object_uuid=self.uuid, object_type=self.analyst_data_object_type,
**kwargs)
the_relationship.from_dict(
related_object_type=related_object_type,
related_object_uuid=related_object_uuid,
relationship_type=relationship_type, object_uuid=self.uuid,
object_type=self.analyst_data_object_type, contained=True,
parent=self, **kwargs
)
self.relationships.append(the_relationship)
self.edited = True
return the_relationship
Expand All @@ -93,12 +102,8 @@ def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def]
relationships = kwargs.pop('Relationship', [])
super().from_dict(**kwargs)
for note in notes:
note.pop('object_uuid', None)
note.pop('object_type', None)
self.add_note(**note)
for opinion in opinions:
opinion.pop('object_uuid', None)
opinion.pop('object_type', None)
self.add_opinion(**opinion)
for relationship in relationships:
relationship.pop('object_uuid', None)
Expand Down Expand Up @@ -2489,6 +2494,10 @@ class MISPAnalystData(AbstractMISP):
'Object', 'Note', 'Opinion', 'Relationship', 'Organisation',
'SharingGroup'}

@property
def analyst_data_object_type(self) -> str:
return self._analyst_data_object_type

@property
def org(self) -> MISPOrganisation:
return self.Org
Expand All @@ -2504,6 +2513,10 @@ def orgc(self, orgc: MISPOrganisation) -> None:
else:
raise PyMISPError('Orgc must be of type MISPOrganisation.')

@property
def parent(self) -> MISPAttribute | MISPEvent | MISPEventReport | MISPObject:
return self.__parent

def __new__(cls, *args, **kwargs):
if cls is MISPAnalystData:
raise TypeError(f"only children of '{cls.__name__}' may be instantiated")
Expand All @@ -2518,8 +2531,54 @@ def __init__(self, **kwargs: dict[str, Any]) -> None:
self.created: float | int | datetime
self.modified: float | int | datetime
self.SharingGroup: MISPSharingGroup
self._analyst_data_object_type: str # Must be defined in the child class

def add_note(self, note: str, language: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs: dict[str, Any]) -> MISPNote:
misp_note = MISPNote()
if object_uuid is None:
object_uuid = self.uuid
if object_type is None:
object_type = self.analyst_data_object_type
if parent is None and hasattr(self, 'parent'):
parent = self.parent
misp_note.from_dict(
note=note, language=language, object_uuid=object_uuid,
object_type=object_type, parent=parent, contained=True, **kwargs
)
if parent is None:
if not hasattr(self, 'Note'):
self.Note: list[MISPNote] = []
self.Note.append(misp_note)
else:
self.parent.notes.append(misp_note)
self.edited = True
return misp_note

def add_opinion(self, opinion: int, comment: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs: dict[str, Any]) -> MISPOpinion:
misp_opinion = MISPOpinion()
if object_uuid is None:
object_uuid = self.uuid
if object_type is None:
object_type = self.analyst_data_object_type
if parent is None and hasattr(self, 'parent'):
parent = self.parent
misp_opinion.from_dict(
opinion=opinion, comment=comment, object_uuid=object_uuid,
object_type=object_type, parent=parent, contained=True, **kwargs
)
if parent is None:
if not hasattr(self, 'Opinion'):
self.Opinion: list[MISPOpinion] = []
self.Opinion.append(misp_opinion)
else:
self.parent.opinions.append(misp_opinion)
self.edited = True
return misp_opinion

def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def]
notes = kwargs.pop('Note', [])
opinions = kwargs.pop('Opinion', [])
self.__parent = kwargs.pop('parent', None)
self.distribution = kwargs.pop('distribution', None)
if self.distribution is not None:
self.distribution = int(self.distribution)
Expand Down Expand Up @@ -2573,14 +2632,19 @@ def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def]

super().from_dict(**kwargs)

for note in notes:
self.add_note(**note)
for opinion in opinions:
self.add_opinion(**opinion)

def _set_default(self) -> None:
if not hasattr(self, 'created'):
self.created = datetime.timestamp(datetime.now())
if not hasattr(self, 'modified'):
self.modified = self.created


class MISPNote(AnalystDataBehaviorMixin, MISPAnalystData):
class MISPNote(MISPAnalystData):

_fields_for_feed: set[str] = MISPAnalystData._fields_for_feed.union({'note', 'language'})

Expand All @@ -2591,8 +2655,8 @@ def __init__(self, **kwargs: dict[str, Any]) -> None:
self.language: str
super().__init__(**kwargs)

def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def]
if 'Note' in kwargs:
def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def]
if not contained and 'Note' in kwargs:
kwargs = kwargs['Note']
self.note = kwargs.pop('note', None)
if self.note is None:
Expand All @@ -2605,7 +2669,7 @@ def __repr__(self) -> str:
return f'<{self.__class__.__name__}(NotInitialized)'


class MISPOpinion(AnalystDataBehaviorMixin, MISPAnalystData):
class MISPOpinion(MISPAnalystData):

_fields_for_feed: set[str] = MISPAnalystData._fields_for_feed.union({'opinion', 'comment'})

Expand All @@ -2616,8 +2680,8 @@ def __init__(self, **kwargs: dict[str, Any]) -> None:
self.comment: str
super().__init__(**kwargs)

def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def]
if 'Opinion' in kwargs:
def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def]
if not contained and 'Opinion' in kwargs:
kwargs = kwargs['Opinion']
self.opinion = kwargs.pop('opinion', None)
if self.opinion is not None:
Expand All @@ -2639,7 +2703,7 @@ def __repr__(self) -> str:
return f'<{self.__class__.__name__}(NotInitialized)'


class MISPRelationship(AnalystDataBehaviorMixin, MISPAnalystData):
class MISPRelationship(MISPAnalystData):

_fields_for_feed: set[str] = MISPAnalystData._fields_for_feed.union({'related_object_uuid', 'related_object_type', 'relationship_type'})

Expand All @@ -2651,8 +2715,8 @@ def __init__(self, **kwargs: dict[str, Any]) -> None:
self.relationship_type: str
super().__init__(**kwargs)

def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def]
if 'Relationship' in kwargs:
def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def]
if not contained and 'Relationship' in kwargs:
kwargs = kwargs['Relationship']
self.related_object_type = kwargs.pop('related_object_type', None)
if self.related_object_type is None:
Expand Down
Loading