Ejemplo n.º 1
0
 def save_proxy_settings(self):
     proxy_url = urllib.parse.urlparse(
         self.gtk_builder_get('entry_proxy_url').get_text().strip())
     proxy_username = self.gtk_builder_get(
         'entry_proxy_username').get_text().strip()
     proxy_password = self.gtk_builder_get(
         'entry_proxy_password').get_text().strip()
     if not proxy_url.geturl():
         self.config['proxy.url'] = None
         os.environ.pop('HTTP_PROXY', None)
         os.environ.pop('HTTPS_PROXY', None)
         return
     if not (proxy_url.hostname and proxy_url.scheme):
         gui_utilities.show_dialog_warning(
             'Invalid Proxy Settings', self.parent,
             'The proxy url you have submitted is not valid.')
         return
     try:
         proxy_url.port
     except ValueError:
         gui_utilities.show_dialog_warning(
             'Invalid Proxy Settings', self.parent,
             'The port must be an integer between 1-65535 inclusive.')
         return
     netloc = proxy_url.netloc
     if proxy_username:
         netloc = '{}:{}@{}'.format(proxy_username, proxy_password,
                                    proxy_url.netloc)
     formatted_proxy_url = urllib.parse.urlunparse(
         (proxy_url.scheme, netloc, proxy_url.path, '', '', ''))
     self.config['proxy.url'] = formatted_proxy_url
     os.environ['HTTP_PROXY'] = formatted_proxy_url
     os.environ['HTTPS_PROXY'] = formatted_proxy_url
Ejemplo n.º 2
0
	def _sender_precheck_attachment(self):
		attachment = self.config.get('mailer.attachment_file')
		if not attachment:
			return True
		if not os.path.isfile(attachment):
			gui_utilities.show_dialog_warning('Invalid Attachment', self.parent, 'The specified attachment file does not exist.')
			return False
		if not os.access(attachment, os.R_OK):
			gui_utilities.show_dialog_warning('Invalid Attachment', self.parent, 'The specified attachment file can not be read.')
			return False
		self.text_insert("File '{0}' will be attached to sent messages.\n".format(os.path.basename(attachment)))
		_, extension = os.path.splitext(attachment)
		extension = extension[1:]
		if self.config['remove_attachment_metadata'] and extension in ('docm', 'docx', 'pptm', 'pptx', 'xlsm', 'xlsx'):
			scrubber.remove_office_metadata(attachment)
			self.text_insert("Attachment file detected as MS Office 2007+, metadata has been removed.\n")
		md5 = hashlib.new('md5')
		sha1 = hashlib.new('sha1')
		with open(attachment, 'rb') as file_h:
			data = True
			while data:
				data = file_h.read(1024)
				md5.update(data)
				sha1.update(data)
		self.text_insert("  MD5:  {0}\n".format(md5.hexdigest()))
		self.text_insert("  SHA1: {0}\n".format(sha1.hexdigest()))
		return True
Ejemplo n.º 3
0
	def _sender_precheck_settings(self):
		required_settings = {
			'mailer.webserver_url': 'Web Server URL',
			'mailer.subject': 'Subject',
			'mailer.html_file': 'Message HTML File'
		}
		target_type = self.config.get('mailer.target_type')
		if target_type == 'file':
			required_settings['mailer.target_file'] = 'Target CSV File'
		elif target_type == 'single':
			required_settings['mailer.target_email_address'] = 'Target Email Address'
			required_settings['mailer.target_name'] = 'Target Name'
		else:
			gui_utilities.show_dialog_warning('Invalid Target Type', self.parent, 'Please specify a target file or name and email address.')
			return False
		message_type = self.config.get('mailer.message_type')
		if not message_type in ('email', 'calendar_invite'):
			gui_utilities.show_dialog_warning('Invalid Message Type', self.parent, 'Please select a valid message type.')
			return False
		for setting, setting_name in required_settings.items():
			if not self.config.get(setting):
				gui_utilities.show_dialog_warning("Missing Required Option: '{0}'".format(setting_name), self.parent, 'Return to the Config tab and set all required options')
				return
			if not setting.endswith('_file'):
				continue
			file_path = self.config[setting]
			if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
				gui_utilities.show_dialog_warning('Invalid Option Configuration', self.parent, "Setting: '{0}'\nReason: the file could not be read.".format(setting_name))
				return False
		if not self.config.get('smtp_server'):
			gui_utilities.show_dialog_warning('Missing SMTP Server Setting', self.parent, 'Please configure the SMTP server')
			return False
		return True
Ejemplo n.º 4
0
    def start_sftp_client(self):
        """
		Start the client's preferred sftp client application.
		"""
        if not self.config['sftp_client']:
            gui_utilities.show_dialog_warning(
                'Invalid SFTP Configuration', self,
                'An SFTP client is not configured')
            return False
        command = str(self.config['sftp_client'])
        sftp_bin = shlex.split(command)[0]
        if not utilities.which(sftp_bin):
            self.logger.warning('could not locate the sftp binary: ' +
                                sftp_bin)
            gui_utilities.show_dialog_warning(
                'Invalid SFTP Configuration', self,
                "Could not find the SFTP binary '{0}'".format(sftp_bin))
            return False
        try:
            command = command.format(
                server=self.config['server'],
                username=self.config['server_username'],
                web_root=self.config['server_config']['server.web_root'])
        except KeyError:
            pass
        self.logger.debug("starting sftp client command: {0}".format(command))
        utilities.start_process(command, wait=False)
        return
Ejemplo n.º 5
0
 def save_alert_settings(self):
     email_address = gui_utilities.gobject_get_value(
         self.gobjects['entry_email_address'])
     phone_number = gui_utilities.gobject_get_value(
         self.gobjects['entry_sms_phone_number'])
     sms_carrier = gui_utilities.gobject_get_value(
         self.gobjects['combobox_sms_carrier'])
     server_user = self.application.server_user
     if email_address and not utilities.is_valid_email_address(
             email_address):
         gui_utilities.show_dialog_warning(
             'Invalid Email Address', self.parent,
             'The email address you have entered is not valid.')
         return
     if phone_number:
         phone_number = ''.join(d for d in phone_number
                                if d in string.digits)
         if len(phone_number) > 11:
             gui_utilities.show_dialog_warning(
                 'Invalid Phone Number', self.parent,
                 'The phone number must not contain more than 11 digits')
             return
     email_address = utilities.nonempty_string(email_address)
     phone_number = utilities.nonempty_string(phone_number)
     sms_carrier = utilities.nonempty_string(sms_carrier)
     self.application.rpc(
         'db/table/set', 'users', server_user.id,
         ('email_address', 'phone_number', 'phone_carrier'),
         (email_address, phone_number, sms_carrier))
Ejemplo n.º 6
0
	def _sender_precheck_settings(self):
		required_settings = {
			'mailer.webserver_url': 'Web Server URL',
			'mailer.subject': 'Subject',
			'mailer.html_file': 'Message HTML File'
		}
		target_type = self.config.get('mailer.target_type')
		if target_type == 'file':
			required_settings['mailer.target_file'] = 'Target CSV File'
		elif target_type == 'single':
			required_settings['mailer.target_email_address'] = 'Target Email Address'
			required_settings['mailer.target_name'] = 'Target Name'
		else:
			gui_utilities.show_dialog_warning('Invalid Target Type', self.parent, 'Please specify a target file or name and email address.')
			return False
		message_type = self.config.get('mailer.message_type')
		if not message_type in ('email', 'calendar_invite'):
			gui_utilities.show_dialog_warning('Invalid Message Type', self.parent, 'Please select a valid message type.')
			return False
		for setting, setting_name in required_settings.items():
			if not self.config.get(setting):
				gui_utilities.show_dialog_warning("Missing Required Option: '{0}'".format(setting_name), self.parent, 'Return to the Config tab and set all required options')
				return
			if not setting.endswith('_file'):
				continue
			file_path = self.config[setting]
			if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
				gui_utilities.show_dialog_warning('Invalid Option Configuration', self.parent, "Setting: '{0}'\nReason: the file could not be read.".format(setting_name))
				return False
		if not self.config.get('smtp_server'):
			gui_utilities.show_dialog_warning('Missing SMTP Server Setting', self.parent, 'Please configure the SMTP server')
			return False
		return True
Ejemplo n.º 7
0
	def _sender_precheck_attachment(self):
		attachment = self.config.get('mailer.attachment_file')
		if not attachment:
			return True
		if not os.path.isfile(attachment):
			gui_utilities.show_dialog_warning('Invalid Attachment', self.parent, 'The specified attachment file does not exist.')
			return False
		if not os.access(attachment, os.R_OK):
			gui_utilities.show_dialog_warning('Invalid Attachment', self.parent, 'The specified attachment file can not be read.')
			return False
		self.text_insert("File '{0}' will be attached to sent messages.\n".format(os.path.basename(attachment)))
		_, extension = os.path.splitext(attachment)
		extension = extension[1:]
		if self.config['remove_attachment_metadata'] and extension in ('docm', 'docx', 'pptm', 'pptx', 'xlsm', 'xlsx'):
			scrubber.remove_office_metadata(attachment)
			self.text_insert("Attachment file detected as MS Office 2007+, metadata has been removed.\n")
		md5 = hashlib.new('md5')
		sha1 = hashlib.new('sha1')
		with open(attachment, 'rb') as file_h:
			data = True
			while data:
				data = file_h.read(1024)
				md5.update(data)
				sha1.update(data)
		self.text_insert("  MD5:  {0}\n".format(md5.hexdigest()))
		self.text_insert("  SHA1: {0}\n".format(sha1.hexdigest()))
		return True
Ejemplo n.º 8
0
	def signal_button_clicked_verify(self, button):
		target_url = self.gobjects['entry_webserver_url'].get_text()
		error_description = None
		try:
			response = test_webserver_url(target_url, self.config['server_config']['server.secret_id'])
		except requests.exceptions.RequestException as error:
			if isinstance(error, requests.exceptions.ConnectionError):
				self.logger.warning('verify url attempt failed, could not connect')
				error_description = 'Could not connect to the server'
			elif isinstance(error, requests.exceptions.Timeout):
				self.logger.warning('verify url attempt failed, a timeout occurred')
				error_description = 'The HTTP request timed out'
			else:
				self.logger.warning('unknown verify url exception: ' + repr(error))
				error_description = 'An unknown verify URL exception occurred'
		else:
			if response.status_code < 200 or response.status_code > 299:
				self.logger.warning("verify url HTTP error: {0} {1}".format(response.status_code, response.reason))
				error_description = "HTTP status {0} {1}".format(response.status_code, response.reason)
			else:
				self.logger.debug("verify url HTTP status: {0} {1}".format(response.status_code, response.reason))
		if error_description:
			gui_utilities.show_dialog_warning('Unable To Open The Web Server URL', self.parent, error_description)
		else:
			gui_utilities.show_dialog_info('Successfully Opened The Web Server URL', self.parent)
		return
Ejemplo n.º 9
0
	def signal_treeview_key_pressed(self, widget, event):
		if event.type != Gdk.EventType.KEY_PRESS:
			return

		treeview = self.gobjects['treeview_campaigns']
		keyval = event.get_keyval()[1]
		if event.get_state() == Gdk.ModifierType.CONTROL_MASK:
			if keyval == Gdk.KEY_c:
				gui_utilities.gtk_treeview_selection_to_clipboard(treeview)
		elif keyval == Gdk.KEY_F5:
			self.load_campaigns()
			self._highlight_campaign(self.config.get('campaign_name'))
		elif keyval == Gdk.KEY_Delete:
			treeview_selection = treeview.get_selection()
			(model, tree_iter) = treeview_selection.get_selected()
			if not tree_iter:
				return
			campaign_id = model.get_value(tree_iter, 0)
			if self.config.get('campaign_id') == campaign_id:
				gui_utilities.show_dialog_warning('Can Not Delete Campaign', self.dialog, 'Can not delete the current campaign.')
				return
			if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self.dialog, 'This action is irreversible, all campaign data will be lost.'):
				return
			self.parent.rpc('campaign/delete', campaign_id)
			self.load_campaigns()
			self._highlight_campaign(self.config.get('campaign_name'))
Ejemplo n.º 10
0
 def _sender_precheck_campaign(self):
     campaign = self.application.rpc.remote_table_row("campaigns", self.config["campaign_id"])
     if campaign.expiration and campaign.expiration < datetime.datetime.utcnow():
         gui_utilities.show_dialog_warning(
             "Campaign Is Expired", self.parent, "The current campaign has already expired"
         )
         return False
     return True
Ejemplo n.º 11
0
	def signal_button_clicked(self, button):
		if self._creation_assistant is not None:
			gui_utilities.show_dialog_warning('Campaign Creation Assistant', self.dialog, 'The campaign creation assistant is already active.')
			return
		assistant = CampaignAssistant(self.application)
		assistant.assistant.set_transient_for(self.dialog)
		assistant.assistant.set_modal(True)
		assistant.assistant.connect('destroy', self.signal_assistant_destroy, assistant)
		assistant.interact()
		self._creation_assistant = assistant
Ejemplo n.º 12
0
	def export_table_to_xlsx_worksheet(self, worksheet):
		"""Export the data represented by the view to a XLSX worksheet."""
		if not self.loader_thread_lock.acquire(False) or (isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive()):
			gui_utilities.show_dialog_warning('Can Not Export Rows While Loading', self.parent)
			return
		store = self.gobjects['treeview_campaign'].get_model()
		columns = dict(enumerate(('UID',) + self.view_columns))
		worksheet.set_column(0, len(columns), 30)
		export.liststore_to_xlsx_worksheet(store, worksheet, columns)
		self.loader_thread_lock.release()
Ejemplo n.º 13
0
	def export_table_to_xlsx_worksheet(self, worksheet):
		"""Export the data represented by the view to a XLSX worksheet."""
		if not self.loader_thread_lock.acquire(False) or (isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive()):
			gui_utilities.show_dialog_warning('Can Not Export Rows While Loading', self.parent)
			return
		store = self.gobjects['treeview_campaign'].get_model()
		columns = dict(enumerate(('UID',) + self.view_columns))
		worksheet.set_column(0, len(columns), 30)
		export.liststore_to_xlsx_worksheet(store, worksheet, columns)
		self.loader_thread_lock.release()
Ejemplo n.º 14
0
	def save_sms_settings(self):
		phone_number = gui_utilities.gobject_get_value(self.gobjects['entry_sms_phone_number'])
		sms_carrier = gui_utilities.gobject_get_value(self.gobjects['combobox_sms_carrier'])
		server_user = self.application.server_user
		if phone_number:
			phone_number = ''.join(d for d in phone_number if d in string.digits)
			if len(phone_number) > 11:
				gui_utilities.show_dialog_warning('Invalid Phone Number', self.parent, 'The phone number must not contain more than 11 digits')
				return
		phone_number = utilities.nonempty_string(phone_number)
		sms_carrier = utilities.nonempty_string(sms_carrier)
		self.application.rpc('db/table/set', 'users', server_user.id, ('phone_number', 'phone_carrier'), (phone_number, sms_carrier))
Ejemplo n.º 15
0
	def signal_button_clicked_export(self, button):
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Export Rows While Loading', self.parent)
			return
		dialog = gui_utilities.UtilityFileChooser('Export Data', self.parent)
		file_name = self.config['campaign_name'] + '.csv'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			return
		destination_file = response['target_path']
		export.treeview_liststore_to_csv(self.gobjects['treeview_campaign'], destination_file)
	def signal_button_clicked_export(self, button):
		if isinstance(self.row_loader_thread, threading.Thread) and self.row_loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Export Rows While Loading', self.parent)
			return
		dialog = gui_utilities.UtilityFileChooser('Export Data', self.parent)
		file_name = self.config['campaign_name'] + '.csv'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			return
		destination_file = response['target_filename']
		export.treeview_liststore_to_csv(self.gobjects['treeview_campaign'], destination_file)
Ejemplo n.º 17
0
	def signal_popup_menu_activate_show_documentation(self, _):
		named_row = self._selected_named_row
		if named_row is None or named_row.type != _ROW_TYPE_PLUGIN:
			return
		if not named_row.installed:
			gui_utilities.show_dialog_warning('No Documentation', self.window, 'This plugin has no documentation.')
			return
		try:
			PluginDocumentationWindow(self.application, named_row.id)
		except FileNotFoundError as error:
			self.logger.warning(error.strerror)
			gui_utilities.show_dialog_warning('No Documentation', self.window, error.strerror.capitalize() + '.')
Ejemplo n.º 18
0
	def _prompt_to_delete_row(self, treeview, selection):
		(model, tree_iter) = selection.get_selected()
		if not tree_iter:
			return
		campaign_id = model.get_value(tree_iter, 0)
		if self.config.get('campaign_id') == campaign_id:
			gui_utilities.show_dialog_warning('Can Not Delete Campaign', self.dialog, 'Can not delete the current campaign.')
			return
		if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self.dialog, 'This action is irreversible, all campaign data will be lost.'):
			return
		self.application.emit('campaign-delete', campaign_id)
		self.load_campaigns()
		self._highlight_campaign(self.config.get('campaign_name'))
Ejemplo n.º 19
0
	def _prompt_to_delete_row(self, treeview, selection):
		(model, tree_iter) = selection.get_selected()
		if not tree_iter:
			return
		campaign_id = model.get_value(tree_iter, 0)
		if self.config.get('campaign_id') == campaign_id:
			gui_utilities.show_dialog_warning('Can Not Delete Campaign', self.dialog, 'Can not delete the current campaign.')
			return
		if not gui_utilities.show_dialog_yes_no('Delete This Campaign?', self.dialog, 'This action is irreversible, all campaign data will be lost.'):
			return
		self.application.emit('campaign-delete', campaign_id)
		self.load_campaigns()
		self._highlight_campaign(self.config.get('campaign_name'))
	def signal_button_clicked(self, button):
		campaign_name_entry = self.gobjects['entry_new_campaign_name']
		campaign_name = campaign_name_entry.get_property('text')
		if not campaign_name:
			gui_utilities.show_dialog_warning('Invalid Campaign Name', self.dialog, 'Please specify a new campaign name')
			return
		try:
			self.parent.rpc('campaign/new', campaign_name)
		except AdvancedHTTPServer.AdvancedHTTPServerRPCError:
			gui_utilities.show_dialog_error('Failed To Create New Campaign', self.dialog, 'Encountered an error creating the new campaign')
			return
		campaign_name_entry.set_property('text', '')
		self.load_campaigns()
		self._highlight_campaign(campaign_name)
Ejemplo n.º 21
0
	def signal_button_clicked(self, button):
		campaign_name_entry = self.gobjects['entry_new_campaign_name']
		campaign_name = campaign_name_entry.get_property('text')
		if not campaign_name:
			gui_utilities.show_dialog_warning('Invalid Campaign Name', self.dialog, 'Please specify a new campaign name')
			return
		try:
			self.parent.rpc('campaign/new', campaign_name)
		except:
			gui_utilities.show_dialog_error('Failed To Create New Campaign', self.dialog, 'Encountered an error creating the new campaign')
			return
		campaign_name_entry.set_property('text', '')
		self.load_campaigns()
		self._highlight_campaign(campaign_name)
	def signal_activate_popup_menu_delete(self, action):
		if isinstance(self.row_loader_thread, threading.Thread) and self.row_loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent)
			return
		treeview = self.gobjects['treeview_campaign']
		selection = treeview.get_selection()
		(model, tree_iter) = selection.get_selected()
		if not tree_iter:
			return
		row_id = model.get_value(tree_iter, 0)
		if not gui_utilities.show_dialog_yes_no('Delete This Row?', self.parent, 'This information will be lost'):
			return
		self.parent.rpc(self.remote_table_name + '/delete', row_id)
		self.load_campaign_information(force=True)
	def signal_button_clicked_verify(self, button):
		target_url = self.gobjects['entry_webserver_url'].get_text()
		try:
			parsed_url = urlparse.urlparse(target_url)
			query = urlparse.parse_qs(parsed_url.query)
			query['id'] = [self.config['server_config']['server.secret_id']]
			query = urllib.urlencode(query, True)
			target_url = urlparse.urlunparse((parsed_url.scheme, parsed_url.netloc, parsed_url.path, parsed_url.params, query, parsed_url.fragment))
			urllib2.urlopen(target_url, timeout=5)
		except:
			gui_utilities.show_dialog_warning('Unable To Open The Web Server URL', self.parent)
			return
		gui_utilities.show_dialog_info('Successfully Opened The Web Server URL', self.parent)
		return
Ejemplo n.º 24
0
	def _prompt_to_delete_row(self, treeview, _):
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent)
			return
		model = treeview.get_model()
		row_ids = [model.get_value(ti, 0) for ti in gui_utilities.gtk_treeview_selection_iterate(treeview)]
		if len(row_ids) == 0:
			return
		elif len(row_ids) == 1:
			message = 'Delete This Row?'
		else:
			message = "Delete These {0:,} Rows?".format(len(row_ids))
		if not gui_utilities.show_dialog_yes_no(message, self.parent, 'This information will be lost.'):
			return
		self.application.emit(self.table_name[:-1] + '-delete', row_ids)
Ejemplo n.º 25
0
	def _prompt_to_delete_row(self, treeview, _):
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent)
			return
		model = treeview.get_model()
		row_ids = [model.get_value(ti, 0) for ti in gui_utilities.gtk_treeview_selection_iterate(treeview)]
		if len(row_ids) == 0:
			return
		elif len(row_ids) == 1:
			message = 'Delete This Row?'
		else:
			message = "Delete These {0:,} Rows?".format(len(row_ids))
		if not gui_utilities.show_dialog_yes_no(message, self.parent, 'This information will be lost.'):
			return
		self.application.emit(self.table_name[:-1] + '-delete', row_ids)
Ejemplo n.º 26
0
	def export_table_to_xlsx_worksheet(self, worksheet, title_format):
		"""
		Export the data represented by the view to an XLSX worksheet.

		:param worksheet: The destination sheet for the store's data.
		:type worksheet: :py:class:`xlsxwriter.worksheet.Worksheet`
		:param title_format: The formatting to use for the title row.
		:type title_format: :py:class:`xlsxwriter.format.Format`
		"""
		if not self.loader_thread_lock.acquire(False) or (isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive()):
			gui_utilities.show_dialog_warning('Can Not Export Rows While Loading', self.parent)
			return
		store = self.gobjects['treeview_campaign'].get_model()
		columns = dict(enumerate(('UID',) + self.view_columns))
		export.liststore_to_xlsx_worksheet(store, worksheet, columns, title_format)
		self.loader_thread_lock.release()
Ejemplo n.º 27
0
 def _sender_precheck_settings(self):
     required_settings = {
         "mailer.webserver_url": "Web Server URL",
         "mailer.subject": "Subject",
         "mailer.html_file": "Message HTML File",
     }
     target_type = self.config.get("mailer.target_type")
     if target_type == "file":
         required_settings["mailer.target_file"] = "Target CSV File"
     elif target_type == "single":
         required_settings["mailer.target_email_address"] = "Target Email Address"
         required_settings["mailer.target_name"] = "Target Name"
     else:
         gui_utilities.show_dialog_warning(
             "Invalid Target Type", self.parent, "Please specify a target file or name and email address."
         )
         return False
     message_type = self.config.get("mailer.message_type")
     if not message_type in ("email", "calendar_invite"):
         gui_utilities.show_dialog_warning(
             "Invalid Message Type", self.parent, "Please select a valid message type."
         )
         return False
     for setting, setting_name in required_settings.items():
         if not self.config.get(setting):
             gui_utilities.show_dialog_warning(
                 "Missing Required Option: '{0}'".format(setting_name),
                 self.parent,
                 "Return to the Config tab and set all required options",
             )
             return
         if not setting.endswith("_file"):
             continue
         file_path = self.config[setting]
         if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
             gui_utilities.show_dialog_warning(
                 "Invalid Option Configuration",
                 self.parent,
                 "Setting: '{0}'\nReason: the file could not be read.".format(setting_name),
             )
             return False
     if not self.config.get("smtp_server"):
         gui_utilities.show_dialog_warning(
             "Missing SMTP Server Setting", self.parent, "Please configure the SMTP server"
         )
         return False
     return True
Ejemplo n.º 28
0
	def save_alert_settings(self):
		email_address = gui_utilities.gobject_get_value(self.gobjects['entry_email_address'])
		phone_number = gui_utilities.gobject_get_value(self.gobjects['entry_sms_phone_number'])
		sms_carrier = gui_utilities.gobject_get_value(self.gobjects['combobox_sms_carrier'])
		server_user = self.application.server_user
		if email_address and not utilities.is_valid_email_address(email_address):
			gui_utilities.show_dialog_warning('Invalid Email Address', self.parent, 'The email address you have entered is not valid.')
			return
		if phone_number:
			phone_number = ''.join(d for d in phone_number if d in string.digits)
			if len(phone_number) > 11:
				gui_utilities.show_dialog_warning('Invalid Phone Number', self.parent, 'The phone number must not contain more than 11 digits')
				return
		email_address = utilities.nonempty_string(email_address)
		phone_number = utilities.nonempty_string(phone_number)
		sms_carrier = utilities.nonempty_string(sms_carrier)
		self.application.rpc('db/table/set', 'users', server_user.id, ('email_address', 'phone_number', 'phone_carrier'), (email_address, phone_number, sms_carrier))
Ejemplo n.º 29
0
	def verify_sms_settings(self):
		phone_number = gui_utilities.gobject_get_value(self.gobjects['entry_sms_phone_number'])
		phone_number_set = bool(phone_number)
		sms_carrier_set = bool(self.gobjects['combobox_sms_carrier'].get_active() > 0)
		if phone_number_set ^ sms_carrier_set:
			gui_utilities.show_dialog_warning('Missing Information', self.parent, 'Both a phone number and a valid carrier must be specified')
			if 'sms_phone_number' in self.config:
				del self.config['sms_phone_number']
			if 'sms_carrier' in self.config:
				del self.config['sms_carrier']
		elif phone_number_set and sms_carrier_set:
			phone_number = ''.join(d for d in phone_number if d in string.digits)
			if len(phone_number) != 10:
				gui_utilities.show_dialog_warning('Invalid Phone Number', self.parent, 'The phone number must contain exactly 10 digits')
				return
			username = self.config['server_username']
			self.application.rpc('users/set', username, ('phone_number', 'phone_carrier'), (phone_number, self.config['sms_carrier']))
Ejemplo n.º 30
0
	def export_table_to_csv(self):
		"""Export the data represented by the view to a CSV file."""
		if not self.loader_thread_lock.acquire(False) or (isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive()):
			gui_utilities.show_dialog_warning('Can Not Export Rows While Loading', self.parent)
			return
		dialog = extras.FileChooserDialog('Export Data', self.parent)
		file_name = self.config['campaign_name'] + '.csv'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			self.loader_thread_lock.release()
			return
		destination_file = response['target_path']
		store = self.gobjects['treeview_campaign'].get_model()
		columns = dict(enumerate(('UID',) + self.view_columns))
		export.liststore_to_csv(store, destination_file, columns)
		self.loader_thread_lock.release()
Ejemplo n.º 31
0
	def check_totp(self, _, window, entry, new_otp, this_user):
		if not new_otp.verify(entry.get_text().strip()):
			gui_utilities.show_dialog_warning(
				'Incorrect TOTP',
				self.application.get_active_window(),
				'The specified TOTP code is invalid. Make sure your time\n'\
				+ 'is correct, rescan the QR code and try again.'
			)
			return
		self.application.rpc.remote_table_row_set('users', this_user['id'], {'otp_secret': new_otp.secret})
		gui_utilities.show_dialog_info(
			'TOTP Enrollment',
			self.application.get_active_window(),
			'Successfully set the TOTP secret. Your account is now enrolled\n'\
			+ 'in two factor authentication. You will be prompted to enter the\n'
			+ 'value the next time you login.'
		)
		window.destroy()
Ejemplo n.º 32
0
	def _export_lock(self):
		show_dialog_warning = lambda: gui_utilities.show_dialog_warning('Export Failed', self.parent, 'Can not export data while loading.')
		if not self.loader_thread_lock.acquire(False):
			show_dialog_warning()
			return False
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			self.loader_thread_lock.release()
			show_dialog_warning()
			return False
		return True
Ejemplo n.º 33
0
	def _export_lock(self):
		show_dialog_warning = lambda: gui_utilities.show_dialog_warning('Export Failed', self.parent, 'Can not export data while loading.')
		if not self.loader_thread_lock.acquire(False):
			show_dialog_warning()
			return False
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			self.loader_thread_lock.release()
			show_dialog_warning()
			return False
		return True
Ejemplo n.º 34
0
 def check_totp(self, _, window, entry, new_otp, this_user):
     if not new_otp.verify(entry.get_text().strip()):
         gui_utilities.show_dialog_warning(
          'Incorrect TOTP',
          self.application.get_active_window(),
          'The specified TOTP code is invalid. Make sure your time\n'\
          + 'is correct, rescan the QR code and try again.'
         )
         return
     rpc.remote_table_row_set('users', this_user['id'],
                              {'otp_secret': new_otp.secret})
     gui_utilities.show_dialog_info(
      'TOTP Enrollment',
      self.application.get_active_window(),
      'Successfully set the TOTP secret. Your account is now enrolled\n'\
      + 'in two factor authentication. You will be prompted to enter the\n'
      + 'value the next time you login.'
     )
     window.destroy()
Ejemplo n.º 35
0
	def _prompt_to_delete_row(self, treeview, selection):
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent)
			return
		(model, tree_paths) = selection.get_selected_rows()
		if not tree_paths:
			return
		tree_iters = map(model.get_iter, tree_paths)
		row_ids = [model.get_value(ti, 0) for ti in tree_iters]
		if len(row_ids) == 1:
			message = 'Delete This Row?'
		else:
			message = "Delete These {0:,} Rows?".format(len(row_ids))
		if not gui_utilities.show_dialog_yes_no(message, self.parent, 'This information will be lost.'):
			return
		if len(row_ids) == 1:
			self.rpc('db/table/delete', self.remote_table_name, row_ids[0])
		else:
			self.rpc('db/table/delete/multi', self.remote_table_name, row_ids)
		self.load_campaign_information()
	def signal_button_clicked(self, button):
		campaign_name_entry = self.gobjects['entry_new_campaign_name']
		campaign_name = campaign_name_entry.get_property('text')
		if not campaign_name:
			gui_utilities.show_dialog_warning('Invalid Campaign Name', self.dialog, 'Please specify a new campaign name')
			return
		try:
			self.parent.rpc('campaign/new', campaign_name)
		except:
			gui_utilities.show_dialog_error('Failed To Create New Campaign', self.dialog, 'Encountered an error creating the new campaign')
			return
		campaign_name_entry.set_property('text', '')
		self.load_campaigns()
		treeview = self.gobjects['treeview_campaigns']
		store = treeview.get_model()
		store_iter = store.get_iter_first()
		while store_iter:
			if campaign_name == store.get_value(store_iter, 1):
				treeview.set_cursor(store.get_path(store_iter), None, False)
				break
			store_iter = store.iter_next(store_iter)
Ejemplo n.º 37
0
	def signal_button_clicked_verify_spf(self, button):
		sender_email = self.gobjects['entry_source_email_smtp'].get_text()

		if not utilities.is_valid_email_address(sender_email):
			gui_utilities.show_dialog_warning('Warning', self.parent, 'Can not check SPF records for an invalid source email address.\n')
			return True

		spf_test_ip = mailer.guess_smtp_server_address(self.config['smtp_server'], (self.config['ssh_server'] if self.config['smtp_ssh_enable'] else None))
		if not spf_test_ip:
			gui_utilities.show_dialog_warning('Warning', self.parent, 'Skipping spf policy check because the smtp server address could not be reliably detected')
			return True

		spf_test_sender, spf_test_domain = sender_email.split('@')
		try:
			spf_test = spf.SenderPolicyFramework(spf_test_ip, spf_test_domain, spf_test_sender)
			spf_result = spf_test.check_host()
		except spf.SPFError as error:
			gui_utilities.show_dialog_warning('Warning', self.parent, "Done, encountered exception: {0}.\n".format(error.__class__.__name__))
			return True

		if not spf_result:
			gui_utilities.show_dialog_info('SPF Check Results', self.parent, 'No SPF records found.')
		else:
			if spf_result is 'fail':
				gui_utilities.show_dialog_info('SPF Check Results:', self.parent, 'SPF exists with a hard fail. Your messages will probably be blocked.')
			elif spf_result is 'softfail':
				gui_utilities.show_dialog_info('SPF Check Results', self.parent, 'SPF Exists with a soft fail. Your messages have strong possiblity of being blocked. Check your logs.')
			return True
		return True
Ejemplo n.º 38
0
 def _sender_precheck_settings(self):
     required_settings = {
         'mailer.webserver_url': 'Web Server URL',
         'mailer.company_name': 'Company Name',
         'mailer.subject': 'Subject',
         'mailer.html_file': 'Message HTML File',
         'mailer.target_file': 'Target CSV File'
     }
     for setting, setting_name in required_settings.items():
         if not self.config.get(setting):
             gui_utilities.show_dialog_warning(
                 "Missing Required Option: '{0}'".format(setting_name),
                 self.parent,
                 'Return to the Config tab and set all required options')
             return
         if not setting.endswith('_file'):
             continue
         file_path = self.config[setting]
         if not (os.path.isfile(file_path)
                 and os.access(file_path, os.R_OK)):
             gui_utilities.show_dialog_warning(
                 'Invalid Option Configuration', self.parent,
                 "Setting: '{0}'\nReason: the file could not be read.".
                 format(setting_name))
             return False
     if not self.config.get('smtp_server'):
         gui_utilities.show_dialog_warning(
             'Missing SMTP Server Setting', self.parent,
             'Please configure the SMTP server')
         return False
     return True
Ejemplo n.º 39
0
	def signal_button_clicked_verify_spf(self, button):
		sender_email = self.gobjects['entry_source_email_smtp'].get_text()

		if not utilities.is_valid_email_address(sender_email):
			gui_utilities.show_dialog_warning('Warning', self.parent, 'Can not check SPF records for an invalid source email address.\n')
			return True

		spf_test_ip = mailer.guess_smtp_server_address(self.config['smtp_server'], (self.config['ssh_server'] if self.config['smtp_ssh_enable'] else None))
		if not spf_test_ip:
			gui_utilities.show_dialog_warning('Warning', self.parent, 'Skipping spf policy check because the smtp server address could not be reliably detected')
			return True

		spf_test_sender, spf_test_domain = sender_email.split('@')
		try:
			spf_test = spf.SenderPolicyFramework(spf_test_ip, spf_test_domain, spf_test_sender)
			spf_result = spf_test.check_host()
		except spf.SPFError as error:
			gui_utilities.show_dialog_warning('Warning', self.parent, "Done, encountered exception: {0}.\n".format(error.__class__.__name__))
			return True

		if not spf_result:
			gui_utilities.show_dialog_info('SPF Check Results', self.parent, 'No SPF records found.')
		else:
			if spf_result is 'fail':
				gui_utilities.show_dialog_info('SPF Check Results:', self.parent, 'SPF exists with a hard fail. Your messages will probably be blocked.')
			elif spf_result is 'softfail':
				gui_utilities.show_dialog_info('SPF Check Results', self.parent, 'SPF Exists with a soft fail. Your messages have strong possiblity of being blocked. Check your logs.')
			return True
		return True
Ejemplo n.º 40
0
	def _prompt_to_delete_row(self):
		selection = self.gobjects['treeview_campaign'].get_selection()
		if not selection.count_selected_rows():
			return
		if isinstance(self.loader_thread, threading.Thread) and self.loader_thread.is_alive():
			gui_utilities.show_dialog_warning('Can Not Delete Rows While Loading', self.parent)
			return
		(model, tree_paths) = selection.get_selected_rows()
		if not tree_paths:
			return

		tree_iters = map(model.get_iter, tree_paths)
		row_ids = map(lambda ti: model.get_value(ti, 0), tree_iters)
		if len(row_ids) == 1:
			message = 'Delete This Row?'
		else:
			message = "Delete These {0:,} Rows?".format(len(row_ids))
		if not gui_utilities.show_dialog_yes_no(message, self.parent, 'This information will be lost.'):
			return
		for row_id in row_ids:
			self.parent.rpc(self.remote_table_name + '/delete', row_id)
		self.load_campaign_information(force=True)
	def signal_button_clicked_sender_start(self, button):
		required_settings = {
			'mailer.webserver_url': 'Web Server URL',
			'mailer.company_name': 'Company Name',
			'mailer.source_email': 'Source Email',
			'mailer.subject': 'Friendly Alias',
			'mailer.html_file': 'Message HTML File',
			'mailer.target_file': 'Target CSV File'
		}
		for setting, setting_name in required_settings.items():
			if not self.config.get(setting):
				gui_utilities.show_dialog_warning("Missing Required Option: '{0}'".format(setting_name), self.parent, 'Return to the Config tab and set all required options')
				return
			if not setting.endswith('_file'):
				continue
			file_path = self.config[setting]
			if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
				gui_utilities.show_dialog_warning('Invalid Option Configuration', self.parent, "Setting: '{0}'\nReason: File could not be read".format(setting_name))
				return
		if not self.config.get('smtp_server'):
			gui_utilities.show_dialog_warning('Missing SMTP Server Setting', self.parent, 'Please configure the SMTP server')
			return
		if self.sender_thread:
			return
		self.parent.save_config()
		self.gobjects['button_mail_sender_start'].set_sensitive(False)
		self.gobjects['button_mail_sender_stop'].set_sensitive(True)
		self.progressbar.set_fraction(0)
		self.sender_thread = MailSenderThread(self.config, self.config['mailer.target_file'], self, self.parent.rpc)

		# Connect to the SMTP server
		if self.config['smtp_ssh_enable']:
			while True:
				self.text_insert('Connecting To SSH... ')
				login_dialog = KingPhisherClientSSHLoginDialog(self.config, self.parent)
				login_dialog.objects_load_from_config()
				response = login_dialog.interact()
				if response == Gtk.ResponseType.CANCEL:
					self.sender_start_failure(text='Canceled.\n')
					return
				if self.sender_thread.server_ssh_connect():
					self.text_insert('Done.\n')
					break
				self.sender_start_failure('Failed to connect to SSH', 'Failed.\n')
		self.text_insert('Connecting To SMTP Server... ')
		if not self.sender_thread.server_smtp_connect():
			self.sender_start_failure('Failed to connect to SMTP', 'Failed.\n')
			return
		self.text_insert('Done.\n')

		parsed_target_url = urlparse.urlparse(self.config['mailer.webserver_url'])
		landing_page_hostname = parsed_target_url.netloc
		landing_page = parsed_target_url.path
		landing_page = landing_page.lstrip('/')
		self.parent.rpc('campaign/landing_page/new', self.config['campaign_id'], landing_page_hostname, landing_page)

		self.sender_thread.start()
		self.gobjects['togglebutton_mail_sender_pause'].set_sensitive(True)
Ejemplo n.º 42
0
	def signal_button_clicked_verify(self, button):
		target_url = self.gobjects['entry_webserver_url'].get_text()
		try:
			test_webserver_url(target_url, self.config['server_config']['server.secret_id'])
		except Exception as error:
			error_description = None
			if isinstance(error, urllib.request.URLError) and hasattr(error, 'reason') and isinstance(error.reason, Exception):
				error = error.reason
			if isinstance(error, urllib.request.HTTPError) and error.getcode():
				self.logger.warning("verify url HTTPError: {0} {1}".format(error.getcode(), error.reason))
				error_description = "HTTP status {0} {1}".format(error.getcode(), error.reason)
			elif isinstance(error, socket.gaierror):
				self.logger.warning('verify url attempt failed, socket.gaierror')
				error_description = error.args[-1]
			elif isinstance(error, socket.timeout):
				self.logger.warning('verify url attempt failed, connection timeout occurred')
				error_description = 'Connection timed out'
			else:
				self.logger.warning('unknown verify url exception: ' + repr(error))
			gui_utilities.show_dialog_warning('Unable To Open The Web Server URL', self.parent, error_description)
			return
		gui_utilities.show_dialog_info('Successfully Opened The Web Server URL', self.parent)
		return
Ejemplo n.º 43
0
    def signal_button_clicked_verify(self, button):
        target_url = self.gobjects["entry_webserver_url"].get_text()
        error_description = None
        if re.match(r"^\s+", target_url):
            target_url = target_url.strip()
            self.gobjects["entry_webserver_url"].set_text(target_url)
        for _ in range(1):
            if not target_url.strip().startswith("http"):
                error_description = "The web server URL is invalid"
                break

            try:
                response = test_webserver_url(target_url, self.config["server_config"]["server.secret_id"])
            except (requests.exceptions.ConnectionError, requests.exceptions.RequestException) as error:
                if isinstance(error, requests.exceptions.ConnectionError):
                    self.logger.warning("verify url attempt failed, could not connect")
                    error_description = "Could not connect to the server"
                elif isinstance(error, requests.exceptions.Timeout):
                    self.logger.warning("verify url attempt failed, a timeout occurred")
                    error_description = "The HTTP request timed out"
                else:
                    self.logger.warning("unknown verify url exception: " + repr(error))
                    error_description = "An unknown verify URL exception occurred"
                break

            if not response.ok:
                self.logger.warning("verify url HTTP error: {0} {1}".format(response.status_code, response.reason))
                error_description = "HTTP status {0} {1}".format(response.status_code, response.reason)
                break

            self.logger.debug("verify url HTTP status: {0} {1}".format(response.status_code, response.reason))
        if error_description:
            gui_utilities.show_dialog_warning("Unable To Open The Web Server URL", self.parent, error_description)
        else:
            gui_utilities.show_dialog_info("Successfully Opened The Web Server URL", self.parent)
        return
Ejemplo n.º 44
0
	def signal_button_clicked_verify(self, button):
		target_url = self.gobjects['entry_webserver_url'].get_text()
		error_description = None
		if re.match(r'^\s+', target_url):
			target_url = target_url.strip()
			self.gobjects['entry_webserver_url'].set_text(target_url)
		for _ in range(1):
			if not target_url.strip().startswith('http'):
				error_description = 'The web server URL is invalid'
				break

			try:
				response = test_webserver_url(target_url, self.config['server_config']['server.secret_id'])
			except (requests.exceptions.ConnectionError, requests.exceptions.RequestException) as error:
				if isinstance(error, requests.exceptions.ConnectionError):
					self.logger.warning('verify url attempt failed, could not connect')
					error_description = 'Could not connect to the server'
				elif isinstance(error, requests.exceptions.Timeout):
					self.logger.warning('verify url attempt failed, a timeout occurred')
					error_description = 'The HTTP request timed out'
				else:
					self.logger.warning('unknown verify url exception: ' + repr(error))
					error_description = 'An unknown verify URL exception occurred'
				break

			if not response.ok:
				self.logger.warning("verify url HTTP error: {0} {1}".format(response.status_code, response.reason))
				error_description = "HTTP status {0} {1}".format(response.status_code, response.reason)
				break

			self.logger.debug("verify url HTTP status: {0} {1}".format(response.status_code, response.reason))
		if error_description:
			gui_utilities.show_dialog_warning('Unable To Open The Web Server URL', self.parent, error_description)
		else:
			gui_utilities.show_dialog_info('Successfully Opened The Web Server URL', self.parent)
		return
Ejemplo n.º 45
0
	def start_sftp_client(self):
		"""
		Start the client's preferred sftp client application.
		"""
		if not self.config['sftp_client']:
			gui_utilities.show_dialog_warning('Invalid SFTP Configuration', self, 'An SFTP client is not configured')
			return False
		command = str(self.config['sftp_client'])
		sftp_bin = shlex.split(command)[0]
		if not utilities.which(sftp_bin):
			self.logger.warning('could not locate the sftp binary: ' + sftp_bin)
			gui_utilities.show_dialog_warning('Invalid SFTP Configuration', self, "Could not find the SFTP binary '{0}'".format(sftp_bin))
			return False
		try:
			command = command.format(
				server=self.config['server'],
				username=self.config['server_username'],
				web_root=self.config['server_config']['server.web_root']
			)
		except KeyError:
			pass
		self.logger.debug("starting sftp client command: {0}".format(command))
		utilities.start_process(command, wait=False)
		return
Ejemplo n.º 46
0
	def _sender_precheck_settings(self):
		required_settings = {
			'mailer.webserver_url': 'Web Server URL',
			'mailer.subject': 'Subject',
			'mailer.html_file': 'Message HTML File',
			'mailer.target_file': 'Target CSV File'
		}
		for setting, setting_name in required_settings.items():
			if not self.config.get(setting):
				gui_utilities.show_dialog_warning("Missing Required Option: '{0}'".format(setting_name), self.parent, 'Return to the Config tab and set all required options')
				return
			if not setting.endswith('_file'):
				continue
			file_path = self.config[setting]
			if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
				gui_utilities.show_dialog_warning('Invalid Option Configuration', self.parent, "Setting: '{0}'\nReason: the file could not be read.".format(setting_name))
				return False
		if not self.config.get('smtp_server'):
			gui_utilities.show_dialog_warning('Missing SMTP Server Setting', self.parent, 'Please configure the SMTP server')
			return False
		return True
Ejemplo n.º 47
0
	def _sender_precheck_campaign(self):
		campaign = self.application.rpc.remote_table_row('campaigns', self.config['campaign_id'])
		if campaign.expiration and campaign.expiration < datetime.datetime.utcnow():
			gui_utilities.show_dialog_warning('Campaign Is Expired', self.parent, 'The current campaign has already expired')
			return False
		return True
Ejemplo n.º 48
0
	def _show_dialog_busy(self):
		gui_utilities.show_dialog_warning('Currently Busy', self.window, 'An operation is already running.')