mirror of https://github.com/MISP/PyMISP
parent
029ca57b5f
commit
8194c534d7
|
@ -309,11 +309,11 @@ def get_value_link_to_event(misp_event, item, col2_style, config=None, color=Tru
|
|||
'''
|
||||
|
||||
# Does MispEven has the attribute ?
|
||||
if hasattr(misp_event, item[1]):
|
||||
if is_safe_attribute(misp_event, item[1]):
|
||||
# It has the requested attribute .. building upon it.
|
||||
|
||||
# Does misp_object has an uuid and do we know the baseurl ?
|
||||
if hasattr(misp_event, "uuid") and config is not None and moduleconfig[0] in config:
|
||||
if is_safe_attribute(misp_event, "uuid") and config is not None and moduleconfig[0] in config:
|
||||
# We can build links
|
||||
curr_uuid = str(getattr(misp_event, "uuid"))
|
||||
curr_baseurl = config[moduleconfig[0]]
|
||||
|
@ -348,7 +348,7 @@ def get_timestamp_value(misp_event, item, col2_style):
|
|||
:param col2_style: style to be applied on the returned paragraph
|
||||
:return: a Paragraph to add in the pdf, regarding the values of "timestamp"
|
||||
'''
|
||||
if hasattr(misp_event, item[1]):
|
||||
if is_safe_attribute(misp_event, item[1]):
|
||||
return Paragraph(str(getattr(misp_event, item[1]).strftime(EXPORT_DATE_FORMAT)), col2_style)
|
||||
return Paragraph(item[2], col2_style)
|
||||
|
||||
|
@ -363,7 +363,7 @@ def get_creator_organisation_value(misp_event, item, col2_style):
|
|||
:param col2_style: style to be applied on the returned paragraph
|
||||
:return: a Paragraph to add in the pdf, regarding the values of "creator organisation"
|
||||
'''
|
||||
if hasattr(misp_event, item[1]):
|
||||
if is_safe_attribute(misp_event, item[1]):
|
||||
return Paragraph(safe_string(getattr(getattr(misp_event, item[1]), item[3])), col2_style)
|
||||
return Paragraph(item[2], col2_style)
|
||||
|
||||
|
@ -378,7 +378,7 @@ def get_attributes_number_value(misp_event, item, col2_style):
|
|||
:param col2_style: style to be applied on the returned paragraph
|
||||
:return: a Paragraph to add in the pdf, regarding the values of "attributes"
|
||||
'''
|
||||
if hasattr(misp_event, item[1]):
|
||||
if is_safe_attribute(misp_event, item[1]):
|
||||
return Paragraph(str(len(getattr(misp_event, item[1]))), col2_style)
|
||||
return Paragraph(item[2], col2_style)
|
||||
|
||||
|
@ -393,7 +393,7 @@ def get_tag_value(misp_event, item, col2_style):
|
|||
:param col2_style: style to be applied on the returned paragraph
|
||||
:return: a Paragraph to add in the pdf, regarding the values of "tags"
|
||||
'''
|
||||
if hasattr(misp_event, item[1]):
|
||||
if is_safe_attribute_table(misp_event, item[1]):
|
||||
table_event_tags = create_flowable_table_from_tags(misp_event)
|
||||
return table_event_tags
|
||||
return Paragraph(item[2], col2_style)
|
||||
|
@ -418,12 +418,10 @@ def get_published_value(misp_event, item, col2_style):
|
|||
YES_ANSWER = "<font color=" + GREEN_COLOR + "><b> Yes </b></font> ("
|
||||
NO_ANSWER = "<font color=" + RED_COLOR + "><b>No</b></font>"
|
||||
|
||||
answer = ""
|
||||
|
||||
# Formatting similar to MISP Event web view
|
||||
if hasattr(misp_event, item[1]):
|
||||
if is_safe_attribute(misp_event, item[1]):
|
||||
if getattr(misp_event, item[1]): # == True
|
||||
if hasattr(misp_event, item[3]):
|
||||
if is_safe_attribute(misp_event, item[3]):
|
||||
# Published and have published date
|
||||
answer = Paragraph(YES_ANSWER + getattr(misp_event, item[3]).strftime(EXPORT_DATE_FORMAT) + ")",
|
||||
col2_style)
|
||||
|
@ -445,6 +443,9 @@ def is_safe_attribute(curr_object, attribute_name):
|
|||
return hasattr(curr_object, attribute_name) and getattr(curr_object, attribute_name) is not None and getattr(
|
||||
curr_object, attribute_name) != ""
|
||||
|
||||
def is_safe_attribute_table(curr_object, attribute_name):
|
||||
return hasattr(curr_object, attribute_name) and getattr(curr_object, attribute_name) is not None and getattr(
|
||||
curr_object, attribute_name) != []
|
||||
|
||||
def create_flowable_table_from_one_attribute(misp_attribute):
|
||||
'''
|
||||
|
@ -465,7 +466,7 @@ def create_flowable_table_from_one_attribute(misp_attribute):
|
|||
|
||||
# Handle the special case of links
|
||||
STANDARD_TYPE = True
|
||||
if hasattr(misp_attribute, 'type') and (getattr(misp_attribute, 'type') in [LINK_TYPE, URL_TYPE]):
|
||||
if is_safe_attribute(misp_attribute, 'type') and (getattr(misp_attribute, 'type') in [LINK_TYPE, URL_TYPE]):
|
||||
# getattr(misp_attribute, 'type') == LINK_TYPE or getattr(misp_attribute, 'type') == URL_TYPE):
|
||||
# Special case for links
|
||||
STANDARD_TYPE = False
|
||||
|
@ -492,12 +493,53 @@ def create_flowable_table_from_one_attribute(misp_attribute):
|
|||
|
||||
# Tags
|
||||
item = ["Tags", 'Tag', "None"]
|
||||
if hasattr(misp_attribute, item[1]):
|
||||
if is_safe_attribute_table(misp_attribute, item[1]):
|
||||
data.append([Paragraph(item[0], col1_style), get_tag_value(misp_attribute, item, col2_style)])
|
||||
|
||||
return create_flowable_table_from_data(data)
|
||||
|
||||
|
||||
def create_flowable_table_from_one_object(misp_object):
|
||||
'''
|
||||
Returns a table (flowable) representing the object
|
||||
:param misp_attribute: A misp object
|
||||
:return: a table representing this misp's object's attributes, to add to the pdf as a flowable
|
||||
'''
|
||||
data = []
|
||||
col1_style, col2_style = get_table_styles()
|
||||
|
||||
# To reduce code size, and automate it a bit, triplet (Displayed Name, object_attribute_name,
|
||||
# to_display_if_not_present) are store in the following list
|
||||
list_attr_automated = [["UUID", 'uuid', "None"],
|
||||
["Description", 'description', "None"],
|
||||
["Meta Category", 'meta-category', "None"],
|
||||
["Object Name", 'name', "None"],
|
||||
["Comment", 'comment', "None"],
|
||||
["Type", 'type', "None"],
|
||||
["Object Name", 'name', "None"]]
|
||||
|
||||
# Automated adding of standard (python) attributes of the misp object
|
||||
for item in list_attr_automated:
|
||||
if is_safe_attribute(misp_object, item[1]):
|
||||
# The attribute exists, we fetch it and create the row
|
||||
data.append([Paragraph(item[0], col1_style),
|
||||
get_unoverflowable_paragraph(getattr(misp_object, item[1]), col2_style)])
|
||||
|
||||
# The attribute does not exist, you may want to print a default text on the row. Then use as a else case :
|
||||
# data.append([Paragraph(item[0], col1_style), Paragraph(item[2], col2_style)])
|
||||
|
||||
data = [create_flowable_table_from_data(data)]
|
||||
|
||||
# Handle all the attributes
|
||||
if is_safe_attribute(misp_object, "Attribute"):
|
||||
data += create_flowable_table_from_attributes(misp_object)
|
||||
|
||||
# Add a page break at the end of an object
|
||||
data.append(PageBreak())
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def create_tags_table_from_data(data):
|
||||
'''
|
||||
Given a list of flowables tags (2D/list of list), creates a Table with styles adapted to tags.
|
||||
|
@ -589,7 +631,7 @@ def get_image_value(misp_attribute, item, col2_style):
|
|||
answer = img
|
||||
except OSError:
|
||||
logger.error(
|
||||
"Trying to add an attachment during PDF export generation. Attachement joining failed. Attachmement may not be an image.")
|
||||
"Trying to add an attachment during PDF export generation. Attachement joining failed. Attachement may not be an image.")
|
||||
answer = get_unoverflowable_paragraph(
|
||||
"<font color=" + BAD_LINK_COLOR + ">" + NOT_A_PICTURE_MESSAGE + "</font>", col2_style, False)
|
||||
|
||||
|
@ -771,16 +813,16 @@ def create_flowable_table_from_attributes(misp_event):
|
|||
sample_style_sheet = getSampleStyleSheet()
|
||||
i = 0
|
||||
|
||||
if hasattr(misp_event, "Attribute"):
|
||||
if is_safe_attribute_table(misp_event, "Attribute"):
|
||||
# There is some attributes for this object
|
||||
for item in getattr(misp_event, "Attribute"):
|
||||
# you can use a spacer instead of title to separate paragraph: flowable_table.append(Spacer(1, 5 * mm))
|
||||
flowable_table.append(Paragraph("Attribute #" + str(i), sample_style_sheet['Heading3']))
|
||||
flowable_table.append(Paragraph("Attribute #" + str(i), sample_style_sheet['Heading4']))
|
||||
flowable_table.append(create_flowable_table_from_one_attribute(item))
|
||||
i += 1
|
||||
else:
|
||||
# No attributes for this object
|
||||
flowable_table.append(Paragraph("No attributes", sample_style_sheet['Heading2']))
|
||||
flowable_table.append(Paragraph("No attributes", sample_style_sheet['Heading4']))
|
||||
|
||||
return flowable_table
|
||||
|
||||
|
@ -796,7 +838,7 @@ def create_flowable_table_from_tags(misp_event):
|
|||
col1_style, col2_style = get_table_styles()
|
||||
i = 0
|
||||
|
||||
if hasattr(misp_event, "Tag") and len(getattr(misp_event, "Tag")) > 1: # 'Tag' can exist and be empty
|
||||
if is_safe_attribute_table(misp_event, "Tag") : # and len(getattr(misp_event, "Tag")) > 1: # 'Tag' can exist and be empty
|
||||
# There is some tags for this object
|
||||
for item in getattr(misp_event, "Tag"):
|
||||
flowable_table.append(create_flowable_tag(item))
|
||||
|
@ -809,6 +851,34 @@ def create_flowable_table_from_tags(misp_event):
|
|||
return answer_tags
|
||||
|
||||
|
||||
def create_flowable_table_from_objects(misp_event):
|
||||
'''
|
||||
Returns a list of flowables representing the list of objects of a misp event.
|
||||
The list is composed of a serie of
|
||||
[ header object, table of object information, [ header of attribute, table of attribute]*] to add to the pdf
|
||||
:param misp_event: A misp event
|
||||
:return: a table of flowables
|
||||
'''
|
||||
|
||||
flowable_table = []
|
||||
sample_style_sheet = getSampleStyleSheet()
|
||||
i = 0
|
||||
|
||||
if is_safe_attribute_table(misp_event, "Object"):
|
||||
|
||||
# There is a list of objects
|
||||
for item in getattr(misp_event, "Object"):
|
||||
# you can use a spacer instead of title to separate paragraph: flowable_table.append(Spacer(1, 5 * mm))
|
||||
flowable_table.append(Paragraph("Object #" + str(i), sample_style_sheet['Heading3']))
|
||||
flowable_table += create_flowable_table_from_one_object(item)
|
||||
i += 1
|
||||
else:
|
||||
# No object found
|
||||
flowable_table.append(Paragraph("No object", sample_style_sheet['Heading3']))
|
||||
|
||||
return flowable_table
|
||||
|
||||
|
||||
########################################################################
|
||||
# Handling static parts drawn on the upper layer
|
||||
|
||||
|
@ -884,12 +954,20 @@ def collect_parts(misp_event, config=None):
|
|||
sample_style_sheet = getSampleStyleSheet()
|
||||
|
||||
# Create stuff
|
||||
title = get_value_link_to_event(misp_event, ["Info", 'info', "None"], sample_style_sheet['Heading1'], config, False)
|
||||
subtitle = Paragraph("General information", sample_style_sheet['Heading2'])
|
||||
attributes = Paragraph("Attributes", sample_style_sheet['Heading2'])
|
||||
title_style = ParagraphStyle(name='Column_1', parent=sample_style_sheet['Heading1'], alignment=TA_CENTER)
|
||||
title = get_value_link_to_event(misp_event, ["Info", 'info', "None"], title_style, config, False)
|
||||
|
||||
table_event_general = create_flowable_table_from_event(misp_event, config)
|
||||
table_event_attribute = create_flowable_table_from_attributes(misp_event)
|
||||
subtitle = Paragraph("General information", sample_style_sheet['Heading2'])
|
||||
table_general_metainformation = create_flowable_table_from_event(misp_event, config)
|
||||
|
||||
event_attributes_title = Paragraph("Attributes", sample_style_sheet['Heading2'])
|
||||
table_direct_attributes = create_flowable_table_from_attributes(misp_event)
|
||||
|
||||
event_objects_title = Paragraph("Objects", sample_style_sheet['Heading2'])
|
||||
table_objects = create_flowable_table_from_objects(misp_event)
|
||||
|
||||
event_sighting_title = Paragraph("Sighting", sample_style_sheet['Heading2'])
|
||||
# TODO : table_event_sightings = create_flowable_table_from_sightings(misp_event)
|
||||
|
||||
# If you want to output the full json (as debug), just add next line
|
||||
# paragraph_2 = Paragraph(str(misp_event.to_json()), sample_style_sheet['Code'])
|
||||
|
@ -897,12 +975,20 @@ def collect_parts(misp_event, config=None):
|
|||
# Add all parts to final PDF
|
||||
flowables.append(title)
|
||||
flowables.append(subtitle)
|
||||
flowables.append(table_event_general)
|
||||
flowables.append(table_general_metainformation)
|
||||
|
||||
flowables.append(PageBreak())
|
||||
|
||||
flowables.append(attributes)
|
||||
flowables += table_event_attribute
|
||||
flowables.append(event_attributes_title)
|
||||
flowables += table_direct_attributes
|
||||
|
||||
flowables.append(PageBreak())
|
||||
flowables.append(event_objects_title)
|
||||
flowables += table_objects
|
||||
|
||||
# TODO : flowables.append(PageBreak())
|
||||
# TODO : flowables.append(event_sighting_title)
|
||||
# TODO : flowables += table_event_sightings
|
||||
|
||||
return flowables
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -54,36 +54,36 @@ class TestMISPEvent(unittest.TestCase):
|
|||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + 'to_delete1.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent),
|
||||
self.storage_folder + "basic_event.pdf")
|
||||
self.storage_folder + "normal_event.pdf")
|
||||
|
||||
def test_HTML_json(self):
|
||||
if self.check_python_2():
|
||||
self.assertTrue(True)
|
||||
else:
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + '56e12e66-f01c-41be-afea-4d9a950d210f.json')
|
||||
self.mispevent.load_file(self.test_folder + 'HTML_event.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent),
|
||||
self.storage_folder + "HTML.pdf")
|
||||
self.storage_folder + "HTML_event.pdf")
|
||||
|
||||
def test_long_json(self):
|
||||
if self.check_python_2():
|
||||
self.assertTrue(True)
|
||||
else:
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + '57153590-f73c-49fa-be4b-4737950d210f.json')
|
||||
self.mispevent.load_file(self.test_folder + 'long_event.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent),
|
||||
self.storage_folder + "long.pdf")
|
||||
self.storage_folder + "long_event.pdf")
|
||||
# Issue report : "We are not smart enough" : https://pairlist2.pair.net/pipermail/reportlab-users/2010-May/009529.html
|
||||
# Not nice but working solution exposed ther e: https://pairlist2.pair.net/pipermail/reportlab-users/2016-March/011525.html
|
||||
# Not nice but working solution exposed there: https://pairlist2.pair.net/pipermail/reportlab-users/2016-March/011525.html
|
||||
|
||||
def test_very_long_json(self):
|
||||
if self.check_python_2():
|
||||
self.assertTrue(True)
|
||||
else:
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + '5abf6421-c1b8-477b-a9d2-9c0902de0b81.json')
|
||||
self.mispevent.load_file(self.test_folder + 'very_long_event.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent),
|
||||
self.storage_folder + "very_long.pdf")
|
||||
self.storage_folder + "very_long_event.pdf")
|
||||
|
||||
def test_full_config_json(self):
|
||||
if self.check_python_2():
|
||||
|
@ -96,9 +96,9 @@ class TestMISPEvent(unittest.TestCase):
|
|||
config[moduleconfig[1]] = "My Wonderful CERT"
|
||||
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + '5abf6421-c1b8-477b-a9d2-9c0902de0b81.json')
|
||||
self.mispevent.load_file(self.test_folder + 'very_long_event.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent, config),
|
||||
self.storage_folder + "config_complete.pdf")
|
||||
self.storage_folder + "config_complete_event.pdf")
|
||||
|
||||
def test_partial_0_config_json(self):
|
||||
if self.check_python_2():
|
||||
|
@ -110,9 +110,9 @@ class TestMISPEvent(unittest.TestCase):
|
|||
config[moduleconfig[0]] = "http://localhost:8080"
|
||||
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + '5abf6421-c1b8-477b-a9d2-9c0902de0b81.json')
|
||||
self.mispevent.load_file(self.test_folder + 'very_long_event.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent, config),
|
||||
self.storage_folder + "config_partial_0.pdf")
|
||||
self.storage_folder + "config_partial_0_event.pdf")
|
||||
|
||||
def test_partial_1_config_json(self):
|
||||
if self.check_python_2():
|
||||
|
@ -124,9 +124,9 @@ class TestMISPEvent(unittest.TestCase):
|
|||
config[moduleconfig[1]] = "My Wonderful CERT"
|
||||
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + '5abf6421-c1b8-477b-a9d2-9c0902de0b81.json')
|
||||
self.mispevent.load_file(self.test_folder + 'very_long_event.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent, config),
|
||||
self.storage_folder + "config_partial_1.pdf")
|
||||
self.storage_folder + "config_partial_1_event.pdf")
|
||||
|
||||
def test_image_json(self):
|
||||
if self.check_python_2():
|
||||
|
@ -143,6 +143,36 @@ class TestMISPEvent(unittest.TestCase):
|
|||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent, config),
|
||||
self.storage_folder + "image_event.pdf")
|
||||
|
||||
def test_objects_1_json(self):
|
||||
if self.check_python_2():
|
||||
self.assertTrue(True)
|
||||
else:
|
||||
|
||||
config = {}
|
||||
moduleconfig = ["MISP_base_url_for_dynamic_link", "MISP_name_for_metadata"]
|
||||
config[moduleconfig[0]] = "http://localhost:8080"
|
||||
config[moduleconfig[1]] = "My Wonderful CERT"
|
||||
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + 'mainly_objects_1.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent, config),
|
||||
self.storage_folder + "mainly_objects_1.pdf")
|
||||
|
||||
def test_objects_2_json(self):
|
||||
if self.check_python_2():
|
||||
self.assertTrue(True)
|
||||
else:
|
||||
|
||||
config = {}
|
||||
moduleconfig = ["MISP_base_url_for_dynamic_link", "MISP_name_for_metadata"]
|
||||
config[moduleconfig[0]] = "http://localhost:8080"
|
||||
config[moduleconfig[1]] = "My Wonderful CERT"
|
||||
|
||||
self.init_event()
|
||||
self.mispevent.load_file(self.test_folder + 'mainly_objects_2.json')
|
||||
reportlab_generator.register_value_to_file(reportlab_generator.convert_event_in_pdf_buffer(self.mispevent, config),
|
||||
self.storage_folder + "mainly_objects_2.pdf")
|
||||
|
||||
|
||||
def test_batch_image_events(self):
|
||||
# Test case ONLY for manual testing. Needs to download a full list of image events !
|
||||
|
@ -170,7 +200,7 @@ class TestMISPEvent(unittest.TestCase):
|
|||
reportlab_generator.convert_event_in_pdf_buffer(self.mispevent),
|
||||
self.storage_image_folder + curr_file + ".pdf")
|
||||
print("Elapsed time : " + str(time.time() - t))
|
||||
# Local run : 1958.930s for 1064 files
|
||||
# Local run : 73.061s for 102 files
|
||||
|
||||
def test_batch_OSINT_events(self):
|
||||
# Test case ONLY for manual testing. Needs to download a full list of OSINT events !
|
||||
|
|
Loading…
Reference in New Issue