summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKali Kaneko (leap communications) <kali@leap.se>2017-02-01 14:49:45 +0100
committerKali Kaneko (leap communications) <kali@leap.se>2017-02-23 00:40:31 +0100
commit1d4a3d68869dd9c416b104399097a6bb0c1bace3 (patch)
tree9afc38280e17a84e55184f064cf34f1a490ac539
parent6d1d18faec5caa60c26b8245f0ab17c63d0b80d8 (diff)
[feature] new commands: get_cert
-rw-r--r--src/leap/bitmask/bonafide/_protocol.py9
-rw-r--r--src/leap/bitmask/bonafide/service.py16
-rw-r--r--src/leap/bitmask/cli/command.py6
-rw-r--r--src/leap/bitmask/cli/eip.py14
-rw-r--r--src/leap/bitmask/core/dispatcher.py21
-rw-r--r--src/leap/bitmask/core/service.py2
-rw-r--r--src/leap/bitmask/vpn/__init__.py10
-rw-r--r--src/leap/bitmask/vpn/_checks.py27
-rw-r--r--src/leap/bitmask/vpn/_control.py7
-rw-r--r--src/leap/bitmask/vpn/_management.py14
-rw-r--r--src/leap/bitmask/vpn/eip.py2
-rw-r--r--src/leap/bitmask/vpn/errors.py2
-rw-r--r--src/leap/bitmask/vpn/manager.py13
-rw-r--r--src/leap/bitmask/vpn/process.py7
-rw-r--r--src/leap/bitmask/vpn/service.py91
15 files changed, 163 insertions, 78 deletions
diff --git a/src/leap/bitmask/bonafide/_protocol.py b/src/leap/bitmask/bonafide/_protocol.py
index ac631d8..91b8b24 100644
--- a/src/leap/bitmask/bonafide/_protocol.py
+++ b/src/leap/bitmask/bonafide/_protocol.py
@@ -192,9 +192,12 @@ class BonafideProtocol(object):
d = self._sessions[full_id].get_smtp_cert()
return d
- def do_get_vpn_cert(self):
- # FIXME to be implemented
- pass
+ def do_get_vpn_cert(self, full_id):
+ if (full_id not in self._sessions or
+ not self._sessions[full_id].is_authenticated):
+ return fail(RuntimeError("There is no session for such user"))
+ d = self._sessions[full_id].get_vpn_cert()
+ return d
def do_update_user(self):
# FIXME to be implemented
diff --git a/src/leap/bitmask/bonafide/service.py b/src/leap/bitmask/bonafide/service.py
index 37d1e21..69aac2d 100644
--- a/src/leap/bitmask/bonafide/service.py
+++ b/src/leap/bitmask/bonafide/service.py
@@ -120,7 +120,21 @@ class BonafideService(HookableService):
def do_provider_list(self, seeded=False):
return self._bonafide.do_provider_list(seeded)
- def do_get_smtp_cert(self, username):
+ # TODO make username mandatory
+ # and move active_user to the cli machinery
+ def do_get_vpn_cert(self, username=None):
+ if not username:
+ username = self._active_user
+ if not username:
+ return defer.fail(
+ RuntimeError('No active user, cannot get VPN cert.'))
+ d = self._bonafide.do_get_vpn_cert(username)
+ d.addCallback(lambda response: (username, response))
+ return d
+
+ def do_get_smtp_cert(self, username=None):
+ if not username:
+ username = self._active_user
if not username:
return defer.fail(
RuntimeError('No username, cannot get SMTP cert.'))
diff --git a/src/leap/bitmask/cli/command.py b/src/leap/bitmask/cli/command.py
index 0e70d2e..ff213a3 100644
--- a/src/leap/bitmask/cli/command.py
+++ b/src/leap/bitmask/cli/command.py
@@ -116,7 +116,11 @@ class Command(object):
if self.print_json:
print(json.dumps(obj, indent=2))
elif not obj['error']:
- return printer(obj['result'])
+ if not obj['result']:
+ print (Fore.RED + 'ERROR: malformed response, expected'
+ ' obj["result"]' + Fore.RESET)
+ else:
+ return printer(obj['result'])
else:
print Fore.RED + 'ERROR:' + '%s' % obj['error'] + Fore.RESET
diff --git a/src/leap/bitmask/cli/eip.py b/src/leap/bitmask/cli/eip.py
index eac8682..5fb240c 100644
--- a/src/leap/bitmask/cli/eip.py
+++ b/src/leap/bitmask/cli/eip.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# eip
-# Copyright (C) 2016 LEAP
+# Copyright (C) 2016-2017 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
@@ -24,14 +24,18 @@ class Eip(command.Command):
service = 'eip'
usage = '''{name} eip <subcommand>
-Bitmask Encrypted Internet Service
+Bitmask Encrypted Internet Proxy Service
SUBCOMMANDS:
- start Start service
- stop Stop service
+ enable Enable EIP Service
+ disable Disable EIP Service
+ check Check whether EIP service is properly configured
+ get_cert Get EIP Certificate from provider
+ start Start EIP
+ stop Stop EIP
status Display status about service
'''.format(name=command.appname)
- commands = ['start', 'stop', 'status']
+ commands = ['start', 'stop', 'status', 'check', 'get_cert']
diff --git a/src/leap/bitmask/core/dispatcher.py b/src/leap/bitmask/core/dispatcher.py
index 833741d..a93c3ec 100644
--- a/src/leap/bitmask/core/dispatcher.py
+++ b/src/leap/bitmask/core/dispatcher.py
@@ -201,12 +201,27 @@ class EIPCmd(SubCommand):
except IndexError:
raise DispatchError(
'wrong number of arguments: expected 1, got none')
- d = eip.do_start(provider)
+ # TODO --- attempt to get active provider
+ # TODO or catch the exception and send error
+ provider = parts[2]
+ d = eip.start_vpn(provider)
return d
@register_method('dict')
def do_STOP(self, eip, *parts):
- d = eip.do_stop()
+ d = eip.stop_vpn()
+ return d
+
+ @register_method('check')
+ def do_CHECK(self, eip, *parts):
+ d = eip.do_check()
+ return d
+
+ @register_method('get_cert')
+ def do_GET_CERT(self, eip, *parts):
+ # TODO -- attempt to get active provider
+ provider = parts[2]
+ d = eip.do_get_cert(provider)
return d
@@ -513,7 +528,7 @@ def _format_error(failure):
logger.failure('[DISPATCHER] Unexpected error:')
except:
logger.debug('[DISPATCHER] Unexpected error: %r' % failure.value)
- logger.debug('%r' % failure)
+ print failure.getTraceback()
# if needed, we could add here the exception type as an extra field
return json.dumps({'error': failure.value.message, 'result': None})
diff --git a/src/leap/bitmask/core/service.py b/src/leap/bitmask/core/service.py
index 3a3b1f6..65b5ddc 100644
--- a/src/leap/bitmask/core/service.py
+++ b/src/leap/bitmask/core/service.py
@@ -32,7 +32,7 @@ from leap.bitmask.core import _zmq
from leap.bitmask.core import flags
from leap.bitmask.core import _session
from leap.bitmask.core.web.service import HTTPDispatcherService
-from leap.bitmask.vpn import EIPService
+from leap.bitmask.vpn.service import EIPService
from leap.common.events import server as event_server
logger = Logger()
diff --git a/src/leap/bitmask/vpn/__init__.py b/src/leap/bitmask/vpn/__init__.py
index 6c3cf06..e69de29 100644
--- a/src/leap/bitmask/vpn/__init__.py
+++ b/src/leap/bitmask/vpn/__init__.py
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-from .manager import VPNManager
-from .eip import EIPManager
-from .service import EIPService
-from .fw.firewall import FirewallManager
-
-import errors
-
-__all__ = ['VPNManager', 'FirewallManager', 'EIPManager', 'EIPService',
- 'errors']
diff --git a/src/leap/bitmask/vpn/_checks.py b/src/leap/bitmask/vpn/_checks.py
new file mode 100644
index 0000000..3a1914f
--- /dev/null
+++ b/src/leap/bitmask/vpn/_checks.py
@@ -0,0 +1,27 @@
+import os
+
+from leap.common.config import get_path_prefix
+
+
+class ImproperlyConfigured(Exception):
+ pass
+
+
+def is_service_ready(provider):
+ valid_cert = _has_valid_cert(provider)
+ return True
+
+
+def get_eip_cert_path(provider):
+ return os.path.join(get_path_prefix(),
+ 'leap', 'providers', provider,
+ 'keys', 'client', 'openvpn.pem')
+
+
+def _has_valid_cert(provider):
+ cert_path = get_eip_cert_path(provider)
+ has_file = os.path.isfile(cert_path)
+ if not has_file:
+ raise ImproperlyConfigured('Missing EIP certificate')
+
+
diff --git a/src/leap/bitmask/vpn/_control.py b/src/leap/bitmask/vpn/_control.py
index 991dc0f..82dd90b 100644
--- a/src/leap/bitmask/vpn/_control.py
+++ b/src/leap/bitmask/vpn/_control.py
@@ -14,11 +14,8 @@ class VPNControl(object):
OPENVPN_VERB = "openvpn_verb"
def __init__(self, **kwargs):
- """
- Instantiate empty attributes and get a copy
- of a QObject containing the QSignals that we will pass along
- to the VPNManager.
- """
+ # TODO what the fuck this is doing that is different from
+ # the manager?
self._vpnproc = None
self._pollers = []
diff --git a/src/leap/bitmask/vpn/_management.py b/src/leap/bitmask/vpn/_management.py
index 0eb37b7..51120a3 100644
--- a/src/leap/bitmask/vpn/_management.py
+++ b/src/leap/bitmask/vpn/_management.py
@@ -1,3 +1,6 @@
+from leap.bitmask.vpn.constants import IS_MAC
+
+
class OpenVPNAlreadyRunning(Exception):
message = ("Another openvpn instance is already running, and could "
"not be stopped.")
@@ -36,15 +39,7 @@ class VPNManagement(object):
"""
self._tn = None
self._signaler = signaler
- self._aborted = False
-
- @property
- def aborted(self):
- return self._aborted
-
- @aborted.setter
- def aborted(self, value):
- self._aborted = value
+ self.aborted = False
def _seek_to_eof(self):
"""
@@ -419,4 +414,3 @@ class VPNManagement(object):
else:
logger.warning("Unable to terminate OpenVPN")
raise OpenVPNAlreadyRunning
-
diff --git a/src/leap/bitmask/vpn/eip.py b/src/leap/bitmask/vpn/eip.py
index 853fabd..d673662 100644
--- a/src/leap/bitmask/vpn/eip.py
+++ b/src/leap/bitmask/vpn/eip.py
@@ -18,7 +18,7 @@
from colorama import Fore
-from leap.bitmask.vpn import VPNManager
+from leap.bitmask.vpn.manager import VPNManager
from leap.bitmask.vpn.fw.firewall import FirewallManager
from leap.bitmask.vpn.status import StatusQueue
from leap.bitmask.vpn.zmq_pub import ZMQPublisher
diff --git a/src/leap/bitmask/vpn/errors.py b/src/leap/bitmask/vpn/errors.py
index 77cf1dc..239ea35 100644
--- a/src/leap/bitmask/vpn/errors.py
+++ b/src/leap/bitmask/vpn/errors.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from .process import OpenVPNAlreadyRunning, AlienOpenVPNAlreadyRunning
+from ._management import OpenVPNAlreadyRunning, AlienOpenVPNAlreadyRunning
from .launcher import OpenVPNNotFoundException, VPNLauncherException
from leap.bitmask.vpn.launchers.linux import (
EIPNoPolkitAuthAgentAvailable, EIPNoPkexecAvailable)
diff --git a/src/leap/bitmask/vpn/manager.py b/src/leap/bitmask/vpn/manager.py
index 541da9e..6802585 100644
--- a/src/leap/bitmask/vpn/manager.py
+++ b/src/leap/bitmask/vpn/manager.py
@@ -22,11 +22,15 @@ VPN Manager
import os
import tempfile
-from leap.bitmask.vpn import process, _config
-from leap.bitmask.vpn.constants import IS_WIN
+from .process import VPNProcess
+from ._config import _TempEIPConfig
+from .constants import IS_WIN
+# TODO this is very badly named. There is another class that is called
+# manager!!!
+
class VPNManager(object):
def __init__(self, remotes, cert_path, key_path, ca_path, extra_flags,
@@ -45,11 +49,12 @@ class VPNManager(object):
domain = "demo.bitmask.net"
self._remotes = remotes
- self._eipconfig = _config._TempEIPConfig(extra_flags, cert_path, ports)
+ self._eipconfig = _TempEIPConfig(extra_flags, cert_path, ports)
self._providerconfig = _config._TempProviderConfig(domain, ca_path)
# signaler = None # XXX handle signaling somehow...
signaler = mock_signaler
- self._vpn = process.VPN(remotes=remotes, signaler=signaler)
+ self._vpn = VPNProcess(remotes=remotes, signaler=signaler)
+
def start(self):
"""
diff --git a/src/leap/bitmask/vpn/process.py b/src/leap/bitmask/vpn/process.py
index 4aae26b..47c2942 100644
--- a/src/leap/bitmask/vpn/process.py
+++ b/src/leap/bitmask/vpn/process.py
@@ -16,7 +16,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-VPN Manager, spawned in a custom processProtocol.
+VPN Process management.
+A custom processProtocol launches the VPNProcess and connects to its management
+interface.
"""
import os
@@ -48,6 +50,7 @@ from leap.bitmask.vpn.utils import get_vpn_launcher
from leap.bitmask.vpn.launchers import linux
from leap.bitmask.vpn.udstelnet import UDSTelnet
from leap.bitmask.vpn import _observer
+from leap.bitmask.vpn import _management
logger = Logger()
@@ -56,7 +59,7 @@ logger = Logger()
OPENVPN_VERBOSITY = 1
-class VPNProcess(protocol.ProcessProtocol, VPNManager):
+class VPNProcess(protocol.ProcessProtocol, _management.VPNManagement):
"""
A ProcessProtocol class that can be used to spawn a process that will
launch openvpn and connect to its management interface to control it
diff --git a/src/leap/bitmask/vpn/service.py b/src/leap/bitmask/vpn/service.py
index d83a9ef..59e251d 100644
--- a/src/leap/bitmask/vpn/service.py
+++ b/src/leap/bitmask/vpn/service.py
@@ -22,16 +22,19 @@ EIP service declaration.
import os
-from twisted.application import service
-from twisted.python import log
+from twisted.internet import defer
from leap.bitmask.hooks import HookableService
-from leap.bitmask.vpn import EIPManager
+from leap.bitmask.vpn.eip import EIPManager
+from leap.bitmask.vpn._checks import is_service_ready, get_eip_cert_path
from leap.common.config import get_path_prefix
+from leap.common.files import check_and_fix_urw_only
class EIPService(HookableService):
+ name = 'eip'
+
def __init__(self, basepath=None):
"""
Initialize EIP service
@@ -45,18 +48,66 @@ class EIPService(HookableService):
else:
self._basepath = basepath
+ def startService(self):
+ print "Starting EIP Service..."
+ # TODO this could trigger a check for validity of the certificates,
+ # etc.
+ super(EIPService, self).startService()
+
+ def stopService(self):
+ print "Stopping EIP Service..."
+ super(EIPService, self).stopService()
+
+ def start_vpn(self, domain):
+ self._setup(domain)
+ self._eip.start()
+ self._started = True
+ return "Starting"
+
+ def stop_vpn(self):
+ if self._started:
+ self._eip.stop()
+ self._started = False
+ return "Stopping"
+ else:
+ return "Not started"
+
+ def do_status(self):
+ # TODO -- get status from a dedicated STATUS CLASS
+ return {'result': 'running'}
+
+ def do_check(self):
+ """Check whether the EIP Service is properly configured,
+ and can be started"""
+ # TODO either pass a provider, or set a given provider
+ _ready = is_service_ready('demo.bitmask.net')
+ return {'eip_ready': 'ok'}
+
+ @defer.inlineCallbacks
+ def do_get_cert(self, provider):
+ # fetch vpn cert and store
+ bonafide = self.parent.getServiceNamed("bonafide")
+ _, cert_str = yield bonafide.do_get_vpn_cert()
+
+ cert_path = get_eip_cert_path(provider)
+ cert_dir = os.path.dirname(cert_path)
+ if not os.path.exists(cert_dir):
+ os.makedirs(cert_dir, mode=0700)
+ with open(cert_path, 'w') as outf:
+ outf.write(cert_str)
+ check_and_fix_urw_only(cert_path)
+ defer.returnValue({'get_cert': 'ok'})
+
def _setup(self, provider):
- """
- Set up EIPManager for a specified provider.
+ """Set up EIPManager for a specified provider.
:param provider: the provider to use, e.g. 'demo.bitmask.net'
- :type provider: str
- """
+ :type provider: str"""
# FIXME
# XXX picked manually from eip-service.json
remotes = (
- ("198.252.153.84", "1194"),
- ("46.165.242.169", "1194"),
+ ("198.252.153.84", "1194 "),
+ ("46.165.242.169", "1194 "),
)
prefix = os.path.join(self._basepath,
@@ -76,25 +127,3 @@ class EIPService(HookableService):
self._eip = EIPManager(remotes, cert_path, key_path, ca_path,
extra_flags)
-
- def startService(self):
- print "Starting EIP Service..."
- super(EIPService, self).startService()
-
- def stopService(self):
- print "Stopping EIP Service..."
- super(EIPService, self).stopService()
-
- def do_start(self, domain):
- self._setup(domain)
- self._eip.start()
- self._started = True
- return "Starting"
-
- def do_stop(self):
- if self._started:
- self._eip.stop()
- self._started = False
- return "Stopping"
- else:
- return "Not started"