def _add_collection_data(self, collection_type, collection_items): if collection_type not in COLLECTION_TYPES: self.logger.warning('unknown repository collection type: ' + collection_type) return if not isinstance(collection_items, list): self.logger.warning('invalid repository collection information for type: ' + collection_type) return if not collection_items: return collection = self.collections.get(collection_type) if collection is None: collection = utilities.FreezableDict() # validate each of the items so we know that the basic keys we expect # to be present are set to with the correct value types for item in collection_items: if not isinstance(item, dict): raise TypeError('collection item is not a dict') for key in ('authors', 'files'): if isinstance(item.get(key), list) and item[key]: continue raise KeyError('collection item is missing non-empty list key: ' + key) for key in ('description', 'name', 'title', 'version'): if isinstance(item.get(key), str) and item[key]: continue raise KeyError('collection item is missing non-empty string key: ' + key) if not all(isinstance(value, str) for value in item['authors']): raise TypeError('collection item has non-string item in list: authors') item['authors'] = tuple(item['authors']) if not all(isinstance(value, dict) for value in item['files']): raise TypeError('collection item has non-dict item in list: files') item_files = [] for item_file in item['files']: if not (isinstance(item_file.get('path-destination'), str) and item_file['path-destination']): raise KeyError('collection item file is missing non-empty string key: path-destination') if not (isinstance(item_file.get('path-source'), str) and item_file['path-source']): raise KeyError('collection item file is missing non-empty string key: path-source') if not isinstance(item_file.get('signed-by'), (str, type(None))): raise TypeError('collection item file has invalid item: signed-by') if not isinstance(item_file.get('signature'), (str, type(None))): raise TypeError('collection item file has invalid item: signed-by') # normalize empty strings to None for signed-by and signature if not item_file.get('signature'): item_file['signature'] = None if not item_file.get('signed-by'): item_file['signed-by'] = None # make sure both keys are present or neither are present if bool(item_file['signature']) ^ bool(item_file['signed-by']): raise ValueError('collection item file must either have both signature and signed-by keys or neither') item_file['path_destination'] = item_file.pop('path-destination') item_file['path_source'] = item_file.pop('path-source') item_file['signed_by'] = item_file.pop('signed-by') item_files.append(CollectionItemFile(**item_file)) item['files'] = tuple(item_files) item = utilities.FreezableDict(sorted(item.items(), key=lambda i: i[0])) item.freeze() collection[item['name']] = item self.collections[collection_type] = collection
def _add_collection_data(self, collection_type, collection_items): if collection_type not in COLLECTION_TYPES: self.logger.warning('unknown repository collection type: ' + collection_type) return collection = self.collections.get(collection_type) if collection is None: collection = utilities.FreezableDict() # validate each of the items so we know that the basic keys we expect # to be present are set to with the correct value types for item in collection_items: item['authors'] = tuple(item['authors']) item_files = [] for item_file in item['files']: # normalize empty strings to None for signed-by and signature if not item_file.get('signature'): item_file['signature'] = None if not item_file.get('signed-by'): item_file['signed-by'] = None item_files.append(CollectionItemFile.from_dict(item_file)) item['files'] = tuple(item_files) item = utilities.FreezableDict( sorted(item.items(), key=lambda i: i[0])) item.freeze() collection[item['name']] = item self.collections[collection_type] = collection
def _add_collection_data(self, collection_type, collection_items): if collection_type not in COLLECTION_TYPES: self.logger.warning('unknown repository collection type: ' + collection_type) return collection = self.collections.get(collection_type) if collection is None: collection = utilities.FreezableDict() # validate each of the items so we know that the basic keys we expect # to be present are set to with the correct value types for item in collection_items: item['authors'] = tuple(item['authors']) item_files = [] for item_file in item['files']: # normalize empty strings to None for signed-by and signature if not item_file.get('signature'): item_file['signature'] = None if not item_file.get('signed-by'): item_file['signed-by'] = None # make sure both keys are present or neither are present if bool(item_file['signature']) ^ bool(item_file['signed-by']): raise ValueError( 'collection item file must either have both signature and signed-by keys or neither' ) item_file['path_destination'] = item_file.pop( 'path-destination') item_file['path_source'] = item_file.pop('path-source') item_file['signed_by'] = item_file.pop('signed-by') item_files.append(CollectionItemFile(**item_file)) item['files'] = tuple(item_files) item = utilities.FreezableDict( sorted(item.items(), key=lambda i: i[0])) item.freeze() collection[item['name']] = item self.collections[collection_type] = collection
def __init__(self, parent, application): """ :param parent: The parent window for this object. :type parent: :py:class:`Gtk.Window` :param application: The main client application instance. :type application: :py:class:`Gtk.Application` """ self.parent = parent self.application = application self.config = application.config self.logger = logging.getLogger('KingPhisher.Client.' + self.__class__.__name__) self.box = Gtk.Box() self.box.set_property('orientation', Gtk.Orientation.VERTICAL) self.box.show() self.label = Gtk.Label(label='View Campaign') """The :py:class:`Gtk.Label` representing this tabs name.""" self.notebook = Gtk.Notebook() """ The :py:class:`Gtk.Notebook` for holding sub-tabs.""" self.notebook.connect('switch-page', self.signal_notebook_switch_page) self.notebook.set_scrollable(True) self.box.pack_start(self.notebook, True, True, 0) self.tabs = utilities.FreezableDict() """A dict object holding the sub tabs managed by this object.""" current_page = self.notebook.get_current_page() self.last_page_id = current_page if graphs.has_matplotlib: self.logger.info('matplotlib is installed, dashboard will be available') dashboard_tab = CampaignViewDashboardTab(application) self.tabs['dashboard'] = dashboard_tab self.notebook.append_page(dashboard_tab.box, dashboard_tab.label) else: self.logger.warning('matplotlib is not installed, dashboard will not be available') messages_tab = CampaignViewMessagesTab(application) self.tabs['messages'] = messages_tab self.notebook.append_page(messages_tab.box, messages_tab.label) visits_tab = CampaignViewVisitsTab(application) self.tabs['visits'] = visits_tab self.notebook.append_page(visits_tab.box, visits_tab.label) credentials_tab = CampaignViewCredentialsTab(application) self.tabs['credentials'] = credentials_tab self.notebook.append_page(credentials_tab.box, credentials_tab.label) if self.config.get('gui.show_deaddrop', False): deaddrop_connections_tab = CampaignViewDeaddropTab(application) self.tabs['deaddrop_connections'] = deaddrop_connections_tab self.notebook.append_page(deaddrop_connections_tab.box, deaddrop_connections_tab.label) self.tabs.freeze() for tab in self.tabs.values(): tab.box.show() self.notebook.show() self.application.connect('campaign-set', self.signal_kpc_campaign_set)
def __init__(self, data, keys=None): """ :param dict data: The formatted repository data. :param keys: The keys to use for verifying remote data. :type keys: :py:class:`~king_phisher.security_keys.SecurityKeys` """ self.security_keys = keys or security_keys.SecurityKeys() """The :py:class:`~king_phisher.security_keys.SecurityKeys` used for verifying remote data.""" created = data.get('created') if isinstance(created, str): self.created = dateutil.parser.parse(created) else: self.created = None self._req_sess = requests.Session() self._req_sess.mount('file://', requests_file.FileAdapter()) self.description = data.get('description') self.homepage = data.get('homepage') """The URL of the homepage for this repository if it was specified.""" for key in ('title', 'url-base'): if isinstance(data.get(key), str) and data[key]: continue raise KeyError('repository data is missing non-empty string key: ' + key) self.title = data['title'] """The title string of this repository.""" self.url_base = data['url-base'] """The base URL string of files included in this repository.""" self.collections = utilities.FreezableDict() """The dictionary of the different collection types included in this repository.""" if 'collections-include' in data: # include-files is reversed so the dictionary can get .update()'ed and the first seen will be the value kept for include in reversed(data['collections-include']): include_data = self._fetch_json(include) if 'collections' not in include_data: self.logger.warning("included file {0} missing 'collections' entry".format(include['path'])) continue include_data = include_data['collections'] for collection_type in include.get('types', COLLECTION_TYPES): if collection_type not in include_data: continue collection = include_data.get(collection_type) if collection is None: continue self._add_collection_data(collection_type, collection) if 'collections' in data: for collection_type in COLLECTION_TYPES: collection = data['collections'].get(collection_type) if collection is None: continue self._add_collection_data(collection_type, collection) item_count = sum(len(collection) for collection in self.collections.values()) self.logger.debug("initialized catalog repository with {0} collection types and {1} total items".format(len(self.collections), item_count)) for collection_type, collection in self.collections.items(): collection.freeze() self.collections[collection_type] = Collection(self, collection_type, collection) self.collections.freeze()
def __init__(self, parent, application): """ :param parent: The parent window for this object. :type parent: :py:class:`Gtk.Window` :param application: The main client application instance. :type application: :py:class:`Gtk.Application` """ super(MailSenderTab, self).__init__() self.parent = parent self.application = application self.config = application.config self.box = Gtk.Box() self.box.set_property('orientation', Gtk.Orientation.VERTICAL) self.box.show() self.label = Gtk.Label(label='Send Messages') """The :py:class:`Gtk.Label` representing this tabs name.""" self.notebook = Gtk.Notebook() """ The :py:class:`Gtk.Notebook` for holding sub-tabs.""" self.notebook.connect('switch-page', self.signal_notebook_switch_page) self.notebook.set_scrollable(True) self.box.pack_start(self.notebook, True, True, 0) self.status_bar = Gtk.Statusbar() self.status_bar.show() self.box.pack_end(self.status_bar, False, False, 0) self.tabs = utilities.FreezableDict() """A dict object holding the sub tabs managed by this object.""" current_page = self.notebook.get_current_page() self.last_page_id = current_page config_tab = MailSenderConfigurationTab(self.application) self.tabs['config'] = config_tab self.notebook.append_page(config_tab.box, config_tab.label) edit_tab = MailSenderEditTab(self.application) self.tabs['edit'] = edit_tab self.notebook.append_page(edit_tab.box, edit_tab.label) preview_tab = MailSenderPreviewTab(self.application) self.tabs['preview'] = preview_tab self.notebook.append_page(preview_tab.box, preview_tab.label) send_messages_tab = MailSenderSendTab(self.application) self.tabs['send_messages'] = send_messages_tab self.notebook.append_page(send_messages_tab.box, send_messages_tab.label) self.tabs.freeze() for tab in self.tabs.values(): tab.box.show() self.notebook.show() self.application.connect('campaign-set', self.signal_kp_campaign_set)
def __init__(self): self.keys = utilities.FreezableDict() """The dictionary of the loaded security keys, keyed by their identity string.""" if not self._load_key_store('security.json'): raise RuntimeError( 'failed to load any keys from the primary store') self._load_key_store('security.local.json') self.keys.freeze() self.logger.info( "security key store initialized with {0:,} keys".format( len(self.keys)))
def __init__(self, data, keys=None): """ :param dict data: The formatted repository data. :param keys: The keys to use for verifying remote data. :type keys: :py:class:`~king_phisher.security_keys.SecurityKeys` """ self.security_keys = keys or security_keys.SecurityKeys() """The :py:class:`~king_phisher.security_keys.SecurityKeys` used for verifying remote data.""" self._req_sess = requests.Session() self._req_sess.mount('file://', requests_file.FileAdapter()) self.description = data.get('description') self.homepage = data.get('homepage') """The URL of the homepage for this repository if it was specified.""" self.id = data['id'] """The unique identifier of this repository.""" self.title = data['title'] """The title string of this repository.""" self.url_base = data['url-base'] """The base URL string of files included in this repository.""" self.collections = utilities.FreezableDict() """The dictionary of the different collection types included in this repository.""" if 'collections-include' in data: # include-files is reversed so the dictionary can get .update()'ed and the first seen will be the value kept for include in reversed(data['collections-include']): include_data = self._fetch_json(include) utilities.validate_json_schema( include_data, 'king-phisher.catalog.collections') include_data = include_data['collections'] for collection_type in include.get('types', COLLECTION_TYPES): collection = include_data.get(collection_type) if collection is None: continue self._add_collection_data(collection_type, collection) if 'collections' in data: for collection_type in COLLECTION_TYPES: collection = data['collections'].get(collection_type) if collection is None: continue self._add_collection_data(collection_type, collection) item_count = sum( len(collection) for collection in self.collections.values()) self.logger.debug( "initialized catalog repository with {0} collection types and {1} total items" .format(len(self.collections), item_count)) for collection_type, collection in self.collections.items(): collection.freeze() self.collections[collection_type] = Collection( self, collection_type, collection) self.collections.freeze()
def from_dict(cls, value, repo): """ Load the collection item file from the specified dict object. :param dict value: The dictionary to load the data from. :return: """ items = utilities.FreezableDict() for item in value['items']: item['files'] = tuple( CollectionItemFile.from_dict(file) for file in item['files']) items[item['title']] = item items.freeze() return cls(repo, value['type'], items)
def __init__(self, application): """ :param application: The parent application for this object. :type application: :py:class:`Gtk.Application` """ assert isinstance(application, Gtk.Application) self.config = application.config """A reference to the King Phisher client configuration.""" self.application = application """The parent :py:class:`Gtk.Application` instance.""" self.logger = logging.getLogger('KingPhisher.Client.' + self.__class__.__name__) builder = Gtk.Builder() self.gtk_builder = builder """A :py:class:`Gtk.Builder` instance used to load Glade data with.""" top_level_dependencies = [self.dependencies.name] if self.dependencies.top_level is not None: top_level_dependencies.extend(self.dependencies.top_level) builder.add_objects_from_file(which_glade(), top_level_dependencies) builder.connect_signals(self) gobject = builder.get_object(self.dependencies.name) if isinstance(gobject, Gtk.Window): gobject.set_transient_for(self.application.get_active_window()) if isinstance(gobject, Gtk.ApplicationWindow): application.add_window(gobject) if isinstance(gobject, Gtk.Dialog): gobject.set_modal(True) setattr(self, self.top_gobject, gobject) self.gobjects = utilities.FreezableDict() """A :py:class:`~king_phisher.utilities.FreezableDict` which maps gobjects to their unique GTK Builder id.""" for gobject_id in self.dependencies.children or []: gobject = self.gtk_builder_get(gobject_id) # the following five lines ensure that the types match up, this is to enforce clean development gtype = gobject_id.split('_', 1)[0] if gobject is None: raise TypeError( "gobject {0} could not be found in the glade file".format( gobject_id)) elif gobject.__class__.__name__.lower() != gtype: raise TypeError( "gobject {0} is of type {1} expected {2}".format( gobject_id, gobject.__class__.__name__, gtype)) self.gobjects[gobject_id] = gobject self.gobjects.freeze() if self.objects_persist: self.objects_load_from_config()
def __init__(self, glade_gobject, widget_type, group_name): """ :param glade_gobject: The gobject which has the radio buttons set. :type glade_gobject: :py:class:`.GladeGObject` :param str group_name: The name of the group of buttons. """ utilities.assert_arg_type(glade_gobject, gui_utilities.GladeGObject) self.group_name = group_name name_prefix = widget_type + '_' + self.group_name + '_' self.buttons = utilities.FreezableDict() for gobj_name in glade_gobject.dependencies.children: if not gobj_name.startswith(name_prefix): continue button_name = gobj_name[len(name_prefix):] self.buttons[button_name] = glade_gobject.gobjects[gobj_name] if not len(self.buttons): raise ValueError('found no ' + widget_type + ' of group: ' + self.group_name) self.buttons.freeze()
def __init__(self, application): """ :param application: The parent application for this object. :type application: :py:class:`Gtk.Application` """ utilities.assert_arg_type(application, Gtk.Application, arg_pos=1) self.config = application.config """A reference to the King Phisher client configuration.""" self.application = application """The parent :py:class:`Gtk.Application` instance.""" self.logger = logging.getLogger('KingPhisher.Client.' + self.__class__.__name__) builder = Gtk.Builder() self.gtk_builder = builder """A :py:class:`Gtk.Builder` instance used to load Glade data with.""" top_level_dependencies = [ gobject.name for gobject in self.dependencies.children if isinstance(gobject, GladeProxy) ] top_level_dependencies.append(self.dependencies.name) if self.dependencies.top_level is not None: top_level_dependencies.extend(self.dependencies.top_level) builder.add_objects_from_file(which_glade(), top_level_dependencies) builder.connect_signals(self) gobject = builder.get_object(self.dependencies.name) setattr(self, self.top_gobject, gobject) if isinstance(gobject, Gtk.Window): gobject.set_transient_for(self.application.get_active_window()) self.application.add_reference(self) if isinstance(gobject, Gtk.ApplicationWindow): application.add_window(gobject) if isinstance(gobject, Gtk.Dialog): gobject.set_modal(True) self.gobjects = utilities.FreezableDict() """A :py:class:`~king_phisher.utilities.FreezableDict` which maps gobjects to their unique GTK Builder id.""" self._load_child_dependencies(self.dependencies) self.gobjects.freeze() self._load_child_proxies() if self.objects_persist: self.objects_load_from_config()
import ssl import sys from king_phisher import errors from king_phisher import find from king_phisher import geoip from king_phisher import serializers from king_phisher import utilities import advancedhttpserver import boltons.typeutils from gi.repository import Gtk _tag_mixin_slots = ('id', 'name', 'description') _tag_mixin_types = (int, str, str) database_table_objects = utilities.FreezableDict() UNRESOLVED = boltons.typeutils.make_sentinel('UNRESOLVED', var_name='UNRESOLVED') """A sentinel value used for values in rows to indicate that the data has not been loaded from the server.""" class RemoteRowMeta(type): def __new__(mcs, name, bases, dct): dct['__slots__'] = ('__rpc__', ) + dct.get('__slots__', ()) return super(RemoteRowMeta, mcs).__new__(mcs, name, bases, dct) def __init__(cls, *args, **kwargs): table_name = getattr(cls, '__table__', None) if table_name: database_table_objects[table_name] = cls super(RemoteRowMeta, cls).__init__(*args, **kwargs)