import codecs import os import king_phisher.client.gui_utilities as gui_utilities import king_phisher.client.mailer as mailer import king_phisher.client.plugins as plugins import king_phisher.client.widget.extras as extras import jinja2.exceptions try: from weasyprint import HTML except (ImportError, FileNotFoundError): has_weasyprint = False else: has_weasyprint = True class Plugin(getattr(plugins, 'ClientPluginMailerAttachment', plugins.ClientPlugin)): authors = ['Jeremy Schoeneman', 'Erik Daguerre'] classifiers = ['Plugin :: Client :: Email :: Attachment'] title = 'Generate PDF' description = """ Generates a PDF file from an html attachment that process client King Phisher Jinja variables allowing to embed links to your landing page so users that click the link in the PDF can be tracked when they visit. """ homepage = 'https://github.com/securestate/king-phisher-plugins' options = [ plugins.ClientOptionPath( 'css_stylesheet', 'CSS stylesheet to use for HTML to PDF', display_name='CSS stylesheet', path_type='file-open' ) ] req_min_version = '1.8.0' req_packages = { 'weasyprint==47': has_weasyprint } req_platforms = ('Linux',) version = '2.0' def initialize(self): self.add_menu_item('Tools > Create PDF Preview', self.make_preview) return True def make_preview(self, _): mailer_tab = self.application.main_tabs['mailer'] config_tab = mailer_tab.tabs['config'] config_tab.objects_save_to_config() input_path = self.application.config['mailer.attachment_file'] if not (os.path.isfile(input_path) and os.access(input_path, os.R_OK)): gui_utilities.show_dialog_error( 'PDF Build Error', self.application.get_active_window(), 'Attachment path is invalid or is not readable.' ) return dialog = extras.FileChooserDialog('Save Generated PDF File', self.application.get_active_window()) response = dialog.run_quick_save('PDF Preview.pdf') dialog.destroy() if response is None: return output_path = response['target_path'] if not self.process_attachment_file(input_path, output_path): return gui_utilities.show_dialog_info( 'PDF Created', self.application.get_active_window(), 'Successfully created the PDF file.' ) def process_attachment_file(self, input_path, output_path, target=None): output_path, _ = os.path.splitext(output_path) output_path += '.pdf' try: with codecs.open(input_path, 'r', encoding='utf-8') as file_: msg_template = file_.read() except UnicodeDecodeError as error: gui_utilities.show_dialog_error( 'PDF Build Error', self.application.get_active_window(), "HTML template not in UTF-8 format.\n\n{error}".format(error=error) ) return try: formatted_message = mailer.render_message_template(msg_template, self.application.config, target) except jinja2.exceptions.TemplateSyntaxError as error: gui_utilities.show_dialog_error( 'PDF Build Error', self.application.get_active_window(), "Template syntax error: {error.message} on line {error.lineno}.".format(error=error) ) return except jinja2.exceptions.UndefinedError as error: gui_utilities.show_dialog_error( 'PDF Build Error', self.application.get_active_window(), "Template undefined error: {error.message}.".format(error=error) ) return except TypeError as error: gui_utilities.show_dialog_error( 'PDF Build Error', self.application.get_active_window(), "Template type error: {0}.".format(error.args[0]) ) return css_style = self.config.get('css_stylesheet') if css_style: css_style = css_style.strip() if not (os.path.isfile(css_style) and os.access(css_style, os.R_OK)): self.logger.warning('invalid css file path: ' + css_style) css_style = None weasyprint_html = HTML(string=formatted_message, base_url=os.path.dirname(input_path)) weasyprint_html.write_pdf( output_path, stylesheets=[css_style] if css_style else None, presentational_hints=True ) return output_path