def vte_child_routine(config):
    """
	This is the method which is executed within the child process spawned
	by VTE. It expects additional values to be set in the *config*
	object so it can initialize a new :py:class:`.KingPhisherRPCClient`
	instance. It will then drop into an interpreter where the user may directly
	interact with the rpc object.

	:param str config: A JSON encoded client configuration.
	"""
    config = json_ex.loads(config)
    try:
        import readline
        import rlcompleter  # pylint: disable=unused-variable
    except ImportError:
        pass
    else:
        readline.parse_and_bind('tab: complete')
    for plugins_directory in ('rpc_plugins', 'rpc-plugins'):
        plugins_directory = find.find_data_directory(plugins_directory)
        if not plugins_directory:
            continue
        sys.path.append(plugins_directory)

    headers = config['rpc_data'].pop('headers')
    rpc = KingPhisherRPCClient(**config['rpc_data'])
    if rpc.headers is None:
        rpc.headers = {}
    for name, value in headers.items():
        rpc.headers[str(name)] = str(value)

    banner = "Python {0} on {1}".format(sys.version, sys.platform)
    print(banner)  # pylint: disable=superfluous-parens
    information = "Campaign Name: '{0}' ID: {1}".format(
        config['campaign_name'], config['campaign_id'])
    print(information)  # pylint: disable=superfluous-parens
    console_vars = {
        'CAMPAIGN_NAME': config['campaign_name'],
        'CAMPAIGN_ID': config['campaign_id'],
        'os': os,
        'rpc': rpc,
        'sys': sys
    }
    export_to_builtins = ['CAMPAIGN_NAME', 'CAMPAIGN_ID', 'rpc']
    console = code.InteractiveConsole(console_vars)
    for var in export_to_builtins:
        console.push("__builtins__['{0}'] = {0}".format(var))
    console.interact(
        'The \'rpc\' object holds the connected KingPhisherRPCClient instance')
    return
Example #2
0
def vte_child_routine(config):
	"""
	This is the method which is executed within the child process spawned
	by VTE. It expects additional values to be set in the *config*
	object so it can initialize a new :py:class:`.KingPhisherRPCClient`
	instance. It will then drop into an interpreter where the user may directly
	interact with the rpc object.

	:param str config: A JSON encoded client configuration.
	"""
	config = json_ex.loads(config)
	try:
		import readline
		import rlcompleter  # pylint: disable=unused-variable
	except ImportError:
		pass
	else:
		readline.parse_and_bind('tab: complete')
	for plugins_directory in ('rpc_plugins', 'rpc-plugins'):
		plugins_directory = find.find_data_directory(plugins_directory)
		if not plugins_directory:
			continue
		sys.path.append(plugins_directory)

	headers = config['rpc_data'].pop('headers')
	rpc = KingPhisherRPCClient(**config['rpc_data'])
	if rpc.headers is None:
		rpc.headers = {}
	for name, value in headers.items():
		rpc.headers[str(name)] = str(value)

	banner = "Python {0} on {1}".format(sys.version, sys.platform)
	print(banner)  # pylint: disable=superfluous-parens
	information = "Campaign Name: '{0}' ID: {1}".format(config['campaign_name'], config['campaign_id'])
	print(information)  # pylint: disable=superfluous-parens
	console_vars = {
		'CAMPAIGN_NAME': config['campaign_name'],
		'CAMPAIGN_ID': config['campaign_id'],
		'os': os,
		'rpc': rpc,
		'sys': sys
	}
	export_to_builtins = ['CAMPAIGN_NAME', 'CAMPAIGN_ID', 'rpc']
	console = code.InteractiveConsole(console_vars)
	for var in export_to_builtins:
		console.push("__builtins__['{0}'] = {0}".format(var))
	console.interact('The \'rpc\' object holds the connected KingPhisherRPCClient instance')
	return
Example #3
0
	def __init__(self, file_name, mode, encoding='utf-8'):
		"""
		:param str file_name: The path to the file to open as an archive.
		:param str mode: The mode to open the file such as 'r' or 'w'.
		:param str encoding: The encoding to use for strings.
		"""
		self._mode = mode + ':bz2'
		self.encoding = encoding
		self.file_name = file_name
		epoch = datetime.datetime.utcfromtimestamp(0)
		self.mtime = (datetime.datetime.utcnow() - epoch).total_seconds()
		self._tar_h = tarfile.open(file_name, self._mode)
		if 'r' in mode and self.has_file(self.metadata_file_name):
			self.metadata = json_ex.loads(self.get_data(self.metadata_file_name).decode(self.encoding))
		else:
			self.metadata = {}
		if 'w' in mode:
			self.metadata['timestamp'] = datetime.datetime.utcnow().isoformat()
			self.metadata['version'] = version.version
Example #4
0
    def __init__(self, file_name, mode, encoding='utf-8'):
        """
		:param str file_name: The path to the file to open as an archive.
		:param str mode: The mode to open the file such as 'r' or 'w'.
		:param str encoding: The encoding to use for strings.
		"""
        self._mode = mode + ':bz2'
        self.encoding = encoding
        self.file_name = file_name
        epoch = datetime.datetime.utcfromtimestamp(0)
        self.mtime = (datetime.datetime.utcnow() - epoch).total_seconds()
        self._tar_h = tarfile.open(file_name, self._mode)
        if 'r' in mode and self.has_file(self.metadata_file_name):
            self.metadata = json_ex.loads(
                self.get_data(self.metadata_file_name).decode(self.encoding))
        else:
            self.metadata = {}
        if 'w' in mode:
            self.metadata['timestamp'] = datetime.datetime.utcnow().isoformat()
            self.metadata['version'] = version.version
Example #5
0
def message_data_from_kpm(target_file, dest_dir):
	"""
	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.
	: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 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 KingPhisherInputValidationError('data is missing from the message archive')
	message_config = kpm.get_data('message_config.json')
	message_config = json_ex.loads(message_config)

	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_name = os.path.basename(file_name)
			file_path = os.path.join(attachment_dir, 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 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 KingPhisherInputValidationError('data is missing from the message archive')
		arcfile_h = kpm.get_file(file_name)
		file_path = os.path.join(dest_dir, 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 not 'html_file' in message_config:
			logger.warning('the kpm message configuration is missing the html_file setting')
			raise KingPhisherInputValidationError('data is missing from the message archive')
		arcfile_h = kpm.get_file('message_content.html')
		file_path = os.path.join(dest_dir, message_config['html_file'])
		with open(file_path, 'wb') as file_h:
			file_h.write(message_template_from_kpm(arcfile_h.read(), attachments))
		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 KingPhisherInputValidationError('data is missing from the message archive')
	kpm.close()
	return message_config
Example #6
0
	def test_json_ex_loads(self):
		try:
			json_ex.loads(json_ex.dumps('test'))
		except ValueError:
			self.fail('Invalid data type for json_ex.loads()')
Example #7
0
	def test_json_ex_loads_invalid(self):
		with self.assertRaises(ValueError):
			json_ex.loads("'test")