diff --git a/pymisp/tools/reportlab_generator.py b/pymisp/tools/reportlab_generator.py
index b1d4e06..62747c5 100644
--- a/pymisp/tools/reportlab_generator.py
+++ b/pymisp/tools/reportlab_generator.py
@@ -161,10 +161,16 @@ FRAME_MAX_HEIGHT = 500 # 650 # Ad hoc value for a A4 page
FRAME_MAX_WIDTH = 356
STR_TOO_LONG_WARNING = "
[Too long to fit on a single page. Cropped]"
+# == 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(
"" + getattr(
misp_attribute, item[1]) + "", col2_style, False)])
+ # Handle "bad "links
elif getattr(misp_attribute, 'type') == URL_TYPE:
data.append([Paragraph(item[0], col1_style), get_unoverflowable_paragraph(
- "" + getattr(misp_attribute,item[1]) + "",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])
+ "" + getattr(misp_attribute,
+ item[
+ 1]) + "",
+ 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("" + NOT_A_PICTURE_MESSAGE + "", col2_style, False) ])
# Tags
item = ["Tags", 'Tag', "None"]
diff --git a/tests/test_reportlab.py b/tests/test_reportlab.py
index b2b968f..f93e1e7 100644
--- a/tests/test_reportlab.py
+++ b/tests/test_reportlab.py
@@ -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 !