def __init__(self, config, HandlerClass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages HandlerClass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(HandlerClass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database( config.get('server.database')) self.http_server.config = config self.http_server.throttle_semaphore = threading.Semaphore() self.http_server.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists('server.authentication.cache_timeout', '30m')) self.http_server.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists( 'server.authentication.cache_timeout', '10m'), required_group=config.get_if_exists('server.authentication.group'), pam_service=config.get_if_exists( 'server.authentication.pam_service', 'sshd')) self.job_manager = job.JobManager() """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() self.http_server.job_manager = self.job_manager loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars['embed_youtube_video'] = pages.embed_youtube_video global_vars['make_csrf_page'] = pages.make_csrf_page global_vars['make_redirect_page'] = pages.make_redirect_page self.http_server.template_env = templates.TemplateEnvironmentBase( loader=loader, global_vars=global_vars) self.__geoip_db = geoip.init_database( config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear()
def initialize(self): signals.campaign_alert.connect(self.on_campaign_alert) signals.campaign_alert_expired.connect(self.on_campaign_alert_expired) template_path = self.config['email_jinja_template'] if not template_path: template_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'template.html') if not os.path.isfile(template_path): self.logger.warning('invalid email template: ' + template_path) return False with open(template_path, 'r') as file_: template_data = file_.read() self.render_template = templates.TemplateEnvironmentBase().from_string( template_data) return True
def __init__(self, config, plugin_manager, handler_klass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages handler_klass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(handler_klass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.headers = collections.OrderedDict() """A :py:class:`~collections.OrderedDict` containing additional headers specified from the server configuration to include in responses.""" self.plugin_manager = plugin_manager self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database(config.get('server.database'), extra_init=True) self.throttle_semaphore = threading.BoundedSemaphore() self.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists('server.authentication.session_timeout', '30m') ) self.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists('server.authentication.cache_timeout', '10m'), required_group=config.get_if_exists('server.authentication.group'), pam_service=config.get_if_exists('server.authentication.pam_service', 'sshd') ) self.job_manager = smoke_zephyr.job.JobManager(logger_name='KingPhisher.Server.JobManager') """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() maintenance_interval = 900 # 15 minutes self._maintenance_job = self.job_manager.job_add(self._maintenance, parameters=(maintenance_interval,), seconds=maintenance_interval) loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars.update(template_extras.functions) self.template_env = templates.TemplateEnvironmentBase(loader=loader, global_vars=global_vars) self.ws_manager = web_sockets.WebSocketsManager(config, self.job_manager) self.tables_api = {} self._init_tables_api() for http_server in self.sub_servers: http_server.add_sni_cert = self.add_sni_cert http_server.config = config http_server.forked_authenticator = self.forked_authenticator http_server.get_sni_certs = lambda: self.sni_certs http_server.headers = self.headers http_server.job_manager = self.job_manager http_server.kp_shutdown = self.shutdown http_server.plugin_manager = plugin_manager http_server.remove_sni_cert = self.remove_sni_cert http_server.session_manager = self.session_manager http_server.tables_api = self.tables_api http_server.template_env = self.template_env http_server.throttle_semaphore = self.throttle_semaphore http_server.ws_manager = self.ws_manager if not config.has_option('server.secret_id'): test_id = rest_api.generate_token() config.set('server.secret_id', test_id) self.logger.debug('server request test id initialized with value: ' + test_id) if not config.get_if_exists('server.rest_api.token'): config.set('server.rest_api.token', rest_api.generate_token()) if config.get('server.rest_api.enabled'): self.logger.info('rest api token initialized with value: ' + config.get('server.rest_api.token')) self.__geoip_db = geoip.init_database(config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear() self.__shutdown_lock = threading.Lock() plugin_manager.server = weakref.proxy(self) headers = self.config.get_if_exists('server.headers', []) for header in headers: if ': ' not in header: self.logger.warning("header '{0}' is invalid and will not be included".format(header)) continue header, value = header.split(': ', 1) header = header.strip() self.headers[header] = value self.logger.info("including {0} custom http headers".format(len(self.headers)))
class WebKitHTMLView(_WebKitX_WebView): """ A WebView widget with additional convenience methods for rendering simple HTML content from either files or strings. If a link is opened within the document, the webview will emit the 'open-uri' signal instead of navigating to it. """ __gsignals__ = { 'open-remote-uri': (GObject.SIGNAL_RUN_FIRST, None, (str, (WebKitX.NavigationPolicyDecision if has_webkit2 else WebKitX.WebPolicyDecision))) } template_env = templates.TemplateEnvironmentBase( loader=templates.FindFileSystemLoader()) """ The :py:class:`~king_phisher.templates.TemplateEnvironmentBase` instance to use when rendering template content. The environment uses the :py:class:`~king_phisher.templates.FindFileSystemLoader` loader. """ def __init__(self): super(WebKitHTMLView, self).__init__() self.logger = logging.getLogger('KingPhisher.Client.' + self.__class__.__name__) if has_webkit2: self.get_context().set_cache_model( WebKitX.CacheModel.DOCUMENT_VIEWER) self.connect('decide-policy', self.signal_decide_policy) else: self.connect('navigation-policy-decision-requested', self.signal_decide_policy_webkit) self.connect('button-press-event', self.signal_button_pressed) def do_open_remote_uri(self, uri, decision): self.logger.debug('received request to open uri: ' + uri) def load_html_data(self, html_data, html_file_uri=None): """ Load arbitrary HTML data into the WebKit engine to be rendered. :param str html_data: The HTML data to load into WebKit. :param str html_file_uri: The URI of the file where the HTML data came from. """ if isinstance(html_file_uri, str) and not html_file_uri.startswith('file://'): html_file_uri = 'file://' + html_file_uri if has_webkit2: self.load_html(html_data, html_file_uri) else: if html_file_uri is None: html_file_uri = 'file://' + os.getcwd() self.load_string(html_data, 'text/html', 'UTF-8', html_file_uri) def load_html_file(self, html_file): """ Load arbitrary HTML data from a file into the WebKit engine to be rendered. :param str html_file: The path to the file to load HTML data from. """ with codecs.open(html_file, 'r', encoding='utf-8') as file_h: html_data = file_h.read() self.load_html_data(html_data, html_file) def load_markdown_data(self, md_data, html_file_uri=None, gh_flavor=True, template=None, template_vars=None): """ Load markdown data, render it into HTML and then load it in to the WebKit engine. When *gh_flavor* is enabled, the markdown data is rendered using partial GitHub flavor support as provided by :py:class:`~mdx_partial_gfm.PartialGithubFlavoredMarkdownExtension`. If *template* is specified, it is used to load a Jinja2 template using :py:attr:`.template_env` into which the markdown data is passed in the variable ``markdown`` along with any others specified in the *template_vars* dictionary. :param str md_data: The markdown data to render into HTML for displaying. :param str html_file_uri: The URI of the file where the HTML data came from. :param bool gh_flavor: Whether or not to enable partial GitHub markdown syntax support. :param str template: The name of a Jinja2 HTML template to load for hosting the rendered markdown. :param template_vars: Additional variables to pass to the Jinja2 :py:class:`~jinja2.Template` when rendering it. :return: """ extensions = [] if gh_flavor: extensions = [ mdx_partial_gfm.PartialGithubFlavoredMarkdownExtension() ] md_data = markdown.markdown(md_data, extensions=extensions) if template: template = self.template_env.get_template(template) template_vars = template_vars or {} template_vars['markdown'] = jinja2.Markup(md_data) html = template.render(template_vars) else: html = md_data return self.load_html_data(html, html_file_uri=html_file_uri) def load_markdown_file(self, md_file, **kwargs): """ Load markdown data from a file and render it using :py:meth:`~.load_markdown_data`. :param str md_file: The path to the file to load markdown data from. :param kwargs: Additional keyword arguments to pass to :py:meth:`~.load_markdown_data`. """ with codecs.open(md_file, 'r', encoding='utf-8') as file_h: md_data = file_h.read() return self.load_markdown_data(md_data, md_file, **kwargs) def signal_button_pressed(self, _, event): if event.button == Gdk.BUTTON_SECONDARY: # disable right click altogether return True # webkit2 signal handler def signal_decide_policy(self, _, decision, decision_type): if decision_type == WebKitX.PolicyDecisionType.NAVIGATION_ACTION: uri_request = decision.get_request() uri = uri_request.get_uri() if uri.startswith('file:'): decision.use() else: decision.ignore() self.emit('open-remote-uri', uri, decision) # webkit signal handler def signal_decide_policy_webkit(self, view, frame, request, action, policy): uri = request.get_uri() if uri.startswith('file://'): policy.use() else: policy.ignore() self.emit('open-remote-uri', uri, policy)