diff options
author | Kali Kaneko <kali@leap.se> | 2013-08-12 13:25:44 +0200 |
---|---|---|
committer | Kali Kaneko <kali@leap.se> | 2013-08-12 13:25:44 +0200 |
commit | 6da8d09846db4d2eed01e488bc6a6f5ba48b959f (patch) | |
tree | 3b82e8c4e14b1730ff292b6eb632c145dafb332a /src/leap/gui | |
parent | 00d98a47c60764475d97df1c2eb847e20a77cae5 (diff) |
move everything into bitmask namespace
Diffstat (limited to 'src/leap/gui')
-rw-r--r-- | src/leap/gui/__init__.py | 21 | ||||
-rw-r--r-- | src/leap/gui/loggerwindow.py | 137 | ||||
-rw-r--r-- | src/leap/gui/login.py | 245 | ||||
-rw-r--r-- | src/leap/gui/mainwindow.py | 1537 | ||||
-rw-r--r-- | src/leap/gui/statuspanel.py | 459 | ||||
-rw-r--r-- | src/leap/gui/twisted_main.py | 60 | ||||
-rw-r--r-- | src/leap/gui/ui/loggerwindow.ui | 155 | ||||
-rw-r--r-- | src/leap/gui/ui/login.ui | 132 | ||||
-rw-r--r-- | src/leap/gui/ui/mainwindow.ui | 315 | ||||
-rw-r--r-- | src/leap/gui/ui/statuspanel.ui | 289 | ||||
-rw-r--r-- | src/leap/gui/ui/wizard.ui | 846 | ||||
-rw-r--r-- | src/leap/gui/wizard.py | 626 | ||||
-rw-r--r-- | src/leap/gui/wizardpage.py | 40 |
13 files changed, 0 insertions, 4862 deletions
diff --git a/src/leap/gui/__init__.py b/src/leap/gui/__init__.py deleted file mode 100644 index 4b289442..00000000 --- a/src/leap/gui/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# __init__.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -""" -init file for leap.gui -""" -app = __import__("app", globals(), locals(), [], 2) -__all__ = [app] diff --git a/src/leap/gui/loggerwindow.py b/src/leap/gui/loggerwindow.py deleted file mode 100644 index fcbdbf19..00000000 --- a/src/leap/gui/loggerwindow.py +++ /dev/null @@ -1,137 +0,0 @@ -# -*- coding: utf-8 -*- -# loggerwindow.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -History log window -""" -import logging - -from PySide import QtGui -from ui_loggerwindow import Ui_LoggerWindow -from leap.common.check import leap_assert, leap_assert_type -from leap.util.leap_log_handler import LeapLogHandler - -logger = logging.getLogger(__name__) - - -class LoggerWindow(QtGui.QDialog): - """ - Window that displays a history of the logged messages in the app. - """ - def __init__(self, handler): - """ - Initialize the widget with the custom handler. - - :param handler: Custom handler that supports history and signal. - :type handler: LeapLogHandler. - """ - QtGui.QDialog.__init__(self) - leap_assert(handler, "We need a handler for the logger window") - leap_assert_type(handler, LeapLogHandler) - - # Load UI - self.ui = Ui_LoggerWindow() - self.ui.setupUi(self) - - # Make connections - self.ui.btnSave.clicked.connect(self._save_log_to_file) - self.ui.btnDebug.toggled.connect(self._load_history), - self.ui.btnInfo.toggled.connect(self._load_history), - self.ui.btnWarning.toggled.connect(self._load_history), - self.ui.btnError.toggled.connect(self._load_history), - self.ui.btnCritical.toggled.connect(self._load_history) - - # Load logging history and connect logger with the widget - self._logging_handler = handler - self._connect_to_handler() - self._load_history() - - def _connect_to_handler(self): - """ - This method connects the loggerwindow with the handler through a - signal communicate the logger events. - """ - self._logging_handler.new_log.connect(self._add_log_line) - - def _add_log_line(self, log): - """ - Adds a line to the history, only if it's in the desired levels to show. - - :param log: a log record to be inserted in the widget - :type log: a dict with RECORD_KEY and MESSAGE_KEY. - the record contains the LogRecord of the logging module, - the message contains the formatted message for the log. - """ - html_style = { - logging.DEBUG: "background: #CDFFFF;", - logging.INFO: "background: white;", - logging.WARNING: "background: #FFFF66;", - logging.ERROR: "background: red; color: white;", - logging.CRITICAL: "background: red; color: white; font: bold;" - } - level = log[LeapLogHandler.RECORD_KEY].levelno - message = log[LeapLogHandler.MESSAGE_KEY] - message = message.replace('\n', '<br>\n') - - if self._logs_to_display[level]: - open_tag = "<tr style='" + html_style[level] + "'>" - open_tag += "<td width='100%' style='padding: 5px;'>" - close_tag = "</td></tr>" - message = open_tag + message + close_tag - - self.ui.txtLogHistory.append(message) - - def _load_history(self): - """ - Load the previous logged messages in the widget. - They are stored in the custom handler. - """ - self._set_logs_to_display() - self.ui.txtLogHistory.clear() - history = self._logging_handler.log_history - for line in history: - self._add_log_line(line) - - def _set_logs_to_display(self): - """ - Sets the logs_to_display dict getting the toggled options from the ui - """ - self._logs_to_display = { - logging.DEBUG: self.ui.btnDebug.isChecked(), - logging.INFO: self.ui.btnInfo.isChecked(), - logging.WARNING: self.ui.btnWarning.isChecked(), - logging.ERROR: self.ui.btnError.isChecked(), - logging.CRITICAL: self.ui.btnCritical.isChecked() - } - - def _save_log_to_file(self): - """ - Lets the user save the current log to a file - """ - fileName, filtr = QtGui.QFileDialog.getSaveFileName( - self, self.tr("Save As")) - - if fileName: - try: - with open(fileName, 'w') as output: - output.write(self.ui.txtLogHistory.toPlainText()) - output.write('\n') - logger.debug('Log saved in %s' % (fileName, )) - except IOError, e: - logger.error("Error saving log file: %r" % (e, )) - else: - logger.debug('Log not saved!') diff --git a/src/leap/gui/login.py b/src/leap/gui/login.py deleted file mode 100644 index de0b2d50..00000000 --- a/src/leap/gui/login.py +++ /dev/null @@ -1,245 +0,0 @@ -# -*- coding: utf-8 -*- -# login.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -Login widget implementation -""" -import logging - -from PySide import QtCore, QtGui -from ui_login import Ui_LoginWidget - -from leap.util.keyring_helpers import has_keyring - -logger = logging.getLogger(__name__) - - -class LoginWidget(QtGui.QWidget): - """ - Login widget that emits signals to display the wizard or to - perform login. - """ - - # Emitted when the login button is clicked - login = QtCore.Signal() - cancel_login = QtCore.Signal() - - # Emitted when the user selects "Other..." in the provider - # combobox or click "Create Account" - show_wizard = QtCore.Signal() - - MAX_STATUS_WIDTH = 40 - - BARE_USERNAME_REGEX = r"^[A-Za-z\d_]+$" - - def __init__(self, settings, parent=None): - """ - Constructs the LoginWidget. - - :param settings: client wide settings - :type settings: LeapSettings - :param parent: The parent widget for this widget - :type parent: QWidget or None - """ - QtGui.QWidget.__init__(self, parent) - - self._settings = settings - self._selected_provider_index = -1 - - self.ui = Ui_LoginWidget() - self.ui.setupUi(self) - - self.ui.chkRemember.stateChanged.connect( - self._remember_state_changed) - self.ui.chkRemember.setEnabled(has_keyring()) - - self.ui.lnPassword.setEchoMode(QtGui.QLineEdit.Password) - - self.ui.btnLogin.clicked.connect(self.login) - self.ui.lnPassword.returnPressed.connect(self.login) - - self.ui.lnUser.returnPressed.connect(self._focus_password) - - self.ui.cmbProviders.currentIndexChanged.connect( - self._current_provider_changed) - self.ui.btnCreateAccount.clicked.connect( - self.show_wizard) - - username_re = QtCore.QRegExp(self.BARE_USERNAME_REGEX) - self.ui.lnUser.setValidator( - QtGui.QRegExpValidator(username_re, self)) - - def _remember_state_changed(self, state): - """ - Saves the remember state in the LeapSettings - - :param state: possible stats can be Checked, Unchecked and - PartiallyChecked - :type state: QtCore.Qt.CheckState - """ - enable = True if state == QtCore.Qt.Checked else False - self._settings.set_remember(enable) - - def set_providers(self, provider_list): - """ - Set the provider list to provider_list plus an "Other..." item - that triggers the wizard - - :param provider_list: list of providers - :type provider_list: list of str - """ - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.clear() - self.ui.cmbProviders.addItems(provider_list + [self.tr("Other...")]) - self.ui.cmbProviders.blockSignals(False) - - def select_provider_by_name(self, name): - """ - Given a provider name/domain, it selects it in the combobox - - :param name: name or domain for the provider - :type name: str - """ - provider_index = self.ui.cmbProviders.findText(name) - self.ui.cmbProviders.setCurrentIndex(provider_index) - - def get_selected_provider(self): - """ - Returns the selected provider in the combobox - """ - return self.ui.cmbProviders.currentText() - - def set_remember(self, value): - """ - Checks the remember user and password checkbox - - :param value: True to mark it checked, False otherwise - :type value: bool - """ - self.ui.chkRemember.setChecked(value) - - def get_remember(self): - """ - Returns the remember checkbox state - - :rtype: bool - """ - return self.ui.chkRemember.isChecked() - - def set_user(self, user): - """ - Sets the user and focuses on the next field, password. - - :param user: user to set the field to - :type user: str - """ - self.ui.lnUser.setText(user) - self._focus_password() - - def get_user(self): - """ - Returns the user that appears in the widget. - - :rtype: str - """ - return self.ui.lnUser.text() - - def set_password(self, password): - """ - Sets the password for the widget - - :param password: password to set - :type password: str - """ - self.ui.lnPassword.setText(password) - - def get_password(self): - """ - Returns the password that appears in the widget - - :rtype: str - """ - return self.ui.lnPassword.text() - - def set_status(self, status, error=True): - """ - Sets the status label at the login stage to status - - :param status: status message - :type status: str - """ - if len(status) > self.MAX_STATUS_WIDTH: - status = status[:self.MAX_STATUS_WIDTH] + "..." - if error: - status = "<font color='red'><b>%s</b></font>" % (status,) - self.ui.lblStatus.setText(status) - - def set_enabled(self, enabled=False): - """ - Enables or disables all the login widgets - - :param enabled: wether they should be enabled or not - :type enabled: bool - """ - self.ui.lnUser.setEnabled(enabled) - self.ui.lnPassword.setEnabled(enabled) - self.ui.chkRemember.setEnabled(enabled) - self.ui.cmbProviders.setEnabled(enabled) - - self._set_cancel(not enabled) - - def _set_cancel(self, enabled=False): - """ - Enables or disables the cancel action in the "log in" process. - - :param enabled: wether it should be enabled or not - :type enabled: bool - """ - text = self.tr("Cancel") - login_or_cancel = self.cancel_login - - if not enabled: - text = self.tr("Log In") - login_or_cancel = self.login - - self.ui.btnLogin.setText(text) - - self.ui.btnLogin.clicked.disconnect() - self.ui.btnLogin.clicked.connect(login_or_cancel) - - def _focus_password(self): - """ - Focuses in the password lineedit - """ - self.ui.lnPassword.setFocus() - - def _current_provider_changed(self, param): - """ - SLOT - TRIGGERS: self.ui.cmbProviders.currentIndexChanged - """ - if param == (self.ui.cmbProviders.count() - 1): - self.show_wizard.emit() - # Leave the previously selected provider in the combobox - prev_provider = 0 - if self._selected_provider_index != -1: - prev_provider = self._selected_provider_index - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.setCurrentIndex(prev_provider) - self.ui.cmbProviders.blockSignals(False) - else: - self._selected_provider_index = param diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py deleted file mode 100644 index 5ace1043..00000000 --- a/src/leap/gui/mainwindow.py +++ /dev/null @@ -1,1537 +0,0 @@ -# -*- coding: utf-8 -*- -# mainwindow.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -Main window for the leap client -""" -import logging -import os -import platform -import tempfile -from functools import partial - -import keyring - -from PySide import QtCore, QtGui -from twisted.internet import threads - -from leap.common.check import leap_assert -from leap.common.events import register -from leap.common.events import events_pb2 as proto -from leap.config.leapsettings import LeapSettings -from leap.config.providerconfig import ProviderConfig -from leap.crypto.srpauth import SRPAuth -from leap.gui.loggerwindow import LoggerWindow -from leap.gui.wizard import Wizard -from leap.gui.login import LoginWidget -from leap.gui.statuspanel import StatusPanelWidget -from leap.services.eip.eipbootstrapper import EIPBootstrapper -from leap.services.eip.eipconfig import EIPConfig -from leap.services.eip.providerbootstrapper import ProviderBootstrapper -# XXX: Soledad might not work out of the box in Windows, issue #2932 -from leap.services.soledad.soledadbootstrapper import SoledadBootstrapper -from leap.services.mail.smtpbootstrapper import SMTPBootstrapper -from leap.services.mail import imap -from leap.platform_init import IS_WIN, IS_MAC -from leap.platform_init.initializers import init_platform - -from leap.services.eip.vpnprocess import VPN -from leap.services.eip.vpnprocess import OpenVPNAlreadyRunning -from leap.services.eip.vpnprocess import AlienOpenVPNAlreadyRunning - -from leap.services.eip.vpnlaunchers import VPNLauncherException -from leap.services.eip.vpnlaunchers import OpenVPNNotFoundException -from leap.services.eip.vpnlaunchers import EIPNoPkexecAvailable -from leap.services.eip.vpnlaunchers import EIPNoPolkitAuthAgentAvailable -from leap.services.eip.vpnlaunchers import EIPNoTunKextLoaded - -from leap.util import __version__ as VERSION -from leap.util.keyring_helpers import has_keyring - -from leap.services.mail.smtpconfig import SMTPConfig - -if IS_WIN: - from leap.platform_init.locks import WindowsLock - from leap.platform_init.locks import raise_window_ack - -from ui_mainwindow import Ui_MainWindow - -logger = logging.getLogger(__name__) - - -class MainWindow(QtGui.QMainWindow): - """ - Main window for login and presenting status updates to the user - """ - - # StackedWidget indexes - LOGIN_INDEX = 0 - EIP_STATUS_INDEX = 1 - - # Keyring - KEYRING_KEY = "bitmask" - - # SMTP - PORT_KEY = "port" - IP_KEY = "ip_address" - - OPENVPN_SERVICE = "openvpn" - MX_SERVICE = "mx" - - # Signals - new_updates = QtCore.Signal(object) - raise_window = QtCore.Signal([]) - soledad_ready = QtCore.Signal([]) - - # We use this flag to detect abnormal terminations - user_stopped_eip = False - - def __init__(self, quit_callback, - standalone=False, - openvpn_verb=1, - bypass_checks=False): - """ - Constructor for the client main window - - :param quit_callback: Function to be called when closing - the application. - :type quit_callback: callable - - :param standalone: Set to true if the app should use configs - inside its pwd - :type standalone: bool - - :param bypass_checks: Set to true if the app should bypass - first round of checks for CA - certificates at bootstrap - :type bypass_checks: bool - """ - QtGui.QMainWindow.__init__(self) - - # register leap events - register(signal=proto.UPDATER_NEW_UPDATES, - callback=self._new_updates_available, - reqcbk=lambda req, resp: None) # make rpc call async - register(signal=proto.RAISE_WINDOW, - callback=self._on_raise_window_event, - reqcbk=lambda req, resp: None) # make rpc call async - - self._quit_callback = quit_callback - - self._updates_content = "" - - self.ui = Ui_MainWindow() - self.ui.setupUi(self) - - self._settings = LeapSettings(standalone) - - self._login_widget = LoginWidget( - self._settings, - self.ui.stackedWidget.widget(self.LOGIN_INDEX)) - self.ui.loginLayout.addWidget(self._login_widget) - - # Signals - # TODO separate logic from ui signals. - - self._login_widget.login.connect(self._login) - self._login_widget.cancel_login.connect(self._cancel_login) - self._login_widget.show_wizard.connect( - self._launch_wizard) - - self.ui.btnShowLog.clicked.connect(self._show_logger_window) - - self._status_panel = StatusPanelWidget( - self.ui.stackedWidget.widget(self.EIP_STATUS_INDEX)) - self.ui.statusLayout.addWidget(self._status_panel) - - self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX) - - self._status_panel.start_eip.connect(self._start_eip) - self._status_panel.stop_eip.connect(self._stop_eip) - - # This is loaded only once, there's a bug when doing that more - # than once - ProviderConfig.standalone = standalone - EIPConfig.standalone = standalone - self._standalone = standalone - self._provider_config = ProviderConfig() - # Used for automatic start of EIP - self._provisional_provider_config = ProviderConfig() - self._eip_config = EIPConfig() - - self._already_started_eip = False - - # This is created once we have a valid provider config - self._srp_auth = None - self._logged_user = None - - # This thread is always running, although it's quite - # lightweight when it's done setting up provider - # configuration and certificate. - self._provider_bootstrapper = ProviderBootstrapper(bypass_checks) - - # Intermediate stages, only do something if there was an error - self._provider_bootstrapper.name_resolution.connect( - self._intermediate_stage) - self._provider_bootstrapper.https_connection.connect( - self._intermediate_stage) - self._provider_bootstrapper.download_ca_cert.connect( - self._intermediate_stage) - - # Important stages, loads the provider config and checks - # certificates - self._provider_bootstrapper.download_provider_info.connect( - self._load_provider_config) - self._provider_bootstrapper.check_api_certificate.connect( - self._provider_config_loaded) - - # This thread is similar to the provider bootstrapper - self._eip_bootstrapper = EIPBootstrapper() - - self._eip_bootstrapper.download_config.connect( - self._eip_intermediate_stage) - self._eip_bootstrapper.download_client_certificate.connect( - self._finish_eip_bootstrap) - - self._soledad_bootstrapper = SoledadBootstrapper() - self._soledad_bootstrapper.download_config.connect( - self._soledad_intermediate_stage) - self._soledad_bootstrapper.gen_key.connect( - self._soledad_bootstrapped_stage) - - self._smtp_bootstrapper = SMTPBootstrapper() - self._smtp_bootstrapper.download_config.connect( - self._smtp_bootstrapped_stage) - - self._vpn = VPN(openvpn_verb=openvpn_verb) - self._vpn.qtsigs.state_changed.connect( - self._status_panel.update_vpn_state) - self._vpn.qtsigs.status_changed.connect( - self._status_panel.update_vpn_status) - self._vpn.qtsigs.process_finished.connect( - self._eip_finished) - - self.ui.action_log_out.setEnabled(False) - self.ui.action_log_out.triggered.connect(self._logout) - self.ui.action_about_leap.triggered.connect(self._about) - self.ui.action_quit.triggered.connect(self.quit) - self.ui.action_wizard.triggered.connect(self._launch_wizard) - self.ui.action_show_logs.triggered.connect(self._show_logger_window) - self.raise_window.connect(self._do_raise_mainwindow) - - # Used to differentiate between real quits and close to tray - self._really_quit = False - - self._systray = None - - self._action_eip_provider = QtGui.QAction( - self.tr("No default provider"), self) - self._action_eip_provider.setEnabled(False) - self._action_eip_status = QtGui.QAction( - self.tr("Encrypted internet is OFF"), - self) - self._action_eip_status.setEnabled(False) - - self._status_panel.set_action_eip_status( - self._action_eip_status) - - self._action_eip_startstop = QtGui.QAction( - self.tr("Turn OFF"), self) - self._action_eip_startstop.triggered.connect( - self._stop_eip) - self._action_eip_startstop.setEnabled(False) - self._status_panel.set_action_eip_startstop( - self._action_eip_startstop) - - self._action_visible = QtGui.QAction(self.tr("Hide Main Window"), self) - self._action_visible.triggered.connect(self._toggle_visible) - - self._enabled_services = [] - - self._center_window() - - self.ui.lblNewUpdates.setVisible(False) - self.ui.btnMore.setVisible(False) - self.ui.btnMore.clicked.connect(self._updates_details) - - self.new_updates.connect(self._react_to_new_updates) - self.soledad_ready.connect(self._start_imap_service) - - init_platform() - - self._wizard = None - self._wizard_firstrun = False - - self._logger_window = None - - self._bypass_checks = bypass_checks - - self._soledad = None - self._keymanager = None - self._imap_service = None - - self._login_defer = None - self._download_provider_defer = None - - self._smtp_config = SMTPConfig() - - if self._first_run(): - self._wizard_firstrun = True - self._wizard = Wizard(standalone=standalone, - bypass_checks=bypass_checks) - # Give this window time to finish init and then show the wizard - QtCore.QTimer.singleShot(1, self._launch_wizard) - self._wizard.accepted.connect(self._finish_init) - self._wizard.rejected.connect(self._rejected_wizard) - else: - self._finish_init() - - def _rejected_wizard(self): - """ - SLOT - TRIGGERS: self._wizard.rejected - - Called if the wizard has been cancelled or closed before - finishing. - """ - if self._wizard_firstrun: - self._settings.set_properprovider(False) - self.quit() - else: - self._finish_init() - - def _launch_wizard(self): - """ - SLOT - TRIGGERS: - self._login_widget.show_wizard - self.ui.action_wizard.triggered - - Also called in first run. - - Launches the wizard, creating the object itself if not already - there. - """ - if self._wizard is None: - self._wizard = Wizard(bypass_checks=self._bypass_checks) - self._wizard.accepted.connect(self._finish_init) - self._wizard.rejected.connect(self._wizard.close) - - self.setVisible(False) - # Do NOT use exec_, it will use a child event loop! - # Refer to http://www.themacaque.com/?p=1067 for funny details. - self._wizard.show() - if IS_MAC: - self._wizard.raise_() - self._wizard.finished.connect(self._wizard_finished) - - def _wizard_finished(self): - """ - SLOT - TRIGGERS - self._wizard.finished - - Called when the wizard has finished. - """ - self.setVisible(True) - - def _get_leap_logging_handler(self): - """ - Gets the leap handler from the top level logger - - :return: a logging handler or None - :rtype: LeapLogHandler or None - """ - from leap.util.leap_log_handler import LeapLogHandler - leap_logger = logging.getLogger('leap') - for h in leap_logger.handlers: - if isinstance(h, LeapLogHandler): - return h - return None - - def _show_logger_window(self): - """ - SLOT - TRIGGERS: - self.ui.action_show_logs.triggered - self.ui.btnShowLog.clicked - - Displays the window with the history of messages logged until now - and displays the new ones on arrival. - """ - if self._logger_window is None: - leap_log_handler = self._get_leap_logging_handler() - if leap_log_handler is None: - logger.error('Leap logger handler not found') - else: - self._logger_window = LoggerWindow(handler=leap_log_handler) - self._logger_window.setVisible( - not self._logger_window.isVisible()) - self.ui.btnShowLog.setChecked(self._logger_window.isVisible()) - else: - self._logger_window.setVisible(not self._logger_window.isVisible()) - self.ui.btnShowLog.setChecked(self._logger_window.isVisible()) - - self._logger_window.finished.connect(self._uncheck_logger_button) - - def _uncheck_logger_button(self): - """ - SLOT - Sets the checked state of the loggerwindow button to false. - """ - self.ui.btnShowLog.setChecked(False) - - def _new_updates_available(self, req): - """ - Callback for the new updates event - - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest - """ - self.new_updates.emit(req) - - def _react_to_new_updates(self, req): - """ - SLOT - TRIGGER: self._new_updates_available - - Displays the new updates label and sets the updates_content - """ - self.moveToThread(QtCore.QCoreApplication.instance().thread()) - self.ui.lblNewUpdates.setVisible(True) - self.ui.btnMore.setVisible(True) - self._updates_content = req.content - - def _updates_details(self): - """ - SLOT - TRIGGER: self.ui.btnMore.clicked - - Parses and displays the updates details - """ - msg = self.tr("The Bitmask app is ready to update, please" - " restart the application.") - - # We assume that if there is nothing in the contents, then - # the Bitmask bundle is what needs updating. - if len(self._updates_content) > 0: - files = self._updates_content.split(", ") - files_str = "" - for f in files: - final_name = f.replace("/data/", "") - final_name = final_name.replace(".thp", "") - files_str += final_name - files_str += "\n" - msg += self.tr(" The following components will be updated:\n%s") \ - % (files_str,) - - QtGui.QMessageBox.information(self, - self.tr("Updates available"), - msg) - - def _finish_init(self): - """ - SLOT - TRIGGERS: - self._wizard.accepted - - Also called at the end of the constructor if not first run, - and after _rejected_wizard if not first run. - - Implements the behavior after either constructing the - mainwindow object, loading the saved user/password, or after - the wizard has been executed. - """ - # XXX: May be this can be divided into two methods? - - self._login_widget.set_providers(self._configured_providers()) - self._show_systray() - self.show() - if IS_MAC: - self.raise_() - - if self._wizard: - possible_username = self._wizard.get_username() - possible_password = self._wizard.get_password() - - # select the configured provider in the combo box - domain = self._wizard.get_domain() - self._login_widget.select_provider_by_name(domain) - - self._login_widget.set_remember(self._wizard.get_remember()) - self._enabled_services = list(self._wizard.get_services()) - self._settings.set_enabled_services( - self._login_widget.get_selected_provider(), - self._enabled_services) - if possible_username is not None: - self._login_widget.set_user(possible_username) - if possible_password is not None: - self._login_widget.set_password(possible_password) - self._login() - self._wizard = None - self._settings.set_properprovider(True) - else: - self._try_autostart_eip() - if not self._settings.get_remember(): - # nothing to do here - return - - saved_user = self._settings.get_user() - - try: - username, domain = saved_user.split('@') - except (ValueError, AttributeError) as e: - # if the saved_user does not contain an '@' or its None - logger.error('Username@provider malformed. %r' % (e, )) - saved_user = None - - if saved_user is not None and has_keyring(): - # fill the username - self._login_widget.set_user(username) - - # select the configured provider in the combo box - self._login_widget.select_provider_by_name(domain) - - self._login_widget.set_remember(True) - - saved_password = None - try: - saved_password = keyring.get_password(self.KEYRING_KEY, - saved_user - .encode("utf8")) - except ValueError, e: - logger.debug("Incorrect Password. %r." % (e,)) - - if saved_password is not None: - self._login_widget.set_password( - saved_password.decode("utf8")) - self._login() - - def _try_autostart_eip(self): - """ - Tries to autostart EIP - """ - default_provider = self._settings.get_defaultprovider() - - if default_provider is None: - logger.info("Cannot autostart Encrypted Internet because there is " - "no default provider configured") - return - - self._action_eip_provider.setText(default_provider) - - self._enabled_services = self._settings.get_enabled_services( - default_provider) - - if self._provisional_provider_config.load( - os.path.join("leap", - "providers", - default_provider, - "provider.json")): - self._download_eip_config() - else: - # XXX: Display a proper message to the user - logger.error("Unable to load %s config, cannot autostart." % - (default_provider,)) - - def _show_systray(self): - """ - Sets up the systray icon - """ - if self._systray is not None: - self._systray.setVisible(True) - return - - # Placeholder actions - # They are temporary to display the tray as designed - preferences_action = QtGui.QAction(self.tr("Preferences"), self) - preferences_action.setEnabled(False) - help_action = QtGui.QAction(self.tr("Help"), self) - help_action.setEnabled(False) - - systrayMenu = QtGui.QMenu(self) - systrayMenu.addAction(self._action_visible) - systrayMenu.addSeparator() - systrayMenu.addAction(self._action_eip_provider) - systrayMenu.addAction(self._action_eip_status) - systrayMenu.addAction(self._action_eip_startstop) - systrayMenu.addSeparator() - systrayMenu.addAction(preferences_action) - systrayMenu.addAction(help_action) - systrayMenu.addSeparator() - systrayMenu.addAction(self.ui.action_log_out) - systrayMenu.addAction(self.ui.action_quit) - self._systray = QtGui.QSystemTrayIcon(self) - self._systray.setContextMenu(systrayMenu) - self._systray.setIcon(self._status_panel.ERROR_ICON_TRAY) - self._systray.setVisible(True) - self._systray.activated.connect(self._tray_activated) - - self._status_panel.set_systray(self._systray) - - def _tray_activated(self, reason=None): - """ - SLOT - TRIGGER: self._systray.activated - - Displays the context menu from the tray icon - """ - self._update_hideshow_menu() - - context_menu = self._systray.contextMenu() - if not IS_MAC: - # for some reason, context_menu.show() - # is failing in a way beyond my understanding. - # (not working the first time it's clicked). - # this works however. - context_menu.exec_(self._systray.geometry().center()) - - def _update_hideshow_menu(self): - """ - Updates the Hide/Show main window menu text based on the - visibility of the window. - """ - get_action = lambda visible: ( - self.tr("Show Main Window"), - self.tr("Hide Main Window"))[int(visible)] - - # set labels - visible = self.isVisible() - self._action_visible.setText(get_action(visible)) - - def _toggle_visible(self): - """ - SLOT - TRIGGER: self._action_visible.triggered - - Toggles the window visibility - """ - if not self.isVisible(): - self.show() - self.raise_() - else: - self.hide() - - self._update_hideshow_menu() - - def _center_window(self): - """ - Centers the mainwindow based on the desktop geometry - """ - geometry = self._settings.get_geometry() - state = self._settings.get_windowstate() - - if geometry is None: - app = QtGui.QApplication.instance() - width = app.desktop().width() - height = app.desktop().height() - window_width = self.size().width() - window_height = self.size().height() - x = (width / 2.0) - (window_width / 2.0) - y = (height / 2.0) - (window_height / 2.0) - self.move(x, y) - else: - self.restoreGeometry(geometry) - - if state is not None: - self.restoreState(state) - - def _about(self): - """ - SLOT - TRIGGERS: self.ui.action_about_leap.triggered - - Display the About Bitmask dialog - """ - QtGui.QMessageBox.about( - self, self.tr("About Bitmask - %s") % (VERSION,), - self.tr("Version: <b>%s</b><br>" - "<br>" - "Bitmask is the Desktop client application for " - "the LEAP platform, supporting encrypted internet " - "proxy, secure email, and secure chat (coming soon).<br>" - "<br>" - "LEAP is a non-profit dedicated to giving " - "all internet users access to secure " - "communication. Our focus is on adapting " - "encryption technology to make it easy to use " - "and widely available. <br>" - "<br>" - "<a href='https://leap.se'>More about LEAP" - "</a>") % (VERSION,)) - - def changeEvent(self, e): - """ - Reimplements the changeEvent method to minimize to tray - """ - if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ - e.type() == QtCore.QEvent.WindowStateChange and \ - self.isMinimized(): - self._toggle_visible() - e.accept() - return - QtGui.QMainWindow.changeEvent(self, e) - - def closeEvent(self, e): - """ - Reimplementation of closeEvent to close to tray - """ - if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ - not self._really_quit: - self._toggle_visible() - e.ignore() - return - - self._settings.set_geometry(self.saveGeometry()) - self._settings.set_windowstate(self.saveState()) - - QtGui.QMainWindow.closeEvent(self, e) - - def _configured_providers(self): - """ - Returns the available providers based on the file structure - - :rtype: list - """ - - # TODO: check which providers have a valid certificate among - # other things, not just the directories - providers = [] - try: - providers = os.listdir( - os.path.join(self._provider_config.get_path_prefix(), - "leap", - "providers")) - except Exception as e: - logger.debug("Error listing providers, assume there are none. %r" - % (e,)) - - return providers - - def _first_run(self): - """ - Returns True if there are no configured providers. False otherwise - - :rtype: bool - """ - has_provider_on_disk = len(self._configured_providers()) != 0 - is_proper_provider = self._settings.get_properprovider() - return not (has_provider_on_disk and is_proper_provider) - - def _download_provider_config(self): - """ - Starts the bootstrapping sequence. It will download the - provider configuration if it's not present, otherwise will - emit the corresponding signals inmediately - """ - provider = self._login_widget.get_selected_provider() - - pb = self._provider_bootstrapper - d = pb.run_provider_select_checks(provider, download_if_needed=True) - self._download_provider_defer = d - - def _load_provider_config(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.download_provider_info - - Once the provider config has been downloaded, this loads the - self._provider_config instance with it and starts the second - part of the bootstrapping sequence - - :param data: result from the last stage of the - run_provider_select_checks - :type data: dict - """ - if data[self._provider_bootstrapper.PASSED_KEY]: - provider = self._login_widget.get_selected_provider() - - # If there's no loaded provider or - # we want to connect to other provider... - if (not self._provider_config.loaded() or - self._provider_config.get_domain() != provider): - self._provider_config.load( - os.path.join("leap", "providers", - provider, "provider.json")) - - if self._provider_config.loaded(): - self._provider_bootstrapper.run_provider_setup_checks( - self._provider_config, - download_if_needed=True) - else: - self._login_widget.set_status( - self.tr("Unable to login: Problem with provider")) - logger.error("Could not load provider configuration.") - self._login_widget.set_enabled(True) - else: - self._login_widget.set_status( - self.tr("Unable to login: Problem with provider")) - logger.error(data[self._provider_bootstrapper.ERROR_KEY]) - self._login_widget.set_enabled(True) - - def _login(self): - """ - SLOT - TRIGGERS: - self._login_widget.login - - Starts the login sequence. Which involves bootstrapping the - selected provider if the selection is valid (not empty), then - start the SRP authentication, and as the last step - bootstrapping the EIP service - """ - leap_assert(self._provider_config, "We need a provider config") - - username = self._login_widget.get_user() - password = self._login_widget.get_password() - provider = self._login_widget.get_selected_provider() - - self._enabled_services = self._settings.get_enabled_services( - self._login_widget.get_selected_provider()) - - if len(provider) == 0: - self._login_widget.set_status( - self.tr("Please select a valid provider")) - return - - if len(username) == 0: - self._login_widget.set_status( - self.tr("Please provide a valid username")) - return - - if len(password) == 0: - self._login_widget.set_status( - self.tr("Please provide a valid Password")) - return - - self._login_widget.set_status(self.tr("Logging in..."), error=False) - self._login_widget.set_enabled(False) - - if self._login_widget.get_remember() and has_keyring(): - # in the keyring and in the settings - # we store the value 'usename@provider' - username_domain = (username + '@' + provider).encode("utf8") - try: - keyring.set_password(self.KEYRING_KEY, - username_domain, - password.encode("utf8")) - # Only save the username if it was saved correctly in - # the keyring - self._settings.set_user(username_domain) - except Exception as e: - logger.error("Problem saving data to keyring. %r" - % (e,)) - - self._download_provider_config() - - def _cancel_login(self): - """ - SLOT - TRIGGERS: - self._login_widget.cancel_login - - Stops the login sequence. - """ - logger.debug("Cancelling log in.") - - if self._download_provider_defer: - logger.debug("Cancelling download provider defer.") - self._download_provider_defer.cancel() - - if self._login_defer: - logger.debug("Cancelling login defer.") - self._login_defer.cancel() - - def _provider_config_loaded(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.check_api_certificate - - Once the provider configuration is loaded, this starts the SRP - authentication - """ - leap_assert(self._provider_config, "We need a provider config!") - - if data[self._provider_bootstrapper.PASSED_KEY]: - username = self._login_widget.get_user().encode("utf8") - password = self._login_widget.get_password().encode("utf8") - - if self._srp_auth is None: - self._srp_auth = SRPAuth(self._provider_config) - self._srp_auth.authentication_finished.connect( - self._authentication_finished) - self._srp_auth.logout_finished.connect( - self._done_logging_out) - - # TODO: Add errback! - self._login_defer = self._srp_auth.authenticate(username, password) - else: - self._login_widget.set_status( - "Unable to login: Problem with provider") - logger.error(data[self._provider_bootstrapper.ERROR_KEY]) - self._login_widget.set_enabled(True) - - def _authentication_finished(self, ok, message): - """ - SLOT - TRIGGER: self._srp_auth.authentication_finished - - Once the user is properly authenticated, try starting the EIP - service - """ - - # In general we want to "filter" likely complicated error - # messages, but in this case, the messages make more sense as - # they come. Since they are "Unknown user" or "Unknown - # password" - self._login_widget.set_status(message, error=not ok) - - if ok: - self._logged_user = self._login_widget.get_user() - self.ui.action_log_out.setEnabled(True) - # We leave a bit of room for the user to see the - # "Succeeded" message and then we switch to the EIP status - # panel - QtCore.QTimer.singleShot(1000, self._switch_to_status) - self._login_defer = None - else: - self._login_widget.set_enabled(True) - - def _switch_to_status(self): - """ - Changes the stackedWidget index to the EIP status one and - triggers the eip bootstrapping - """ - if not self._already_started_eip: - self._status_panel.set_provider( - "%s@%s" % (self._login_widget.get_user(), - self._get_best_provider_config().get_domain())) - - self.ui.stackedWidget.setCurrentIndex(self.EIP_STATUS_INDEX) - - self._soledad_bootstrapper.run_soledad_setup_checks( - self._provider_config, - self._login_widget.get_user(), - self._login_widget.get_password(), - download_if_needed=True, - standalone=self._standalone) - - self._download_eip_config() - - def _soledad_intermediate_stage(self, data): - """ - SLOT - TRIGGERS: - self._soledad_bootstrapper.download_config - - If there was a problem, displays it, otherwise it does nothing. - This is used for intermediate bootstrapping stages, in case - they fail. - """ - passed = data[self._soledad_bootstrapper.PASSED_KEY] - if not passed: - # TODO: display in the GUI: - # should pass signal to a slot in status_panel - # that sets the global status - logger.warning("Soledad failed to start: %s" % - (data[self._soledad_bootstrapper.ERROR_KEY],)) - - def _soledad_bootstrapped_stage(self, data): - """ - SLOT - TRIGGERS: - self._soledad_bootstrapper.gen_key - - If there was a problem, displays it, otherwise it does nothing. - This is used for intermediate bootstrapping stages, in case - they fail. - - :param data: result from the bootstrapping stage for Soledad - :type data: dict - """ - passed = data[self._soledad_bootstrapper.PASSED_KEY] - if not passed: - logger.error(data[self._soledad_bootstrapper.ERROR_KEY]) - return - - logger.debug("Done bootstrapping Soledad") - - self._soledad = self._soledad_bootstrapper.soledad - self._keymanager = self._soledad_bootstrapper.keymanager - - # Ok, now soledad is ready, so we can allow other things that - # depend on soledad to start. - - # this will trigger start_imap_service - self.soledad_ready.emit() - - # TODO connect all these activations to the soledad_ready - # signal so the logic is clearer to follow. - - if self._provider_config.provides_mx() and \ - self._enabled_services.count(self.MX_SERVICE) > 0: - self._smtp_bootstrapper.run_smtp_setup_checks( - self._provider_config, - self._smtp_config, - True) - else: - if self._enabled_services.count(self.MX_SERVICE) > 0: - pass # TODO: show MX status - #self._status_panel.set_eip_status( - # self.tr("%s does not support MX") % - # (self._provider_config.get_domain(),), - # error=True) - else: - pass # TODO: show MX status - #self._status_panel.set_eip_status( - # self.tr("MX is disabled")) - - # Service control methods: smtp - - def _smtp_bootstrapped_stage(self, data): - """ - SLOT - TRIGGERS: - self._smtp_bootstrapper.download_config - - If there was a problem, displays it, otherwise it does nothing. - This is used for intermediate bootstrapping stages, in case - they fail. - - :param data: result from the bootstrapping stage for Soledad - :type data: dict - """ - passed = data[self._smtp_bootstrapper.PASSED_KEY] - if not passed: - logger.error(data[self._smtp_bootstrapper.ERROR_KEY]) - return - logger.debug("Done bootstrapping SMTP") - - hosts = self._smtp_config.get_hosts() - # TODO: handle more than one host and define how to choose - if len(hosts) > 0: - hostname = hosts.keys()[0] - logger.debug("Using hostname %s for SMTP" % (hostname,)) - host = hosts[hostname][self.IP_KEY].encode("utf-8") - port = hosts[hostname][self.PORT_KEY] - # TODO: pick local smtp port in a better way - # TODO: Make the encrypted_only configurable - - from leap.mail.smtp import setup_smtp_relay - client_cert = self._eip_config.get_client_cert_path( - self._provider_config) - setup_smtp_relay(port=2013, - keymanager=self._keymanager, - smtp_host=host, - smtp_port=port, - smtp_cert=client_cert, - smtp_key=client_cert, - encrypted_only=False) - - def _start_imap_service(self): - """ - SLOT - TRIGGERS: - soledad_ready - """ - logger.debug('Starting imap service') - - self._imap_service = imap.start_imap_service( - self._soledad, - self._keymanager) - - def _get_socket_host(self): - """ - Returns the socket and port to be used for VPN - - :rtype: tuple (str, str) (host, port) - """ - - # TODO: make this properly multiplatform - - if platform.system() == "Windows": - host = "localhost" - port = "9876" - else: - host = os.path.join(tempfile.mkdtemp(prefix="leap-tmp"), - 'openvpn.socket') - port = "unix" - - return host, port - - def _start_eip(self): - """ - SLOT - TRIGGERS: - self._status_panel.start_eip - self._action_eip_startstop.triggered - or called from _finish_eip_bootstrap - - Starts EIP - """ - self._status_panel.eip_pre_up() - self.user_stopped_eip = False - provider_config = self._get_best_provider_config() - - try: - host, port = self._get_socket_host() - self._vpn.start(eipconfig=self._eip_config, - providerconfig=provider_config, - socket_host=host, - socket_port=port) - - self._settings.set_defaultprovider( - provider_config.get_domain()) - - provider = provider_config.get_domain() - if self._logged_user is not None: - provider = "%s@%s" % (self._logged_user, provider) - - self._status_panel.set_provider(provider) - - self._action_eip_provider.setText(provider_config.get_domain()) - - self._status_panel.eip_started() - - # XXX refactor into status_panel method? - self._action_eip_startstop.setText(self.tr("Turn OFF")) - self._action_eip_startstop.disconnect(self) - self._action_eip_startstop.triggered.connect( - self._stop_eip) - except EIPNoPolkitAuthAgentAvailable: - self._status_panel.set_global_status( - # XXX this should change to polkit-kde where - # applicable. - self.tr("We could not find any " - "authentication " - "agent in your system.<br/>" - "Make sure you have " - "<b>polkit-gnome-authentication-" - "agent-1</b> " - "running and try again."), - error=True) - self._set_eipstatus_off() - except EIPNoTunKextLoaded: - self._status_panel.set_global_status( - self.tr("Encrypted Internet cannot be started because " - "the tuntap extension is not installed properly " - "in your system.")) - self._set_eipstatus_off() - except EIPNoPkexecAvailable: - self._status_panel.set_global_status( - self.tr("We could not find <b>pkexec</b> " - "in your system."), - error=True) - self._set_eipstatus_off() - except OpenVPNNotFoundException: - self._status_panel.set_global_status( - self.tr("We could not find openvpn binary."), - error=True) - self._set_eipstatus_off() - except OpenVPNAlreadyRunning as e: - self._status_panel.set_global_status( - self.tr("Another openvpn instance is already running, and " - "could not be stopped."), - error=True) - self._set_eipstatus_off() - except AlienOpenVPNAlreadyRunning as e: - self._status_panel.set_global_status( - self.tr("Another openvpn instance is already running, and " - "could not be stopped because it was not launched by " - "Bitmask. Please stop it and try again."), - error=True) - self._set_eipstatus_off() - except VPNLauncherException as e: - # XXX We should implement again translatable exceptions so - # we can pass a translatable string to the panel (usermessage attr) - self._status_panel.set_global_status("%s" % (e,), error=True) - self._set_eipstatus_off() - else: - self._already_started_eip = True - - def _set_eipstatus_off(self): - """ - Sets eip status to off - """ - self._status_panel.set_eip_status(self.tr("OFF"), error=True) - self._status_panel.set_eip_status_icon("error") - self._status_panel.set_startstop_enabled(True) - self._status_panel.eip_stopped() - - self._set_action_eipstart_off() - - def _set_action_eipstart_off(self): - """ - Sets eip startstop action to OFF status. - """ - self._action_eip_startstop.setText(self.tr("Turn ON")) - self._action_eip_startstop.disconnect(self) - self._action_eip_startstop.triggered.connect( - self._start_eip) - - def _stop_eip(self, abnormal=False): - """ - SLOT - TRIGGERS: - self._status_panel.stop_eip - self._action_eip_startstop.triggered - or called from _eip_finished - - Stops vpn process and makes gui adjustments to reflect - the change of state. - - :param abnormal: whether this was an abnormal termination. - :type abnormal: bool - """ - if abnormal: - logger.warning("Abnormal EIP termination.") - - self.user_stopped_eip = True - self._vpn.terminate() - - self._set_eipstatus_off() - - self._already_started_eip = False - self._settings.set_defaultprovider(None) - if self._logged_user: - self._status_panel.set_provider( - "%s@%s" % (self._logged_user, - self._get_best_provider_config().get_domain())) - - def _get_best_provider_config(self): - """ - Returns the best ProviderConfig to use at a moment. We may - have to use self._provider_config or - self._provisional_provider_config depending on the start - status. - - :rtype: ProviderConfig - """ - leap_assert(self._provider_config is not None or - self._provisional_provider_config is not None, - "We need a provider config") - - provider_config = None - if self._provider_config.loaded(): - provider_config = self._provider_config - elif self._provisional_provider_config.loaded(): - provider_config = self._provisional_provider_config - else: - leap_assert(False, "We could not find any usable ProviderConfig.") - - return provider_config - - def _download_eip_config(self): - """ - Starts the EIP bootstrapping sequence - """ - leap_assert(self._eip_bootstrapper, "We need an eip bootstrapper!") - - provider_config = self._get_best_provider_config() - - if provider_config.provides_eip() and \ - self._enabled_services.count(self.OPENVPN_SERVICE) > 0 and \ - not self._already_started_eip: - - self._status_panel.set_eip_status( - self.tr("Starting...")) - self._eip_bootstrapper.run_eip_setup_checks( - provider_config, - download_if_needed=True) - self._already_started_eip = True - elif not self._already_started_eip: - if self._enabled_services.count(self.OPENVPN_SERVICE) > 0: - self._status_panel.set_eip_status( - self.tr("Not supported"), - error=True) - else: - self._status_panel.set_eip_status(self.tr("Disabled")) - self._status_panel.set_startstop_enabled(False) - - def _finish_eip_bootstrap(self, data): - """ - SLOT - TRIGGER: self._eip_bootstrapper.download_client_certificate - - Starts the VPN thread if the eip configuration is properly - loaded - """ - leap_assert(self._eip_config, "We need an eip config!") - passed = data[self._eip_bootstrapper.PASSED_KEY] - - if not passed: - error_msg = self.tr("There was a problem with the provider") - self._status_panel.set_eip_status(error_msg, error=True) - logger.error(data[self._eip_bootstrapper.ERROR_KEY]) - self._already_started_eip = False - return - - provider_config = self._get_best_provider_config() - - domain = provider_config.get_domain() - - loaded = self._eip_config.loaded() - if not loaded: - eip_config_path = os.path.join("leap", "providers", - domain, "eip-service.json") - api_version = provider_config.get_api_version() - self._eip_config.set_api_version(api_version) - loaded = self._eip_config.load(eip_config_path) - - if loaded: - self._start_eip() - else: - self._status_panel.set_eip_status( - self.tr("Could not load Encrypted Internet " - "Configuration."), - error=True) - - def _logout(self): - """ - SLOT - TRIGGER: self.ui.action_log_out.triggered - - Starts the logout sequence - """ - # XXX: If other defers are doing authenticated stuff, this - # might conflict with those. CHECK! - threads.deferToThread(self._srp_auth.logout) - - def _done_logging_out(self, ok, message): - """ - SLOT - TRIGGER: self._srp_auth.logout_finished - - Switches the stackedWidget back to the login stage after - logging out - """ - self._logged_user = None - self.ui.action_log_out.setEnabled(False) - self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX) - self._login_widget.set_password("") - self._login_widget.set_enabled(True) - self._login_widget.set_status("") - - def _intermediate_stage(self, data): - """ - SLOT - TRIGGERS: - self._provider_bootstrapper.name_resolution - self._provider_bootstrapper.https_connection - self._provider_bootstrapper.download_ca_cert - self._eip_bootstrapper.download_config - - If there was a problem, displays it, otherwise it does nothing. - This is used for intermediate bootstrapping stages, in case - they fail. - """ - passed = data[self._provider_bootstrapper.PASSED_KEY] - if not passed: - self._login_widget.set_enabled(True) - self._login_widget.set_status( - self.tr("Unable to connect: Problem with provider")) - logger.error(data[self._provider_bootstrapper.ERROR_KEY]) - - def _eip_intermediate_stage(self, data): - """ - SLOT - TRIGGERS: - self._eip_bootstrapper.download_config - - If there was a problem, displays it, otherwise it does nothing. - This is used for intermediate bootstrapping stages, in case - they fail. - """ - passed = data[self._provider_bootstrapper.PASSED_KEY] - if not passed: - self._login_widget.set_status( - self.tr("Unable to connect: Problem with provider")) - logger.error(data[self._provider_bootstrapper.ERROR_KEY]) - self._already_started_eip = False - - def _eip_finished(self, exitCode): - """ - SLOT - TRIGGERS: - self._vpn.process_finished - - Triggered when the EIP/VPN process finishes to set the UI - accordingly. - """ - logger.info("VPN process finished with exitCode %s..." - % (exitCode,)) - - # Ideally we would have the right exit code here, - # but the use of different wrappers (pkexec, cocoasudo) swallows - # the openvpn exit code so we get zero exit in some cases where we - # shouldn't. As a workaround we just use a flag to indicate - # a purposeful switch off, and mark everything else as unexpected. - - # In the near future we should trigger a native notification from here, - # since the user really really wants to know she is unprotected asap. - # And the right thing to do will be to fail-close. - - # TODO we should have a way of parsing the latest lines in the vpn - # log buffer so we can have a more precise idea of which type - # of error did we have (server side, local problem, etc) - abnormal = True - - # XXX check if these exitCodes are pkexec/cocoasudo specific - if exitCode in (126, 127): - self._status_panel.set_global_status( - self.tr("Encrypted Internet could not be launched " - "because you did not authenticate properly."), - error=True) - self._vpn.killit() - elif exitCode != 0 or not self.user_stopped_eip: - self._status_panel.set_global_status( - self.tr("Encrypted Internet finished in an " - "unexpected manner!"), error=True) - else: - abnormal = False - if exitCode == 0 and IS_MAC: - # XXX remove this warning after I fix cocoasudo. - logger.warning("The above exit code MIGHT BE WRONG.") - self._stop_eip(abnormal) - - def _on_raise_window_event(self, req): - """ - Callback for the raise window event - """ - if IS_WIN: - raise_window_ack() - self.raise_window.emit() - - def _do_raise_mainwindow(self): - """ - SLOT - TRIGGERS: - self._on_raise_window_event - - Triggered when we receive a RAISE_WINDOW event. - """ - TOPFLAG = QtCore.Qt.WindowStaysOnTopHint - self.setWindowFlags(self.windowFlags() | TOPFLAG) - self.show() - self.setWindowFlags(self.windowFlags() & ~TOPFLAG) - self.show() - if IS_MAC: - self.raise_() - - def _cleanup_pidfiles(self): - """ - Removes lockfiles on a clean shutdown. - - Triggered after aboutToQuit signal. - """ - if IS_WIN: - WindowsLock.release_all_locks() - - def _cleanup_and_quit(self): - """ - Call all the cleanup actions in a serialized way. - Should be called from the quit function. - """ - logger.debug('About to quit, doing cleanup...') - - if self._imap_service is not None: - self._imap_service.stop() - - if self._srp_auth is not None: - if self._srp_auth.get_session_id() is not None or \ - self._srp_auth.get_token() is not None: - # XXX this can timeout after loong time: See #3368 - self._srp_auth.logout() - - if self._soledad: - logger.debug("Closing soledad...") - self._soledad.close() - else: - logger.error("No instance of soledad was found.") - - logger.debug('Terminating vpn') - self._vpn.terminate(shutdown=True) - - if self._login_defer: - logger.debug("Cancelling login defer.") - self._login_defer.cancel() - - if self._download_provider_defer: - logger.debug("Cancelling download provider defer.") - self._download_provider_defer.cancel() - - # TODO missing any more cancels? - - logger.debug('Cleaning pidfiles') - self._cleanup_pidfiles() - - def quit(self): - """ - Cleanup and tidely close the main window before quitting. - """ - # TODO: separate the shutting down of services from the - # UI stuff. - self._cleanup_and_quit() - - self._really_quit = True - - if self._wizard: - self._wizard.close() - - if self._logger_window: - self._logger_window.close() - - self.close() - - if self._quit_callback: - self._quit_callback() - - logger.debug('Bye.') - - -if __name__ == "__main__": - import signal - - def sigint_handler(*args, **kwargs): - logger.debug('SIGINT catched. shutting down...') - mainwindow = args[0] - mainwindow.quit() - - import sys - - logger = logging.getLogger(name='leap') - logger.setLevel(logging.DEBUG) - console = logging.StreamHandler() - console.setLevel(logging.DEBUG) - formatter = logging.Formatter( - '%(asctime)s ' - '- %(name)s - %(levelname)s - %(message)s') - console.setFormatter(formatter) - logger.addHandler(console) - - app = QtGui.QApplication(sys.argv) - mainwindow = MainWindow() - mainwindow.show() - - timer = QtCore.QTimer() - timer.start(500) - timer.timeout.connect(lambda: None) - - sigint = partial(sigint_handler, mainwindow) - signal.signal(signal.SIGINT, sigint) - - sys.exit(app.exec_()) diff --git a/src/leap/gui/statuspanel.py b/src/leap/gui/statuspanel.py deleted file mode 100644 index f3424c7c..00000000 --- a/src/leap/gui/statuspanel.py +++ /dev/null @@ -1,459 +0,0 @@ -# -*- coding: utf-8 -*- -# statuspanel.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -Status Panel widget implementation -""" -import logging - -from datetime import datetime -from functools import partial -from PySide import QtCore, QtGui - -from ui_statuspanel import Ui_StatusPanel - -from leap.common.check import leap_assert_type -from leap.services.eip.vpnprocess import VPNManager -from leap.platform_init import IS_WIN, IS_LINUX -from leap.util import first - -logger = logging.getLogger(__name__) - - -class RateMovingAverage(object): - """ - Moving window average for calculating - upload and download rates. - """ - SAMPLE_SIZE = 5 - - def __init__(self): - """ - Initializes an empty array of fixed size - """ - self.reset() - - def reset(self): - self._data = [None for i in xrange(self.SAMPLE_SIZE)] - - def append(self, x): - """ - Appends a new data point to the collection. - - :param x: A tuple containing timestamp and traffic points - in the form (timestamp, traffic) - :type x: tuple - """ - self._data.pop(0) - self._data.append(x) - - def get(self): - """ - Gets the collection. - """ - return self._data - - def get_average(self): - """ - Gets the moving average. - """ - data = filter(None, self.get()) - traff = [traffic for (ts, traffic) in data] - times = [ts for (ts, traffic) in data] - - try: - deltatraffic = traff[-1] - first(traff) - deltat = (times[-1] - first(times)).seconds - except IndexError: - deltatraffic = 0 - deltat = 0 - - try: - rate = float(deltatraffic) / float(deltat) / 1024 - except ZeroDivisionError: - rate = 0 - - # In some cases we get negative rates - if rate < 0: - rate = 0 - - return rate - - def get_total(self): - """ - Gets the total accumulated throughput. - """ - try: - return self._data[-1][1] / 1024 - except TypeError: - return 0 - - -class StatusPanelWidget(QtGui.QWidget): - """ - Status widget that displays the current state of the LEAP services - """ - - start_eip = QtCore.Signal() - stop_eip = QtCore.Signal() - - DISPLAY_TRAFFIC_RATES = True - RATE_STR = "%14.2f KB/s" - TOTAL_STR = "%14.2f Kb" - - def __init__(self, parent=None): - QtGui.QWidget.__init__(self, parent) - - self._systray = None - self._action_eip_status = None - - self.ui = Ui_StatusPanel() - self.ui.setupUi(self) - - self.ui.btnEipStartStop.setEnabled(False) - self.ui.btnEipStartStop.clicked.connect( - self.start_eip) - - self.hide_status_box() - - # Set the EIP status icons - self.CONNECTING_ICON = None - self.CONNECTED_ICON = None - self.ERROR_ICON = None - self.CONNECTING_ICON_TRAY = None - self.CONNECTED_ICON_TRAY = None - self.ERROR_ICON_TRAY = None - self._set_eip_icons() - - self._set_traffic_rates() - self._make_status_clickable() - - def _make_status_clickable(self): - """ - Makes upload and download figures clickable. - """ - onclicked = self._on_VPN_status_clicked - self.ui.btnUpload.clicked.connect(onclicked) - self.ui.btnDownload.clicked.connect(onclicked) - - def _on_VPN_status_clicked(self): - """ - SLOT - TRIGGER: self.ui.btnUpload.clicked - self.ui.btnDownload.clicked - - Toggles between rate and total throughput display for vpn - status figures. - """ - self.DISPLAY_TRAFFIC_RATES = not self.DISPLAY_TRAFFIC_RATES - self.update_vpn_status(None) # refresh - - def _set_traffic_rates(self): - """ - Initializes up and download rates. - """ - self._up_rate = RateMovingAverage() - self._down_rate = RateMovingAverage() - - self.ui.btnUpload.setText(self.RATE_STR % (0,)) - self.ui.btnDownload.setText(self.RATE_STR % (0,)) - - def _reset_traffic_rates(self): - """ - Resets up and download rates, and cleans up the labels. - """ - self._up_rate.reset() - self._down_rate.reset() - self.update_vpn_status(None) - - def _update_traffic_rates(self, up, down): - """ - Updates up and download rates. - - :param up: upload total. - :type up: int - :param down: download total. - :type down: int - """ - ts = datetime.now() - self._up_rate.append((ts, up)) - self._down_rate.append((ts, down)) - - def _get_traffic_rates(self): - """ - Gets the traffic rates (in KB/s). - - :returns: a tuple with the (up, down) rates - :rtype: tuple - """ - up = self._up_rate - down = self._down_rate - - return (up.get_average(), down.get_average()) - - def _get_traffic_totals(self): - """ - Gets the traffic total throughput (in Kb). - - :returns: a tuple with the (up, down) totals - :rtype: tuple - """ - up = self._up_rate - down = self._down_rate - - return (up.get_total(), down.get_total()) - - def _set_eip_icons(self): - """ - Sets the EIP status icons for the main window and for the tray - - MAC : dark icons - LINUX : dark icons in window, light icons in tray - WIN : light icons - """ - EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/conn_connecting-light.png", - ":/images/conn_connected-light.png", - ":/images/conn_error-light.png") - - if IS_LINUX: - EIP_ICONS_TRAY = ( - ":/images/conn_connecting.png", - ":/images/conn_connected.png", - ":/images/conn_error.png") - elif IS_WIN: - EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/conn_connecting.png", - ":/images/conn_connected.png", - ":/images/conn_error.png") - - self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) - self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) - self.ERROR_ICON = QtGui.QPixmap(EIP_ICONS[2]) - - self.CONNECTING_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[0]) - self.CONNECTED_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[1]) - self.ERROR_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[2]) - - def set_systray(self, systray): - """ - Sets the systray object to use. - - :param systray: Systray object - :type systray: QtGui.QSystemTrayIcon - """ - leap_assert_type(systray, QtGui.QSystemTrayIcon) - self._systray = systray - - def set_action_eip_startstop(self, action_eip_startstop): - """ - Sets the action_eip_startstop to use. - - :param action_eip_startstop: action_eip_status to be used - :type action_eip_startstop: QtGui.QAction - """ - self._action_eip_startstop = action_eip_startstop - - def set_action_eip_status(self, action_eip_status): - """ - Sets the action_eip_status to use. - - :param action_eip_status: action_eip_status to be used - :type action_eip_status: QtGui.QAction - """ - leap_assert_type(action_eip_status, QtGui.QAction) - self._action_eip_status = action_eip_status - - def set_global_status(self, status, error=False): - """ - Sets the global status label. - - :param status: status message - :type status: str or unicode - :param error: if the status is an erroneous one, then set this - to True - :type error: bool - """ - leap_assert_type(error, bool) - if error: - status = "<font color='red'><b>%s</b></font>" % (status,) - self.ui.lblGlobalStatus.setText(status) - self.ui.globalStatusBox.show() - - def hide_status_box(self): - """ - Hide global status box. - """ - self.ui.globalStatusBox.hide() - - def set_eip_status(self, status, error=False): - """ - Sets the status label at the VPN stage to status - - :param status: status message - :type status: str or unicode - :param error: if the status is an erroneous one, then set this - to True - :type error: bool - """ - leap_assert_type(error, bool) - - self._systray.setToolTip(status) - if error: - status = "<font color='red'>%s</font>" % (status,) - self.ui.lblEIPStatus.setText(status) - - def set_startstop_enabled(self, value): - """ - Enable or disable btnEipStartStop and _action_eip_startstop - based on value - - :param value: True for enabled, False otherwise - :type value: bool - """ - leap_assert_type(value, bool) - self.ui.btnEipStartStop.setEnabled(value) - self._action_eip_startstop.setEnabled(value) - - def eip_pre_up(self): - """ - Triggered when the app activates eip. - Hides the status box and disables the start/stop button. - """ - self.hide_status_box() - self.set_startstop_enabled(False) - - def eip_started(self): - """ - Sets the state of the widget to how it should look after EIP - has started - """ - self.ui.btnEipStartStop.setText(self.tr("Turn OFF")) - self.ui.btnEipStartStop.disconnect(self) - self.ui.btnEipStartStop.clicked.connect( - self.stop_eip) - - def eip_stopped(self): - """ - Sets the state of the widget to how it should look after EIP - has stopped - """ - self._reset_traffic_rates() - self.ui.btnEipStartStop.setText(self.tr("Turn ON")) - self.ui.btnEipStartStop.disconnect(self) - self.ui.btnEipStartStop.clicked.connect( - self.start_eip) - - def set_icon(self, icon): - """ - Sets the icon to display for EIP - - :param icon: icon to display - :type icon: QPixmap - """ - self.ui.lblVPNStatusIcon.setPixmap(icon) - - def update_vpn_status(self, data): - """ - SLOT - TRIGGER: VPN.status_changed - - Updates the download/upload labels based on the data provided - by the VPN thread. - - :param data: a dictionary with the tcp/udp write and read totals. - If data is None, we just will refresh the display based - on the previous data. - :type data: dict - """ - if data: - upload = float(data[VPNManager.TCPUDP_WRITE_KEY] or "0") - download = float(data[VPNManager.TCPUDP_READ_KEY] or "0") - self._update_traffic_rates(upload, download) - - if self.DISPLAY_TRAFFIC_RATES: - uprate, downrate = self._get_traffic_rates() - upload_str = self.RATE_STR % (uprate,) - download_str = self.RATE_STR % (downrate,) - - else: # display total throughput - uptotal, downtotal = self._get_traffic_totals() - upload_str = self.TOTAL_STR % (uptotal,) - download_str = self.TOTAL_STR % (downtotal,) - - self.ui.btnUpload.setText(upload_str) - self.ui.btnDownload.setText(download_str) - - def update_vpn_state(self, data): - """ - SLOT - TRIGGER: VPN.state_changed - - Updates the displayed VPN state based on the data provided by - the VPN thread - """ - status = data[VPNManager.STATUS_STEP_KEY] - self.set_eip_status_icon(status) - if status == "CONNECTED": - self.set_eip_status(self.tr("ON")) - # Only now we can properly enable the button. - self.set_startstop_enabled(True) - elif status == "AUTH": - self.set_eip_status(self.tr("Authenticating...")) - elif status == "GET_CONFIG": - self.set_eip_status(self.tr("Retrieving configuration...")) - elif status == "WAIT": - self.set_eip_status(self.tr("Waiting to start...")) - elif status == "ASSIGN_IP": - self.set_eip_status(self.tr("Assigning IP")) - elif status == "ALREADYRUNNING": - # Put the following calls in Qt's event queue, otherwise - # the UI won't update properly - QtCore.QTimer.singleShot(0, self.stop_eip) - QtCore.QTimer.singleShot(0, partial(self.set_global_status, - self.tr("Unable to start VPN, " - "it's already " - "running."))) - else: - self.set_eip_status(status) - - def set_eip_status_icon(self, status): - """ - Given a status step from the VPN thread, set the icon properly - - :param status: status step - :type status: str - """ - selected_pixmap = self.ERROR_ICON - selected_pixmap_tray = self.ERROR_ICON_TRAY - tray_message = self.tr("Encryption is OFF") - if status in ("WAIT", "AUTH", "GET_CONFIG", - "RECONNECTING", "ASSIGN_IP"): - selected_pixmap = self.CONNECTING_ICON - selected_pixmap_tray = self.CONNECTING_ICON_TRAY - tray_message = self.tr("Turning ON") - elif status in ("CONNECTED"): - tray_message = self.tr("Encryption is ON") - selected_pixmap = self.CONNECTED_ICON - selected_pixmap_tray = self.CONNECTED_ICON_TRAY - - self.set_icon(selected_pixmap) - self._systray.setIcon(QtGui.QIcon(selected_pixmap_tray)) - self._action_eip_status.setText(tray_message) - - def set_provider(self, provider): - self.ui.lblProvider.setText(provider) diff --git a/src/leap/gui/twisted_main.py b/src/leap/gui/twisted_main.py deleted file mode 100644 index c7add3ee..00000000 --- a/src/leap/gui/twisted_main.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# twisted_main.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -""" -Main functions for integration of twisted reactor -""" -import logging - -from twisted.internet import error - -# Resist the temptation of putting the import reactor here, -# it will raise an "reactor already imported" error. - -logger = logging.getLogger(__name__) - - -def start(app): - """ - Start the mainloop. - - :param app: the main qt QApplication instance. - :type app: QtCore.QApplication - """ - from twisted.internet import reactor - logger.debug('starting twisted reactor') - - # this seems to be troublesome under some - # unidentified settings. - #reactor.run() - - reactor.runReturn() - app.exec_() - - -def quit(app): - """ - Stop the mainloop. - - :param app: the main qt QApplication instance. - :type app: QtCore.QApplication - """ - from twisted.internet import reactor - logger.debug('stopping twisted reactor') - try: - reactor.stop() - except error.ReactorNotRunning: - logger.debug('reactor not running') diff --git a/src/leap/gui/ui/loggerwindow.ui b/src/leap/gui/ui/loggerwindow.ui deleted file mode 100644 index b08428a9..00000000 --- a/src/leap/gui/ui/loggerwindow.ui +++ /dev/null @@ -1,155 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>LoggerWindow</class> - <widget class="QWidget" name="LoggerWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>648</width> - <height>469</height> - </rect> - </property> - <property name="windowTitle"> - <string>Logs</string> - </property> - <property name="windowIcon"> - <iconset resource="../../../../data/resources/mainwindow.qrc"> - <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0" colspan="2"> - <widget class="QTextBrowser" name="txtLogHistory"/> - </item> - <item row="0" column="0" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QPushButton" name="btnDebug"> - <property name="text"> - <string>Debug</string> - </property> - <property name="icon"> - <iconset resource="../../../../data/resources/loggerwindow.qrc"> - <normaloff>:/images/oxygen-icons/script-error.png</normaloff>:/images/oxygen-icons/script-error.png</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnInfo"> - <property name="text"> - <string>Info</string> - </property> - <property name="icon"> - <iconset resource="../../../../data/resources/loggerwindow.qrc"> - <normaloff>:/images/oxygen-icons/dialog-information.png</normaloff>:/images/oxygen-icons/dialog-information.png</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnWarning"> - <property name="text"> - <string>Warning</string> - </property> - <property name="icon"> - <iconset resource="../../../../data/resources/loggerwindow.qrc"> - <normaloff>:/images/oxygen-icons/dialog-warning.png</normaloff>:/images/oxygen-icons/dialog-warning.png</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnError"> - <property name="text"> - <string>Error</string> - </property> - <property name="icon"> - <iconset resource="../../../../data/resources/loggerwindow.qrc"> - <normaloff>:/images/oxygen-icons/dialog-error.png</normaloff>:/images/oxygen-icons/dialog-error.png</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnCritical"> - <property name="text"> - <string>Critical</string> - </property> - <property name="icon"> - <iconset resource="../../../../data/resources/loggerwindow.qrc"> - <normaloff>:/images/oxygen-icons/edit-bomb.png</normaloff>:/images/oxygen-icons/edit-bomb.png</iconset> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnSave"> - <property name="text"> - <string>Save to file</string> - </property> - <property name="icon"> - <iconset resource="../../../../data/resources/loggerwindow.qrc"> - <normaloff>:/images/oxygen-icons/document-save-as.png</normaloff>:/images/oxygen-icons/document-save-as.png</iconset> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <tabstops> - <tabstop>btnDebug</tabstop> - <tabstop>btnInfo</tabstop> - <tabstop>btnWarning</tabstop> - <tabstop>btnError</tabstop> - <tabstop>btnCritical</tabstop> - <tabstop>btnSave</tabstop> - <tabstop>txtLogHistory</tabstop> - </tabstops> - <resources> - <include location="../../../../data/resources/loggerwindow.qrc"/> - <include location="../../../../data/resources/mainwindow.qrc"/> - </resources> - <connections/> -</ui> diff --git a/src/leap/gui/ui/login.ui b/src/leap/gui/ui/login.ui deleted file mode 100644 index 42a6897a..00000000 --- a/src/leap/gui/ui/login.ui +++ /dev/null @@ -1,132 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>LoginWidget</class> - <widget class="QWidget" name="LoginWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>356</width> - <height>223</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="5" column="2"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QComboBox" name="cmbProviders"/> - </item> - <item row="5" column="0"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="6" column="1"> - <widget class="QPushButton" name="btnCreateAccount"> - <property name="text"> - <string>Create a new account</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string><b>Provider:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="3" column="1" colspan="2"> - <widget class="QLineEdit" name="lnPassword"> - <property name="inputMask"> - <string/> - </property> - </widget> - </item> - <item row="2" column="1" colspan="2"> - <widget class="QLineEdit" name="lnUser"/> - </item> - <item row="4" column="1" colspan="2"> - <widget class="QCheckBox" name="chkRemember"> - <property name="text"> - <string>Remember username and password</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string><b>Username:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string><b>Password:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QPushButton" name="btnLogin"> - <property name="text"> - <string>Log In</string> - </property> - </widget> - </item> - <item row="0" column="0" colspan="3"> - <widget class="QLabel" name="lblStatus"> - <property name="text"> - <string/> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>cmbProviders</tabstop> - <tabstop>lnUser</tabstop> - <tabstop>lnPassword</tabstop> - <tabstop>chkRemember</tabstop> - <tabstop>btnLogin</tabstop> - <tabstop>btnCreateAccount</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/src/leap/gui/ui/mainwindow.ui b/src/leap/gui/ui/mainwindow.ui deleted file mode 100644 index ecd3cbe9..00000000 --- a/src/leap/gui/ui/mainwindow.ui +++ /dev/null @@ -1,315 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>429</width> - <height>579</height> - </rect> - </property> - <property name="windowTitle"> - <string>Bitmask</string> - </property> - <property name="windowIcon"> - <iconset resource="../../../../data/resources/mainwindow.qrc"> - <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> - </property> - <property name="inputMethodHints"> - <set>Qt::ImhHiddenText</set> - </property> - <property name="iconSize"> - <size> - <width>128</width> - <height>128</height> - </size> - </property> - <widget class="QWidget" name="centralwidget"> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="5"> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="2" column="0"> - <spacer name="horizontalSpacer_8"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <spacer name="horizontalSpacer_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="1"> - <widget class="QLabel" name="lblNewUpdates"> - <property name="text"> - <string>There are new updates available, please restart.</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QPushButton" name="btnMore"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>More...</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="2" column="3"> - <spacer name="horizontalSpacer_9"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="6" column="2"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="10" column="0" colspan="5"> - <widget class="QStackedWidget" name="stackedWidget"> - <property name="currentIndex"> - <number>1</number> - </property> - <widget class="QWidget" name="loginPage"> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="1"> - <layout class="QHBoxLayout" name="loginLayout"/> - </item> - <item row="0" column="2"> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="page_2"> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="statusLayout"/> - </item> - </layout> - </widget> - </widget> - </item> - <item row="7" column="2"> - <widget class="QLabel" name="label"> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/mask-launcher.png</pixmap> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item row="7" column="3" colspan="2"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="17" column="2"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="7" column="0" colspan="2"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="18" column="2"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <spacer name="horizontalSpacer_10"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="btnShowLog"> - <property name="text"> - <string>Show Log</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>false</bool> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QMenuBar" name="menubar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>429</width> - <height>21</height> - </rect> - </property> - <widget class="QMenu" name="menuSession"> - <property name="title"> - <string>&Session</string> - </property> - <addaction name="action_log_out"/> - <addaction name="separator"/> - <addaction name="action_quit"/> - </widget> - <widget class="QMenu" name="menuHelp"> - <property name="title"> - <string>Help</string> - </property> - <addaction name="action_help"/> - <addaction name="separator"/> - <addaction name="action_about_leap"/> - </widget> - <addaction name="menuSession"/> - <addaction name="menuHelp"/> - </widget> - <widget class="QStatusBar" name="statusbar"/> - <action name="action_log_out"> - <property name="text"> - <string>Log &out</string> - </property> - </action> - <action name="action_quit"> - <property name="text"> - <string>&Quit</string> - </property> - </action> - <action name="action_about_leap"> - <property name="text"> - <string>About &Bitmask</string> - </property> - </action> - <action name="action_help"> - <property name="text"> - <string>&Help</string> - </property> - </action> - <action name="action_wizard"> - <property name="text"> - <string>&Wizard</string> - </property> - </action> - <action name="action_show_logs"> - <property name="text"> - <string>Show &logs</string> - </property> - </action> - </widget> - <resources> - <include location="../../../../data/resources/mainwindow.qrc"/> - <include location="../../../../data/resources/locale.qrc"/> - </resources> - <connections/> -</ui> diff --git a/src/leap/gui/ui/statuspanel.ui b/src/leap/gui/ui/statuspanel.ui deleted file mode 100644 index 3482ac7c..00000000 --- a/src/leap/gui/ui/statuspanel.ui +++ /dev/null @@ -1,289 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>StatusPanel</class> - <widget class="QWidget" name="StatusPanel"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>384</width> - <height>477</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="lblProvider"> - <property name="styleSheet"> - <string notr="true">font: bold;</string> - </property> - <property name="text"> - <string>user@domain.org</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QWidget" name="status_rows" native="true"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="1"> - <layout class="QHBoxLayout" name="eip_controls"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Encrypted Internet: </string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lblEIPStatus"> - <property name="styleSheet"> - <string notr="true">font: bold;</string> - </property> - <property name="text"> - <string>Off</string> - </property> - <property name="textFormat"> - <enum>Qt::AutoText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="btnEipStartStop"> - <property name="text"> - <string>Turn On</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="0"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Preferred</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>11</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="0" rowspan="2"> - <widget class="QLabel" name="lblVPNStatusIcon"> - <property name="maximumSize"> - <size> - <width>64</width> - <height>64</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/64/network-eip-down.png</pixmap> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item row="1" column="1"> - <layout class="QHBoxLayout" name="eip_bandwidth"> - <property name="spacing"> - <number>4</number> - </property> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <item> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/16/down-arrow.png</pixmap> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnDownload"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>100</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>120</width> - <height>16777215</height> - </size> - </property> - <property name="cursor"> - <cursorShape>PointingHandCursor</cursorShape> - </property> - <property name="text"> - <string>0.0 KB/s</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/16/up-arrow.png</pixmap> - </property> - </widget> - </item> - <item alignment="Qt::AlignLeft"> - <widget class="QPushButton" name="btnUpload"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>100</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>120</width> - <height>16777215</height> - </size> - </property> - <property name="cursor"> - <cursorShape>PointingHandCursor</cursorShape> - </property> - <property name="text"> - <string>0.0 KB/s</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="3" column="0" colspan="2"> - <widget class="QGroupBox" name="globalStatusBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QLabel" name="lblGlobalStatus"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>...</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources> - <include location="../../../../data/resources/icons.qrc"/> - </resources> - <connections/> -</ui> diff --git a/src/leap/gui/ui/wizard.ui b/src/leap/gui/ui/wizard.ui deleted file mode 100644 index a8f66bbc..00000000 --- a/src/leap/gui/ui/wizard.ui +++ /dev/null @@ -1,846 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Wizard</class> - <widget class="QWizard" name="Wizard"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>536</width> - <height>452</height> - </rect> - </property> - <property name="windowTitle"> - <string>Bitmask first run</string> - </property> - <property name="windowIcon"> - <iconset resource="../../../../data/resources/mainwindow.qrc"> - <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <property name="wizardStyle"> - <enum>QWizard::ModernStyle</enum> - </property> - <property name="options"> - <set>QWizard::IndependentPages</set> - </property> - <widget class="QWizardPage" name="introduction_page"> - <property name="title"> - <string>Welcome</string> - </property> - <property name="subTitle"> - <string>This is the Bitmask first run wizard</string> - </property> - <attribute name="pageId"> - <string notr="true">0</string> - </attribute> - <layout class="QGridLayout" name="gridLayout"> - <item row="3" column="0"> - <widget class="QRadioButton" name="rdoLogin"> - <property name="text"> - <string>Log In with my credentials</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string><html><head/><body><p>Now we will guide you through some configuration that is needed before you can connect for the first time.</p><p>If you ever need to modify these options again, you can find the wizard in the <span style=" font-style:italic;">'Settings'</span> menu from the main window.</p><p>Do you want to <span style=" font-weight:600;">sign up</span> for a new account, or <span style=" font-weight:600;">log in</span> with an already existing username?</p></body></html></string> - </property> - <property name="textFormat"> - <enum>Qt::RichText</enum> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QRadioButton" name="rdoRegister"> - <property name="text"> - <string>Sign up for a new account</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <spacer name="verticalSpacer_11"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="4" column="0"> - <spacer name="verticalSpacer_12"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="WizardPage" name="select_provider_page"> - <property name="title"> - <string>Provider selection</string> - </property> - <property name="subTitle"> - <string>Please enter the domain of the provider you want to use for your connection</string> - </property> - <attribute name="pageId"> - <string notr="true">1</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="1"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>60</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="lnProvider"/> - </item> - <item row="1" column="2"> - <widget class="QPushButton" name="btnCheck"> - <property name="text"> - <string>Check</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>https://</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="4" column="0" colspan="3"> - <widget class="QGroupBox" name="grpCheckProvider"> - <property name="title"> - <string>Checking for a valid provider</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="3" column="0"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Getting provider information</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Can we stablish a secure connection?</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLabel" name="lblProviderInfo"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLabel" name="lblHTTPS"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="lblNameResolution"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Can we reach this provider?</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - <item row="2" column="1" colspan="2"> - <widget class="QLabel" name="lblProviderSelectStatus"> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </widget> - <widget class="QWizardPage" name="provider_info_page"> - <property name="title"> - <string>Provider Information</string> - </property> - <property name="subTitle"> - <string>Description of services offered by this provider</string> - </property> - <attribute name="pageId"> - <string notr="true">2</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="1" column="0" colspan="2"> - <widget class="QLabel" name="lblProviderName"> - <property name="text"> - <string>Name</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <spacer name="verticalSpacer_15"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="1" colspan="2"> - <widget class="QLabel" name="lblProviderDesc"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="baseSize"> - <size> - <width>200</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string>Desc</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="lblServ"> - <property name="text"> - <string><b>Services offered:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QLabel" name="lblServicesOffered"> - <property name="text"> - <string>services</string> - </property> - </widget> - </item> - <item row="4" column="2"> - <spacer name="horizontalSpacer_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="5" column="0"> - <widget class="QLabel" name="label_12"> - <property name="text"> - <string><b>Enrollment policy:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QLabel" name="lblProviderPolicy"> - <property name="text"> - <string>policy</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string><b>URL:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="2" column="1" colspan="2"> - <widget class="QLabel" name="lblProviderURL"> - <property name="text"> - <string>URL</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string><b>Description:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set> - </property> - </widget> - </item> - </layout> - </widget> - <widget class="WizardPage" name="setup_provider_page"> - <property name="title"> - <string>Provider setup</string> - </property> - <property name="subTitle"> - <string>Gathering configuration options for this provider</string> - </property> - <attribute name="pageId"> - <string notr="true">3</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>60</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="lblSetupProviderExpl"> - <property name="text"> - <string>We are downloading some bits that we need to establish a secure connection with the provider for the first time.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_6"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Setting up provider</string> - </property> - <layout class="QGridLayout" name="gridLayout_6"> - <item row="2" column="1"> - <widget class="QLabel" name="lblCheckCaFpr"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="lblDownloadCaCert"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_9"> - <property name="text"> - <string>Getting info from the Certificate Authority</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_10"> - <property name="text"> - <string>Do we trust this Certificate Authority?</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_11"> - <property name="text"> - <string>Establishing a trust relationship with this provider</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLabel" name="lblCheckApiCert"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> - </property> - </widget> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer_8"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="WizardPage" name="register_user_page"> - <property name="title"> - <string>Register new user</string> - </property> - <property name="subTitle"> - <string>Register a new user with provider</string> - </property> - <attribute name="pageId"> - <string notr="true">4</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_7"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <property name="leftMargin"> - <number>4</number> - </property> - <item row="3" column="0"> - <widget class="QLabel" name="label_16"> - <property name="text"> - <string><b>Password:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="3" column="1" colspan="2"> - <widget class="QLineEdit" name="lblPassword"/> - </item> - <item row="4" column="1" colspan="2"> - <widget class="QLineEdit" name="lblPassword2"/> - </item> - <item row="2" column="1" colspan="2"> - <widget class="QLineEdit" name="lblUser"/> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_17"> - <property name="text"> - <string><b>Re-enter password:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QPushButton" name="btnRegister"> - <property name="text"> - <string>Register</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer_4"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>60</height> - </size> - </property> - </spacer> - </item> - <item row="7" column="1"> - <spacer name="verticalSpacer_7"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_15"> - <property name="text"> - <string><b>Username:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="5" column="1" colspan="2"> - <widget class="QCheckBox" name="chkRemember"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Remember my username and password</string> - </property> - </widget> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QLabel" name="lblRegisterStatus"> - <property name="text"> - <string/> - </property> - <property name="textFormat"> - <enum>Qt::AutoText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <widget class="QWizardPage" name="service_selection"> - <property name="title"> - <string>Service selection</string> - </property> - <property name="subTitle"> - <string>Please select the services you would like to have</string> - </property> - <attribute name="pageId"> - <string notr="true">5</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_8"> - <item row="0" column="0"> - <widget class="QGroupBox" name="grpServices"> - <property name="title"> - <string notr="true">Services by PROVIDER</string> - </property> - <layout class="QGridLayout" name="gridLayout_9"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="serviceListLayout"/> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWizardPage" name="finish_page"> - <property name="title"> - <string>Congratulations!</string> - </property> - <property name="subTitle"> - <string>You have successfully configured Bitmask.</string> - </property> - <attribute name="pageId"> - <string notr="true">6</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_10"> - <item row="1" column="0"> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer_9"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="label_23"> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/leap-color-big.png</pixmap> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="label_25"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/mainwindow.qrc">:/images/Globe.png</pixmap> - </property> - </widget> - </item> - <item row="3" column="1"> - <spacer name="verticalSpacer_10"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="3"> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - <customwidgets> - <customwidget> - <class>WizardPage</class> - <extends>QWizardPage</extends> - <header>wizardpage.h</header> - <container>1</container> - </customwidget> - </customwidgets> - <tabstops> - <tabstop>lblUser</tabstop> - <tabstop>lblPassword</tabstop> - <tabstop>lblPassword2</tabstop> - <tabstop>btnRegister</tabstop> - <tabstop>rdoRegister</tabstop> - <tabstop>rdoLogin</tabstop> - <tabstop>lnProvider</tabstop> - <tabstop>btnCheck</tabstop> - </tabstops> - <resources> - <include location="../../../../data/resources/mainwindow.qrc"/> - <include location="../../../../data/resources/locale.qrc"/> - </resources> - <connections/> -</ui> diff --git a/src/leap/gui/wizard.py b/src/leap/gui/wizard.py deleted file mode 100644 index 2b48fc81..00000000 --- a/src/leap/gui/wizard.py +++ /dev/null @@ -1,626 +0,0 @@ -# -*- coding: utf-8 -*- -# wizard.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -First run wizard -""" -import os -import logging -import json - -from PySide import QtCore, QtGui -from functools import partial -from twisted.internet import threads - -from ui_wizard import Ui_Wizard -from leap.config.providerconfig import ProviderConfig -from leap.crypto.srpregister import SRPRegister -from leap.util.privilege_policies import is_missing_policy_permissions -from leap.util.request_helpers import get_content -from leap.util.keyring_helpers import has_keyring -from leap.services.eip.providerbootstrapper import ProviderBootstrapper -from leap.services import get_supported - -logger = logging.getLogger(__name__) - - -class Wizard(QtGui.QWizard): - """ - First run wizard to register a user and setup a provider - """ - - INTRO_PAGE = 0 - SELECT_PROVIDER_PAGE = 1 - PRESENT_PROVIDER_PAGE = 2 - SETUP_PROVIDER_PAGE = 3 - REGISTER_USER_PAGE = 4 - SERVICES_PAGE = 5 - FINISH_PAGE = 6 - - WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", - "password") - - BARE_USERNAME_REGEX = r"^[A-Za-z\d_]+$" - - def __init__(self, standalone=False, bypass_checks=False): - """ - Constructor for the main Wizard. - - :param standalone: If True, the application is running as standalone - and the wizard should display some messages according to this. - :type standalone: bool - :param bypass_checks: Set to true if the app should bypass - first round of checks for CA certificates at bootstrap - :type bypass_checks: bool - """ - QtGui.QWizard.__init__(self) - - self.standalone = standalone - - self.ui = Ui_Wizard() - self.ui.setupUi(self) - - self.setPixmap(QtGui.QWizard.LogoPixmap, - QtGui.QPixmap(":/images/leap-color-small.png")) - - self.QUESTION_ICON = QtGui.QPixmap(":/images/Emblem-question.png") - self.ERROR_ICON = QtGui.QPixmap(":/images/Dialog-error.png") - self.OK_ICON = QtGui.QPixmap(":/images/Dialog-accept.png") - - # Correspondence for services and their name to display - EIP_LABEL = self.tr("Encrypted Internet") - MX_LABEL = self.tr("Encrypted Mail") - - if self._is_need_eip_password_warning(): - EIP_LABEL += " " + self.tr( - "(will need admin password to start)") - - self.SERVICE_DISPLAY = [ - EIP_LABEL, - MX_LABEL - ] - self.SERVICE_CONFIG = [ - "openvpn", - "mx" - ] - - self._selected_services = set() - self._shown_services = set() - - self._show_register = False - - self.ui.grpCheckProvider.setVisible(False) - self.ui.btnCheck.clicked.connect(self._check_provider) - self.ui.lnProvider.returnPressed.connect(self._check_provider) - - self._provider_bootstrapper = ProviderBootstrapper(bypass_checks) - self._provider_bootstrapper.name_resolution.connect( - self._name_resolution) - self._provider_bootstrapper.https_connection.connect( - self._https_connection) - self._provider_bootstrapper.download_provider_info.connect( - self._download_provider_info) - - self._provider_bootstrapper.download_ca_cert.connect( - self._download_ca_cert) - self._provider_bootstrapper.check_ca_fingerprint.connect( - self._check_ca_fingerprint) - self._provider_bootstrapper.check_api_certificate.connect( - self._check_api_certificate) - - self._domain = None - self._provider_config = ProviderConfig() - - # We will store a reference to the defers for eventual use - # (eg, to cancel them) but not doing anything with them right now. - self._provider_select_defer = None - self._provider_setup_defer = None - - self.currentIdChanged.connect(self._current_id_changed) - - self.ui.lblPassword.setEchoMode(QtGui.QLineEdit.Password) - self.ui.lblPassword2.setEchoMode(QtGui.QLineEdit.Password) - - self.ui.lnProvider.textChanged.connect( - self._enable_check) - - self.ui.lblUser.returnPressed.connect( - self._focus_password) - self.ui.lblPassword.returnPressed.connect( - self._focus_second_password) - self.ui.lblPassword2.returnPressed.connect( - self._register) - self.ui.btnRegister.clicked.connect( - self._register) - - usernameRe = QtCore.QRegExp(self.BARE_USERNAME_REGEX) - self.ui.lblUser.setValidator( - QtGui.QRegExpValidator(usernameRe, self)) - - self.page(self.REGISTER_USER_PAGE).setCommitPage(True) - - self._username = None - self._password = None - - self.page(self.REGISTER_USER_PAGE).setButtonText( - QtGui.QWizard.CommitButton, self.tr("&Next >")) - self.page(self.FINISH_PAGE).setButtonText( - QtGui.QWizard.FinishButton, self.tr("Connect")) - - # XXX: Temporary removal for enrollment policy - # https://leap.se/code/issues/2922 - self.ui.label_12.setVisible(False) - self.ui.lblProviderPolicy.setVisible(False) - - def get_domain(self): - return self._domain - - def get_username(self): - return self._username - - def get_password(self): - return self._password - - def get_remember(self): - return has_keyring() and self.ui.chkRemember.isChecked() - - def get_services(self): - return self._selected_services - - def _enable_check(self, text): - self.ui.btnCheck.setEnabled(len(self.ui.lnProvider.text()) != 0) - self._reset_provider_check() - - def _focus_password(self): - """ - Focuses at the password lineedit for the registration page - """ - self.ui.lblPassword.setFocus() - - def _focus_second_password(self): - """ - Focuses at the second password lineedit for the registration page - """ - self.ui.lblPassword2.setFocus() - - def _basic_password_checks(self, username, password, password2): - """ - Performs basic password checks to avoid really easy passwords. - - :param username: username provided at the registrarion form - :type username: str - :param password: password from the registration form - :type password: str - :param password2: second password from the registration form - :type password: str - - :return: returns True if all the checks pass, False otherwise - :rtype: bool - """ - message = None - - if message is None and password != password2: - message = self.tr("Passwords don't match") - - if message is None and len(password) < 6: - message = self.tr("Password too short") - - if message is None and password in self.WEAK_PASSWORDS: - message = self.tr("Password too easy") - - if message is None and username == password: - message = self.tr("Password equal to username") - - if message is not None: - self._set_register_status(message, error=True) - self._focus_password() - return False - - return True - - def _register(self): - """ - Performs the registration based on the values provided in the form - """ - self.ui.btnRegister.setEnabled(False) - - username = self.ui.lblUser.text() - password = self.ui.lblPassword.text() - password2 = self.ui.lblPassword2.text() - - if self._basic_password_checks(username, password, password2): - register = SRPRegister(provider_config=self._provider_config) - register.registration_finished.connect( - self._registration_finished) - - threads.deferToThread( - partial(register.register_user, - username.encode("utf8"), - password.encode("utf8"))) - - self._username = username - self._password = password - self._set_register_status(self.tr("Starting registration...")) - else: - self.ui.btnRegister.setEnabled(True) - - def _set_registration_fields_visibility(self, visible): - """ - This method hides the username and password labels and inputboxes. - - :param visible: sets the visibility of the widgets - True: widgets are visible or False: are not - :type visible: bool - """ - # username and password inputs - self.ui.lblUser.setVisible(visible) - self.ui.lblPassword.setVisible(visible) - self.ui.lblPassword2.setVisible(visible) - - # username and password labels - self.ui.label_15.setVisible(visible) - self.ui.label_16.setVisible(visible) - self.ui.label_17.setVisible(visible) - - # register button - self.ui.btnRegister.setVisible(visible) - - def _registration_finished(self, ok, req): - if ok: - user_domain = self._username + "@" + self._domain - message = "<font color='green'><h3>" - message += self.tr("User %s successfully registered.") % ( - user_domain, ) - message += "</h3></font>" - self._set_register_status(message) - - self.ui.lblPassword2.clearFocus() - self._set_registration_fields_visibility(False) - - # Allow the user to remember his password - if has_keyring(): - self.ui.chkRemember.setVisible(True) - self.ui.chkRemember.setEnabled(True) - - self.page(self.REGISTER_USER_PAGE).set_completed() - self.button(QtGui.QWizard.BackButton).setEnabled(False) - else: - old_username = self._username - self._username = None - self._password = None - error_msg = self.tr("Unknown error") - try: - content, _ = get_content(req) - json_content = json.loads(content) - error_msg = json_content.get("errors").get("login")[0] - if not error_msg.istitle(): - error_msg = "%s %s" % (old_username, error_msg) - except Exception as e: - logger.error("Unknown error: %r" % (e,)) - - self._set_register_status(error_msg, error=True) - self.ui.btnRegister.setEnabled(True) - - def _set_register_status(self, status, error=False): - """ - Sets the status label in the registration page to status - - :param status: status message to display, can be HTML - :type status: str - """ - if error: - status = "<font color='red'><b>%s</b></font>" % (status,) - self.ui.lblRegisterStatus.setText(status) - - def _reset_provider_check(self): - """ - Resets the UI for checking a provider. Also resets the domain - in this object. - """ - self.ui.lblNameResolution.setPixmap(None) - self.ui.lblHTTPS.setPixmap(None) - self.ui.lblProviderInfo.setPixmap(None) - self.ui.lblProviderSelectStatus.setText("") - self._domain = None - self.button(QtGui.QWizard.NextButton).setEnabled(False) - self.page(self.SELECT_PROVIDER_PAGE).set_completed(False) - - def _reset_provider_setup(self): - """ - Resets the UI for setting up a provider. - """ - self.ui.lblDownloadCaCert.setPixmap(None) - self.ui.lblCheckCaFpr.setPixmap(None) - self.ui.lblCheckApiCert.setPixmap(None) - - def _check_provider(self): - """ - SLOT - TRIGGERS: - self.ui.btnCheck.clicked - self.ui.lnProvider.returnPressed - - Starts the checks for a given provider - """ - if len(self.ui.lnProvider.text()) == 0: - return - - self.ui.grpCheckProvider.setVisible(True) - self.ui.btnCheck.setEnabled(False) - self.ui.lnProvider.setEnabled(False) - self.button(QtGui.QWizard.BackButton).clearFocus() - self._domain = self.ui.lnProvider.text() - - self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON) - self._provider_select_defer = self._provider_bootstrapper.\ - run_provider_select_checks(self._domain) - - def _complete_task(self, data, label, complete=False, complete_page=-1): - """ - Checks a task and completes a page if specified - - :param data: data as it comes from the bootstrapper thread for - a specific check - :type data: dict - :param label: label that displays the status icon for a - specific check that corresponds to the data - :type label: QtGui.QLabel - :param complete: if True, it completes the page specified, - which must be of type WizardPage - :type complete: bool - :param complete_page: page id to complete - :type complete_page: int - """ - passed = data[self._provider_bootstrapper.PASSED_KEY] - error = data[self._provider_bootstrapper.ERROR_KEY] - if passed: - label.setPixmap(self.OK_ICON) - if complete: - self.page(complete_page).set_completed() - self.button(QtGui.QWizard.NextButton).setFocus() - else: - label.setPixmap(self.ERROR_ICON) - logger.error(error) - - def _name_resolution(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.name_resolution - - Sets the status for the name resolution check - """ - self._complete_task(data, self.ui.lblNameResolution) - status = "" - passed = data[self._provider_bootstrapper.PASSED_KEY] - if not passed: - status = self.tr("<font color='red'><b>Non-existent " - "provider</b></font>") - else: - self.ui.lblHTTPS.setPixmap(self.QUESTION_ICON) - self.ui.lblProviderSelectStatus.setText(status) - self.ui.btnCheck.setEnabled(not passed) - self.ui.lnProvider.setEnabled(not passed) - - def _https_connection(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.https_connection - - Sets the status for the https connection check - """ - self._complete_task(data, self.ui.lblHTTPS) - status = "" - passed = data[self._provider_bootstrapper.PASSED_KEY] - if not passed: - status = self.tr("<font color='red'><b>%s</b></font>") \ - % (data[self._provider_bootstrapper.ERROR_KEY]) - self.ui.lblProviderSelectStatus.setText(status) - else: - self.ui.lblProviderInfo.setPixmap(self.QUESTION_ICON) - self.ui.btnCheck.setEnabled(not passed) - self.ui.lnProvider.setEnabled(not passed) - - def _download_provider_info(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.download_provider_info - - Sets the status for the provider information download - check. Since this check is the last of this set, it also - completes the page if passed - """ - if self._provider_config.load(os.path.join("leap", - "providers", - self._domain, - "provider.json")): - self._complete_task(data, self.ui.lblProviderInfo, - True, self.SELECT_PROVIDER_PAGE) - else: - new_data = { - self._provider_bootstrapper.PASSED_KEY: False, - self._provider_bootstrapper.ERROR_KEY: - self.tr("Unable to load provider configuration") - } - self._complete_task(new_data, self.ui.lblProviderInfo) - - status = "" - if not data[self._provider_bootstrapper.PASSED_KEY]: - status = self.tr("<font color='red'><b>Not a valid provider" - "</b></font>") - self.ui.lblProviderSelectStatus.setText(status) - self.ui.btnCheck.setEnabled(True) - self.ui.lnProvider.setEnabled(True) - - def _download_ca_cert(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.download_ca_cert - - Sets the status for the download of the CA certificate check - """ - self._complete_task(data, self.ui.lblDownloadCaCert) - passed = data[self._provider_bootstrapper.PASSED_KEY] - if passed: - self.ui.lblCheckCaFpr.setPixmap(self.QUESTION_ICON) - - def _check_ca_fingerprint(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.check_ca_fingerprint - - Sets the status for the CA fingerprint check - """ - self._complete_task(data, self.ui.lblCheckCaFpr) - passed = data[self._provider_bootstrapper.PASSED_KEY] - if passed: - self.ui.lblCheckApiCert.setPixmap(self.QUESTION_ICON) - - def _check_api_certificate(self, data): - """ - SLOT - TRIGGER: self._provider_bootstrapper.check_api_certificate - - Sets the status for the API certificate check. Also finishes - the provider bootstrapper thread since it's not needed anymore - from this point on, unless the whole check chain is restarted - """ - self._complete_task(data, self.ui.lblCheckApiCert, - True, self.SETUP_PROVIDER_PAGE) - - def _service_selection_changed(self, service, state): - """ - SLOT - TRIGGER: service_checkbox.stateChanged - Adds the service to the state if the state is checked, removes - it otherwise - - :param service: service to handle - :type service: str - :param state: state of the checkbox - :type state: int - """ - if state == QtCore.Qt.Checked: - self._selected_services = \ - self._selected_services.union(set([service])) - else: - self._selected_services = \ - self._selected_services.difference(set([service])) - - def _populate_services(self): - """ - Loads the services that the provider provides into the UI for - the user to enable or disable. - """ - self.ui.grpServices.setTitle( - self.tr("Services by %s") % - (self._provider_config.get_name(),)) - - services = get_supported( - self._provider_config.get_services()) - - for service in services: - try: - if service not in self._shown_services: - checkbox = QtGui.QCheckBox(self) - service_index = self.SERVICE_CONFIG.index(service) - checkbox.setText(self.SERVICE_DISPLAY[service_index]) - self.ui.serviceListLayout.addWidget(checkbox) - checkbox.stateChanged.connect( - partial(self._service_selection_changed, service)) - checkbox.setChecked(True) - self._shown_services.add(service) - except ValueError: - logger.error( - self.tr("Something went wrong while trying to " - "load service %s" % (service,))) - - def _current_id_changed(self, pageId): - """ - SLOT - TRIGGER: self.currentIdChanged - - Prepares the pages when they appear - """ - if pageId == self.SELECT_PROVIDER_PAGE: - self._reset_provider_check() - self._enable_check("") - - if pageId == self.SETUP_PROVIDER_PAGE: - self._reset_provider_setup() - self.page(pageId).setSubTitle(self.tr("Gathering configuration " - "options for %s") % - (self._provider_config - .get_name(),)) - self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) - self._provider_setup_defer = self._provider_bootstrapper.\ - run_provider_setup_checks(self._provider_config) - - if pageId == self.PRESENT_PROVIDER_PAGE: - self.page(pageId).setSubTitle(self.tr("Description of services " - "offered by %s") % - (self._provider_config - .get_name(),)) - - lang = QtCore.QLocale.system().name() - self.ui.lblProviderName.setText( - "<b>%s</b>" % - (self._provider_config.get_name(lang=lang),)) - self.ui.lblProviderURL.setText( - "https://%s" % (self._provider_config.get_domain(),)) - self.ui.lblProviderDesc.setText( - "<i>%s</i>" % - (self._provider_config.get_description(lang=lang),)) - - self.ui.lblServicesOffered.setText(self._provider_config - .get_services_string()) - self.ui.lblProviderPolicy.setText(self._provider_config - .get_enrollment_policy()) - - if pageId == self.REGISTER_USER_PAGE: - self.page(pageId).setSubTitle(self.tr("Register a new user with " - "%s") % - (self._provider_config - .get_name(),)) - self.ui.chkRemember.setVisible(False) - - if pageId == self.SERVICES_PAGE: - self._populate_services() - - def _is_need_eip_password_warning(self): - """ - Returns True if we need to add a warning about eip needing - administrative permissions to start. That can be either - because we are running in standalone mode, or because we could - not find the needed privilege escalation mechanisms being operative. - """ - return self.standalone or is_missing_policy_permissions() - - def nextId(self): - """ - Sets the next page id for the wizard based on wether the user - wants to register a new identity or uses an existing one - """ - if self.currentPage() == self.page(self.INTRO_PAGE): - self._show_register = self.ui.rdoRegister.isChecked() - - if self.currentPage() == self.page(self.SETUP_PROVIDER_PAGE): - if self._show_register: - return self.REGISTER_USER_PAGE - else: - return self.SERVICES_PAGE - - return QtGui.QWizard.nextId(self) diff --git a/src/leap/gui/wizardpage.py b/src/leap/gui/wizardpage.py deleted file mode 100644 index b2a00028..00000000 --- a/src/leap/gui/wizardpage.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -# wizardpage.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from PySide import QtGui - - -class WizardPage(QtGui.QWizardPage): - """ - Simple wizard page helper - """ - - def __init__(self): - QtGui.QWizardPage.__init__(self) - self._completed = False - - def set_completed(self, val=True): - self._completed = val - if val: - self.completeChanged.emit() - - def isComplete(self): - return self._completed - - def cleanupPage(self): - self._completed = False - QtGui.QWizardPage.cleanupPage(self) |