Example #1
0
	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
Example #2
0
 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
Example #3
0
 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
Example #4
0
	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)
Example #5
0
	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()
Example #6
0
	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)
Example #7
0
 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)))
Example #8
0
    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()
Example #9
0
    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)
Example #10
0
    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()
Example #11
0
	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()
Example #12
0
    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()
Example #13
0
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)