Exemplo n.º 1
0
    def signal_kpm_select_clicked(self, _):
        dialog = extras.FileChooserDialog('Import Message Configuration',
                                          self.parent)
        dialog.quick_add_filter('King Phisher Message Files', '*.kpm')
        dialog.quick_add_filter('All Files', '*')
        response = dialog.run_quick_open()
        dialog.destroy()
        if not response:
            return False
        target_path = response['target_path']
        self.gobjects['entry_kpm_file'].set_text(target_path)
        self._set_page_complete(self._get_kpm_path().is_valid)

        if not _kpm_file_path_is_valid(target_path):
            return
        # open the KPM for reading to extract the target URL for the assistant,
        # ignore the directory to allow the user to optionally only import the URL
        kpm = archive.ArchiveFile(target_path, 'r')
        if not kpm.has_file('message_config.json'):
            self.logger.warning(
                'the kpm archive is missing the message_config.json file')
            return
        message_config = kpm.get_json('message_config.json')
        webserver_url = message_config.get('webserver_url')
        if not webserver_url:
            return
        self._set_webserver_url(webserver_url)
Exemplo n.º 2
0
def import_database(target_file, clear=True):
    """
	Import the contents of a serialized database from an archive previously
	created with the :py:func:`.export_database` function. The current
	:py:data:`~king_phisher.server.database.models.SCHEMA_VERSION` must be the
	same as the exported archive.

	.. warning::
		This will by default delete the contents of the current database in
		accordance with the *clear* parameter. If *clear* is not
		specified and objects in the database and import share an ID, they will
		be merged.

	:param str target_file: The database archive file to import from.
	:param bool clear: Whether or not to delete the contents of the
		existing database before importing the new data.
	"""
    kpdb = archive.ArchiveFile(target_file, 'r')
    schema_version = kpdb.metadata['database-schema']
    if schema_version != models.SCHEMA_VERSION:
        raise errors.KingPhisherDatabaseError(
            "incompatible database schema versions ({0} vs {1})".format(
                schema_version, models.SCHEMA_VERSION))

    if clear:
        clear_database()
    session = Session()
    for table in models.metadata.sorted_tables:
        table_data = kpdb.get_data('tables/' + table.name)
        for row in sqlalchemy.ext.serializer.loads(table_data):
            session.merge(row)
    session.commit()
    kpdb.close()
Exemplo n.º 3
0
def message_data_to_kpm(message_config, target_file, encoding='utf-8'):
    """
	Save details describing a message to the target file.

	:param dict message_config: The message details from the client configuration.
	:param str target_file: The file to write the data to.
	:param str encoding: The encoding to use for strings.
	"""
    message_config = copy.copy(message_config)
    kpm = archive.ArchiveFile(target_file, 'w')

    for config_name, file_name in KPM_ARCHIVE_FILES.items():
        if os.access(message_config.get(config_name, ''), os.R_OK):
            kpm.add_file(file_name, message_config[config_name])
            message_config[config_name] = os.path.basename(
                message_config[config_name])
            continue
        if len(message_config.get(config_name, '')):
            logger.info(
                "the specified {0} '{1}' is not readable, the setting will be removed"
                .format(config_name, message_config[config_name]))
        if config_name in message_config:
            del message_config[config_name]

    if os.access(message_config.get('html_file', ''), os.R_OK):
        with codecs.open(message_config['html_file'], 'r',
                         encoding=encoding) as file_h:
            template = file_h.read()
        message_config['html_file'] = os.path.basename(
            message_config['html_file'])
        template, attachments = message_template_to_kpm(template)
        logger.debug("identified {0} attachment file{1} to be archived".format(
            len(attachments), 's' if len(attachments) > 1 else ''))
        kpm.add_data('message_content.html', template)
        for attachment in attachments:
            if os.access(attachment, os.R_OK):
                kpm.add_file(
                    os.path.join('attachments', os.path.basename(attachment)),
                    attachment)
    else:
        if len(message_config.get('html_file', '')):
            logger.info(
                "the specified html_file '{0}' is not readable, the setting will be removed"
                .format(message_config['html_file']))
        if 'html_file' in message_config:
            del message_config['html_file']

    kpm.add_data('message_config.json',
                 serializers.JSON.dumps(message_config, pretty=True))
    kpm.close()
    return
Exemplo n.º 4
0
def export_database(target_file):
	"""
	Export the contents of the database using SQLAlchemy's serialization. This
	creates an archive file containing all of the tables and their data. The
	resulting export can be imported into another supported database so long
	as the :py:data:`~king_phisher.server.database.models.SCHEMA_VERSION` is the
	same.

	:param str target_file: The file to write the export to.
	"""
	session = Session()
	kpdb = archive.ArchiveFile(target_file, 'w')
	kpdb.metadata['database-schema'] = models.SCHEMA_VERSION
	for table in models.metadata.sorted_tables:
		table_name = table.name
		table = models.database_table_objects[table_name]
		kpdb.add_data('tables/' + table_name, sqlalchemy.ext.serializer.dumps(session.query(table).all()))
	kpdb.close()
Exemplo n.º 5
0
def message_data_from_kpm(target_file, dest_dir, encoding='utf-8'):
	"""
	Retrieve the stored details describing a message from a previously exported
	file.

	:param str target_file: The file to load as a message archive.
	:param str dest_dir: The directory to extract data and attachment files to.
	:param str encoding: The encoding to use for strings.
	:return: The restored details from the message config.
	:rtype: dict
	"""
	if not archive.is_archive(target_file):
		logger.warning('the file is not recognized as a valid archive')
		raise errors.KingPhisherInputValidationError('file is not in the correct format')
	kpm = archive.ArchiveFile(target_file, 'r')

	attachment_member_names = [n for n in kpm.file_names if n.startswith('attachments' + os.path.sep)]
	attachments = []

	if not kpm.has_file('message_config.json'):
		logger.warning('the kpm archive is missing the message_config.json file')
		raise errors.KingPhisherInputValidationError('data is missing from the message archive')
	message_config = kpm.get_json('message_config.json')
	message_config.pop('company_name', None)

	if attachment_member_names:
		attachment_dir = os.path.join(dest_dir, 'attachments')
		if not os.path.isdir(attachment_dir):
			os.mkdir(attachment_dir)
		for file_name in attachment_member_names:
			arcfile_h = kpm.get_file(file_name)
			file_path = os.path.join(attachment_dir, os.path.basename(file_name))
			with open(file_path, 'wb') as file_h:
				shutil.copyfileobj(arcfile_h, file_h)
			attachments.append(file_path)
		logger.debug("extracted {0} attachment file{1} from the archive".format(len(attachments), 's' if len(attachments) > 1 else ''))

	for config_name, file_name in KPM_ARCHIVE_FILES.items():
		if not file_name in kpm.file_names:
			if config_name in message_config:
				logger.warning("the kpm archive is missing the {0} file".format(file_name))
				raise errors.KingPhisherInputValidationError('data is missing from the message archive')
			continue
		if not message_config.get(config_name):
			logger.warning("the kpm message configuration is missing the {0} setting".format(config_name))
			raise errors.KingPhisherInputValidationError('data is missing from the message archive')
		arcfile_h = kpm.get_file(file_name)
		file_path = os.path.join(dest_dir, os.path.basename(message_config[config_name]))
		with open(file_path, 'wb') as file_h:
			shutil.copyfileobj(arcfile_h, file_h)
		message_config[config_name] = file_path

	if 'message_content.html' in kpm.file_names:
		if 'html_file' not in message_config:
			logger.warning('the kpm message configuration is missing the html_file setting')
			raise errors.KingPhisherInputValidationError('data is missing from the message archive')
		arcfile_h = kpm.get_file('message_content.html')
		file_path = os.path.join(dest_dir, os.path.basename(message_config['html_file']))
		with open(file_path, 'wb') as file_h:
			file_h.write(message_template_from_kpm(arcfile_h.read().decode(encoding), attachments).encode(encoding))
		message_config['html_file'] = file_path
	elif 'html_file' in message_config:
		logger.warning('the kpm archive is missing the message_content.html file')
		raise errors.KingPhisherInputValidationError('data is missing from the message archive')
	kpm.close()
	return message_config