import weasyprint import os import json import hashlib from weasyprint import HTML from pathlib import Path from datetime import datetime class Report(object): def __init__(self, capture_directory): self.capture_directory = capture_directory self.alerts = self.read_json(os.path.join( capture_directory, "assets/alerts.json")) self.whitelist = self.read_json(os.path.join( capture_directory, "assets/whitelist.json")) self.conns = self.read_json(os.path.join( capture_directory, "assets/conns.json")) self.device = self.read_json(os.path.join( capture_directory, "assets/device.json")) self.capinfos = self.read_json(os.path.join( capture_directory, "assets/capinfos.json")) try: with open(os.path.join(self.capture_directory, "capture.pcap"), "rb") as f: self.capture_sha1 = hashlib.sha1(f.read()).hexdigest() except: self.capture_sha1 = "N/A" def read_json(self, json_path): """ Read and convert a JSON file. :return: array or dict. """ with open(json_path, "r") as json_file: return json.load(json_file) def generate_report(self): """ Generate the full report in PDF :return: nothing """ content = self.generate_page_header() content += self.generate_header() content += self.generate_warning() content += self.generate_alerts() content += self.generate_suspect_conns_block() content += self.generate_uncat_conns_block() content += self.generate_whitelist_block() htmldoc = HTML(string=content, base_url="").write_pdf() Path(os.path.join(self.capture_directory, "report.pdf")).write_bytes(htmldoc) def generate_warning(self): """ Generate the warning message. :return: str """ if len(self.alerts["high"]): return "
Your device seems to be compromised as you have {} high alert(s).
".format(self.nb_translate(len(self.alerts["high"]))) elif len(self.alerts["moderate"]): return "
You have {} moderate alert(s), your device might be compromised. Please look at them carefully.
".format(self.nb_translate(len(self.alerts["moderate"]))) elif len(self.alerts["low"]): return "
You have only {} low alert(s), don't hesitate to check them.
".format(self.nb_translate(len(self.alerts["low"]))) else: return "
Everything looks fine, zero alerts. Don't hesitate to check the uncategorized communications, if any.
" def nb_translate(self, nb): """ Translate a number in a string. :return: str """ a = ["one", "two", "three", "four", "five", "six", "seven", "height", "nine"] return a[nb-1] if nb <= 9 else str(nb) def generate_suspect_conns_block(self): """ Generate the table of the network non-whitelisted communications. :return: string """ if not len([c for c in self.conns if c["alert_tiggered"] == True]): return "" title = "

Suspect communications

" table = """""" for rec in self.conns: if rec["alert_tiggered"] == True: table += "" table += "".format(rec["proto"].upper()) table += "".format(rec["resolution"] if rec["resolution"] != rec["ip_dst"] else "--") table += "".format(rec["ip_dst"]) table += "".format(rec["port_dst"]) table += "" table += "
Protocol Domain Dst IP Address Dst port
{}{}{}{}
" return title + table def generate_uncat_conns_block(self): """ Generate the table of the network non-whitelisted communications. :return: string """ if not len([c for c in self.conns if c["alert_tiggered"] == False]): return "" title = "

Uncategorized communications

" table = """""" for rec in self.conns: if rec["alert_tiggered"] == False: table += "" table += "".format(rec["proto"].upper()) table += "".format(rec["resolution"] if rec["resolution"] != rec["ip_dst"] else "--") table += "".format(rec["ip_dst"]) table += "".format(rec["port_dst"]) table += "" table += "
Protocol Domain Dst IP Address Dst port
{}{}{}{}
" return title + table def generate_whitelist_block(self): """ Generate the table of the whitelisted communications. :return: string """ if not len(self.whitelist): return "" title = "

Whitelisted communications

" table = """""" for rec in sorted(self.whitelist, key=lambda k: k['resolution']): table += "" table += "".format(rec["proto"].upper()) table += "".format(rec["resolution"] if rec["resolution"] != rec["ip_dst"] else "--") table += "".format(rec["ip_dst"]) table += "".format(rec["port_dst"]) table += "" table += "
Protocol Domain Dst IP Address Dst port
{}{}{}{}
" return title + table def generate_header(self): """ Generate the report header with context data. :return: string """ header = "
" header += "
" header += "


Device name: {}
".format( self.device["name"]) header += "Device MAC address: {}
".format( self.device["mac_address"]) header += "Report generated on {}
".format( datetime.now().strftime("%d/%m/%Y at %H:%M:%S")) header += "Capture duration: {}s
".format( self.capinfos["Capture duration"]) header += "Number of packets: {}
".format( self.capinfos["Number of packets"]) header += "Capture SHA1: {}
".format(self.capture_sha1) header += "

" header += "
" return header def generate_alerts(self): """ Generate the alerts. :return: string """ alerts = "" return alerts def generate_page_footer(self): """ Generate the html footer. :return: string """ return "" def generate_page_header(self): """ Generate the html header. :return: string """ return """ """.replace("REPORT_HEADER", "Report for the capture {}".format(self.capture_sha1))