add: [exportpdf] Handling pictures embedded as attributes

pull/352/head
Falconieri 2019-02-26 14:03:25 +01:00
parent cefcc3430c
commit 29a1b05c1f
2 changed files with 62 additions and 33 deletions

View File

@ -161,10 +161,16 @@ FRAME_MAX_HEIGHT = 500 # 650 # Ad hoc value for a A4 page
FRAME_MAX_WIDTH = 356
STR_TOO_LONG_WARNING = "<br/><b><font color=red>[Too long to fit on a single page. Cropped]</font></b>"
# == Parameters for error handling for image too big to fit on a page ==
FRAME_PICTURE_MAX_WIDTH = 88 * mm
FRAME_PICTURE_MAX_HEIGHT = 195 * mm
# == Parameters for links management ==
LINK_TYPE = "link" # Name of the type that define 'good' links
URL_TYPE = "url" # Name of the type that define 'bad' links
IMAGE_TYPE = "attachment" # /!\ Not only pictures ! Can be PDF, ...
WARNING_MESSAGE_URL = "'https://Please_consider_that_this_may_be_a_harmful_link'"
NOT_A_PICTURE_MESSAGE = "This attachment is not recognized as an image. Please access this attachment directly from your MISP instance."
GOOD_LINK_COLOR = 'blue'
BAD_LINK_COLOR = 'red'
@ -423,13 +429,14 @@ def get_published_value(misp_event, item, col2_style):
col2_style)
else:
# Published without published date
answer = YES_ANSWER + "no date)"
answer = Paragraph(YES_ANSWER + "no date)",col2_style)
else:
# Not published
answer = NO_ANSWER
answer = Paragraph(NO_ANSWER,col2_style)
else:
# Does not have a published attribute
answer = item[2]
answer = Paragraph(item[2],col2_style)
return answer
@ -456,11 +463,11 @@ def create_flowable_table_from_one_attribute(misp_attribute):
["Type", 'type', "None"],
["Value", 'value', "None"]]
IMAGE_TYPE = "attachment"
# Handle the special case of links
STANDARD_TYPE = True
if hasattr(misp_attribute, 'type') and (getattr(misp_attribute, 'type') in [LINK_TYPE, URL_TYPE, IMAGE_TYPE]):
if hasattr(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
@ -480,41 +487,32 @@ def create_flowable_table_from_one_attribute(misp_attribute):
item = ["Value", 'value', "None"]
if is_safe_attribute(misp_attribute, item[1]):
# Handle "Good" links
if getattr(misp_attribute, 'type') == LINK_TYPE:
data.append([Paragraph(item[0], col1_style), get_unoverflowable_paragraph(
"<font color=" + GOOD_LINK_COLOR + "><a href=" + getattr(misp_attribute, item[1]) + ">" + getattr(
misp_attribute, item[1]) + "</a></font>", col2_style, False)])
# Handle "bad "links
elif getattr(misp_attribute, 'type') == URL_TYPE:
data.append([Paragraph(item[0], col1_style), get_unoverflowable_paragraph(
"<font color=" + BAD_LINK_COLOR + "><a href=" + WARNING_MESSAGE_URL + ">" + getattr(misp_attribute,item[1]) + "</a></font>",col2_style, False)])
elif getattr(misp_attribute, 'type') == IMAGE_TYPE:
# Get the image
buf = getattr(misp_attribute, 'data')
# Scale down (or up ?) the image to fit the maximum frame size
img_size = ImageReader(buf).getSize()
w_scale = FRAME_MAX_WIDTH / img_size[0]
h_scale = FRAME_MAX_HEIGHT / img_size[1]
scale_down = min(w_scale,h_scale)
print(FRAME_MAX_HEIGHT,FRAME_MAX_WIDTH)
print(img_size)
print(w_scale)
print(h_scale)
print(scale_down)
print(img_size[0]*scale_down, img_size[1]*scale_down)
# img_width = 88 * mm # max image height
# print(img_size)
FRAME_PICTURE_MAX_WIDTH = 88*mm
FRAME_PICTURE_MAX_HEIGHT = 195*mm
# return Image(path, width=width, height=(width * aspect))
img = Image(buf,width=FRAME_PICTURE_MAX_WIDTH,height=FRAME_PICTURE_MAX_HEIGHT,kind='bound')
# width, height = img.getSize()
# aspect = height / float(width)
data.append([Paragraph('data', col1_style),img])
"<font color=" + BAD_LINK_COLOR + "><a href=" + WARNING_MESSAGE_URL + ">" + getattr(misp_attribute,
item[
1]) + "</a></font>",
col2_style, False)])
item = ["Data", 'data', "None"]
# Handle pictures
if is_safe_attribute(misp_attribute, item[1]) and getattr(misp_attribute, 'type') == IMAGE_TYPE:
try :
# Get the image
buf = getattr(misp_attribute, item[1])
# Create image within a bounded box (to allow pdf creation)
img = Image(buf, width=FRAME_PICTURE_MAX_WIDTH, height=FRAME_PICTURE_MAX_HEIGHT, kind='bound')
data.append([Paragraph(item[0], col1_style), img])
except OSError :
logger.error("Trying to add an attachment during PDF export generation. Attachement joining failed. Attachmement may not be an image.")
data.append([Paragraph(item[0], col1_style),get_unoverflowable_paragraph("<font color=" + BAD_LINK_COLOR + ">" + NOT_A_PICTURE_MESSAGE + "</font>", col2_style, False) ])
# Tags
item = ["Tags", 'Tag', "None"]

View File

@ -10,7 +10,7 @@ import sys
import os
import time
manual_testing = True
manual_testing = False
class TestMISPEvent(unittest.TestCase):
@ -23,7 +23,9 @@ class TestMISPEvent(unittest.TestCase):
self.root = ""
self.test_folder = self.root + "reportlab_testfiles/"
self.test_batch_folder = self.root + "OSINT_output/"
self.test_image_folder = self.root + "image_json/"
self.storage_folder = self.root + "reportlab_testoutputs/"
self.storage_image_folder = self.root + "reportlab_test_image_outputs/"
def init_event(self):
self.mispevent.info = 'This is a test'
@ -141,6 +143,35 @@ 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_batch_image_events(self):
# Test case ONLY for manual testing. Needs to download a full list of image events !
if self.check_python_2():
self.assertTrue(True)
elif not manual_testing :
self.assertTrue(True)
else:
self.init_event()
file_nb = str(len(os.listdir(self.test_image_folder)))
i = 0
t = time.time()
for curr_file in os.listdir(self.test_image_folder):
self.mispevent = MISPEvent()
file_path = self.test_image_folder + curr_file
print("Current file : " + file_path + " " + str(i) + " over " + file_nb)
i += 1
self.mispevent.load_file(file_path)
reportlab_generator.register_value_to_file(
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
def test_batch_OSINT_events(self):
# Test case ONLY for manual testing. Needs to download a full list of OSINT events !