summaryrefslogtreecommitdiff
path: root/src/leap/baseapp/eip.py
blob: a67fd916a52508711a5198729663d9d45037f8b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import time

from PyQt4 import QtCore

from leap.baseapp.dialogs import ErrorDialog
from leap.eip import exceptions as eip_exceptions
from leap.eip.eipconnection import EIPConnection


class EIPConductorApp(object):

    def __init__(self, *args, **kwargs):
        #
        # conductor is in charge of all
        # vpn-related configuration / monitoring.
        # we pass a tuple of signals that will be
        # triggered when status changes.
        #
        opts = kwargs.pop('opts')
        config_file = getattr(opts, 'config_file', None)

        self.eip_service_started = False

        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
        #if self.conductor.autostart:
            #self.start_or_stopVPN()

        # move to eipconductor init?
        if self.debugmode:
            self.startStopButton.clicked.connect(
                lambda: self.start_or_stopVPN())

    def error_check(self):
        ####### error checking ################
        #
        # bunch of self checks.
        # XXX move somewhere else alltogether.
        #
        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):
        """
        called on timer tick
        polls status and updates ui with real time
        info about transferred bytes / connection state.
        """
        # XXX it's too expensive to poll
        # continously. move to signal events instead.

        if not self.eip_service_started:
            return

        # XXX remove all access to manager layer
        # from here.
        if self.conductor.with_errors:
            #XXX how to wait on pkexec???
            #something better that this workaround, plz!!
            time.sleep(5)
            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..

            self.timer.start(250.0)
            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