diff options
Diffstat (limited to 'src/leap/baseapp/eip.py')
-rw-r--r-- | src/leap/baseapp/eip.py | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py new file mode 100644 index 00000000..029ce0ba --- /dev/null +++ b/src/leap/baseapp/eip.py @@ -0,0 +1,195 @@ +import time + +from PyQt4 import QtCore + +from leap.baseapp.dialogs import ErrorDialog +from leap.baseapp import constants +from leap.eip import exceptions as eip_exceptions +from leap.eip.eipconnection import EIPConnection + + +class EIPConductorApp(object): + """ + initializes an instance of EIPConnection, + gathers errors, and passes status-change signals + from Qt land along to the conductor. + Connects the eip connect/disconnect logic + to the switches in the app (buttons/menu items). + """ + + def __init__(self, *args, **kwargs): + opts = kwargs.pop('opts') + config_file = getattr(opts, 'config_file', None) + + self.eip_service_started = False + + # conductor (eip connection) is in charge of all + # vpn-related configuration / monitoring. + # we pass a tuple of signals that will be + # triggered when status changes. + + self.conductor = EIPConnection( + watcher_cb=self.newLogLine.emit, + config_file=config_file, + status_signals=(self.statusChange.emit, ), + debug=self.debugmode) + + # XXX remove skip download when sample service is ready + self.conductor.run_checks(skip_download=True) + self.error_check() + + # XXX should receive "ready" signal + # it is called from LeapWindow now. + #if self.conductor.autostart: + #self.start_or_stopVPN() + + if self.debugmode: + self.startStopButton.clicked.connect( + lambda: self.start_or_stopVPN()) + + def error_check(self): + + # XXX refactor (by #504) + + if self.conductor.missing_definition is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'The default ' + 'definition.json file cannot be found', + 'error') + + if self.conductor.missing_provider is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'Missing provider. Add a remote_ip entry ' + 'under section [provider] in eip.cfg', + 'error') + + if self.conductor.missing_vpn_keyfile is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'Could not find the vpn keys file', + 'error') + + # ... btw, review pending. + # os.kill of subprocess fails if we have + # some of this errors. + + if self.conductor.bad_provider is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'Bad provider entry. Check that remote_ip entry ' + 'has an IP under section [provider] in eip.cfg', + 'error') + + if self.conductor.bad_keyfile_perms is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'The vpn keys file has bad permissions', + 'error') + + if self.conductor.missing_auth_agent is True: + dialog = ErrorDialog() + dialog.warningMessage( + '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') + + if self.conductor.missing_pkexec is True: + dialog = ErrorDialog() + dialog.warningMessage( + 'We could not find <b>pkexec</b> in your ' + 'system.<br/> Do you want to try ' + '<b>setuid workaround</b>? ' + '(<i>DOES NOTHING YET</i>)', + 'error') + + @QtCore.pyqtSlot() + def statusUpdate(self): + """ + polls status and updates ui with real time + info about transferred bytes / connection state. + right now is triggered by a timer tick + (timer controlled by StatusAwareTrayIcon class) + """ + # TODO I guess it's too expensive to poll + # continously. move to signal events instead. + # (i.e., subscribe to connection status changes + # from openvpn manager) + + if not self.eip_service_started: + return + + if self.conductor.with_errors: + #XXX how to wait on pkexec??? + #something better that this workaround, plz!! + time.sleep(2) + print('errors. disconnect.') + self.start_or_stopVPN() # is stop + + state = self.conductor.poll_connection_state() + if not state: + return + + ts, con_status, ok, ip, remote = state + self.set_statusbarMessage(con_status) + self.setIconToolTip() + + ts = time.strftime("%a %b %d %X", ts) + if self.debugmode: + self.updateTS.setText(ts) + self.status_label.setText(con_status) + self.ip_label.setText(ip) + self.remote_label.setText(remote) + + # status i/o + + status = self.conductor.get_status_io() + if status and self.debugmode: + #XXX move this to systray menu indicators + ts, (tun_read, tun_write, tcp_read, tcp_write, auth_read) = status + ts = time.strftime("%a %b %d %X", ts) + self.updateTS.setText(ts) + self.tun_read_bytes.setText(tun_read) + self.tun_write_bytes.setText(tun_write) + + @QtCore.pyqtSlot() + def start_or_stopVPN(self): + """ + stub for running child process with vpn + """ + if self.eip_service_started is False: + try: + self.conductor.connect() + # XXX move this to error queue + except eip_exceptions.EIPNoCommandError: + dialog = ErrorDialog() + dialog.warningMessage( + 'No suitable openvpn command found. ' + '<br/>(Might be a permissions problem)', + 'error') + if self.debugmode: + self.startStopButton.setText('&Disconnect') + self.eip_service_started = True + + # XXX what is optimum polling interval? + # too little is overkill, too much + # will miss transition states.. + + # XXX decouple! (timer is init by icons class). + # should bring it here? + # to its own class? + + self.timer.start(constants.TIMER_MILLISECONDS) + return + + if self.eip_service_started is True: + self.conductor.disconnect() + if self.debugmode: + self.startStopButton.setText('&Connect') + self.eip_service_started = False + self.timer.stop() + return |