Пример #1
0
	def _get_path(self):
		path = [find.data_directory('plugins')]
		extra_dirs = self.config.get_if_exists('server.plugin_directories', [])
		if isinstance(extra_dirs, str):
			extra_dirs = [extra_dirs]
		elif not isinstance(extra_dirs, list):
			raise errors.KingPhisherInputValidationError('configuration setting server.plugin_directories must be a list')
		for directory in extra_dirs:
			if not os.path.isdir(directory):
				continue
			path.append(directory)
		return path
Пример #2
0
	def _init_tables_api(self):
		# initialize the tables api dataset, this is to effectively pin the schema exposed allowing new columns to be
		# added without breaking rpc compatibility
		file_path = find.data_file('table-api.json')
		if file_path is None:
			raise errors.KingPhisherResourceError('missing the table-api.json data file')
		with open(file_path, 'r') as file_h:
			tables_api_data = serializers.JSON.load(file_h)
		if tables_api_data['schema'] > db_models.SCHEMA_VERSION:
			raise errors.KingPhisherInputValidationError('the table-api.json data file\'s schema version is incompatible')
		for table_name, columns in tables_api_data['tables'].items():
			model = db_models.database_tables[table_name].model
			self.tables_api[table_name] = db_models.MetaTable(
				column_names=columns,
				model=model,
				name=table_name,
				table=model.__table__
			)
		self.logger.debug("initialized the table api dataset (schema version: {0})".format(tables_api_data['schema']))
Пример #3
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
Пример #4
0
def init_database_postgresql(connection_url):
    """
	Perform additional initialization checks and operations for a PostgreSQL
	database. If the database is hosted locally this will ensure that the
	service is currently running and start it if it is not. Additionally if the
	specified database or user do not exist, they will be created.

	:param connection_url: The url for the PostgreSQL database connection.
	:type connection_url: :py:class:`sqlalchemy.engine.url.URL`
	:return: The initialized database engine.
	"""
    if not ipaddress.is_loopback(connection_url.host):
        return

    is_sanitary = lambda s: re.match(r'^[a-zA-Z0-9_]+$', s) is not None

    systemctl_bin = smoke_zephyr.utilities.which('systemctl')
    if systemctl_bin is None:
        logger.info(
            'postgresql service status check failed (could not find systemctl)'
        )
    else:
        postgresql_setup = smoke_zephyr.utilities.which('postgresql-setup')
        if postgresql_setup is None:
            logger.debug('postgresql-setup was not found')
        else:
            logger.debug(
                'using postgresql-setup to ensure that the database is initialized'
            )
            proc_h = _popen([postgresql_setup, '--initdb'])
            proc_h.wait()
        proc_h = _popen([systemctl_bin, 'status', 'postgresql.service'])
        # wait for the process to return and check if it's running (status 0)
        if proc_h.wait() == 0:
            logger.debug('postgresql service is already running via systemctl')
        else:
            logger.info(
                'postgresql service is not running, starting it now via systemctl'
            )
            proc_h = _popen([systemctl_bin, 'start', 'postgresql'])
            if proc_h.wait() != 0:
                logger.error(
                    'failed to start the postgresql service via systemctl')
                raise errors.KingPhisherDatabaseError(
                    'postgresql service failed to start via systemctl')
            logger.debug(
                'postgresql service successfully started via systemctl')

    rows = _popen_psql('SELECT usename FROM pg_user')
    if connection_url.username not in rows:
        logger.info(
            'the specified postgresql user does not exist, adding it now')
        if not is_sanitary(connection_url.username):
            raise errors.KingPhisherInputValidationError(
                'will not create the postgresql user (username contains bad characters)'
            )
        if not is_sanitary(connection_url.password):
            raise errors.KingPhisherInputValidationError(
                'will not create the postgresql user (password contains bad characters)'
            )
        rows = _popen_psql(
            "CREATE USER {url.username} WITH PASSWORD '{url.password}'".format(
                url=connection_url))
        if rows != ['CREATE ROLE']:
            logger.error('failed to create the postgresql user')
            raise errors.KingPhisherDatabaseError(
                'failed to create the postgresql user')
        logger.debug('the specified postgresql user was successfully created')

    rows = _popen_psql('SELECT datname FROM pg_database')
    if connection_url.database not in rows:
        logger.info(
            'the specified postgresql database does not exist, adding it now')
        if not is_sanitary(connection_url.database):
            raise errors.KingPhisherInputValidationError(
                'will not create the postgresql database (name contains bad characters)'
            )
        rows = _popen_psql(
            "CREATE DATABASE {url.database} OWNER {url.username}".format(
                url=connection_url))
        if rows != ['CREATE DATABASE']:
            logger.error('failed to create the postgresql database')
            raise errors.KingPhisherDatabaseError(
                'failed to create the postgresql database')
        logger.debug(
            'the specified postgresql database was successfully created')