summaryrefslogtreecommitdiff
path: root/src/leap
diff options
context:
space:
mode:
authorRuben Pollan <meskio@sindominio.net>2017-02-09 17:24:25 +0100
committerRuben Pollan <meskio@sindominio.net>2017-02-23 00:26:46 +0100
commit59cd23bd3e23bf2b439ad26271733a1b5c8edf68 (patch)
treef8c82c7cc5e0e2fbda93e6fc92a08852a60d1961 /src/leap
parent9f2b3b55ef08d908220f0b401aeec375d1c5ea07 (diff)
[feat] eliminate the active user from bonafide
Active user is now only a concept of the cli. For it we add a ~/.config/leap/bitmaskctl.cfg file. - Resolves: #8769
Diffstat (limited to 'src/leap')
-rw-r--r--src/leap/bitmask/bonafide/service.py25
-rwxr-xr-xsrc/leap/bitmask/cli/bitmask_cli.py16
-rw-r--r--src/leap/bitmask/cli/command.py4
-rw-r--r--src/leap/bitmask/cli/keys.py24
-rw-r--r--src/leap/bitmask/cli/mail.py9
-rw-r--r--src/leap/bitmask/cli/user.py33
-rw-r--r--src/leap/bitmask/config.py84
-rw-r--r--src/leap/bitmask/core/configurable.py74
-rw-r--r--src/leap/bitmask/core/dispatcher.py45
9 files changed, 171 insertions, 143 deletions
diff --git a/src/leap/bitmask/bonafide/service.py b/src/leap/bitmask/bonafide/service.py
index d48a54a7..37d1e214 100644
--- a/src/leap/bitmask/bonafide/service.py
+++ b/src/leap/bitmask/bonafide/service.py
@@ -42,10 +42,6 @@ class BonafideService(HookableService):
self._bonafide = BonafideProtocol()
self.service_hooks = defaultdict(list)
- # XXX this is a quick hack to get a ref
- # to the latest authenticated user.
- self._active_user = None
-
def startService(self):
logger.debug('starting Bonafide Service')
super(BonafideService, self).startService()
@@ -68,8 +64,6 @@ class BonafideService(HookableService):
data = dict(username=username, token=token, uuid=uuid,
password=password)
self.trigger_hook('on_bonafide_auth', **data)
-
- self._active_user = username
return result
# XXX I still have doubts from where it's best to trigger this.
@@ -93,18 +87,10 @@ class BonafideService(HookableService):
return d
def do_logout(self, username):
- if not username:
- username = self._active_user
-
- def reset_active(passthrough):
- self._active_user = None
- return passthrough
-
data = dict(username=username)
self.trigger_hook('on_bonafide_logout', **data)
d = self._bonafide.do_logout(username)
- d.addCallback(reset_active)
d.addCallback(lambda response: {'logout': 'ok'})
return d
@@ -134,18 +120,11 @@ class BonafideService(HookableService):
def do_provider_list(self, seeded=False):
return self._bonafide.do_provider_list(seeded)
- def do_get_smtp_cert(self, username=None):
- if not username:
- username = self._active_user
+ def do_get_smtp_cert(self, username):
if not username:
return defer.fail(
- RuntimeError('No active user, cannot get SMTP cert.'))
+ RuntimeError('No username, cannot get SMTP cert.'))
d = self._bonafide.do_get_smtp_cert(username)
d.addCallback(lambda response: (username, response))
return d
-
- def do_get_active_user(self):
- user = self._active_user or '<none>'
- info = {'user': user}
- return defer.succeed(info)
diff --git a/src/leap/bitmask/cli/bitmask_cli.py b/src/leap/bitmask/cli/bitmask_cli.py
index dfd1fbcd..782a52e5 100755
--- a/src/leap/bitmask/cli/bitmask_cli.py
+++ b/src/leap/bitmask/cli/bitmask_cli.py
@@ -25,6 +25,7 @@ import signal
from colorama import Fore
from twisted.internet import reactor, defer
+from leap.bitmask.config import Configuration
from leap.bitmask.cli.eip import Eip
from leap.bitmask.cli.keys import Keys
from leap.bitmask.cli.mail import Mail
@@ -62,27 +63,27 @@ GENERAL COMMANDS:
"about each command.")
def user(self, raw_args):
- user = User()
+ user = User(self.cfg)
return user.execute(raw_args)
def mail(self, raw_args):
- mail = Mail()
+ mail = Mail(self.cfg)
return mail.execute(raw_args)
def eip(self, raw_args):
- eip = Eip()
+ eip = Eip(self.cfg)
return eip.execute(raw_args)
def keys(self, raw_args):
- keys = Keys()
+ keys = Keys(self.cfg)
return keys.execute(raw_args)
def ui(self, raw_args):
- webui = WebUI()
+ webui = WebUI(self.cfg)
return webui.execute(raw_args)
def logs(self, raw_args):
- logs = Logs()
+ logs = Logs(self.cfg)
return logs.execute(raw_args)
# Single commands
@@ -129,7 +130,8 @@ GENERAL COMMANDS:
@defer.inlineCallbacks
def execute():
- cli = BitmaskCLI()
+ cfg = Configuration("bitmaskctl.cfg")
+ cli = BitmaskCLI(cfg)
cli.data = ['core', 'version']
args = ['--verbose'] if '--verbose' in sys.argv else None
yield cli._send(
diff --git a/src/leap/bitmask/cli/command.py b/src/leap/bitmask/cli/command.py
index 16f483a3..95b0fe8d 100644
--- a/src/leap/bitmask/cli/command.py
+++ b/src/leap/bitmask/cli/command.py
@@ -57,7 +57,9 @@ class Command(object):
"about each command.")
commands = []
- def __init__(self):
+ def __init__(self, cfg):
+ self.cfg = cfg
+
color_init()
zf = ZmqFactory()
e = ZmqEndpoint(ZmqEndpointType.connect, ENDPOINT)
diff --git a/src/leap/bitmask/cli/keys.py b/src/leap/bitmask/cli/keys.py
index 65747cb8..b11d2801 100644
--- a/src/leap/bitmask/cli/keys.py
+++ b/src/leap/bitmask/cli/keys.py
@@ -50,7 +50,11 @@ SUBCOMMANDS:
help='Use private keys (by default uses public)')
subargs = parser.parse_args(raw_args)
- self.data += ['list', subargs.uid]
+ userid = subargs.userid
+ if not userid:
+ userid = self.cfg.get('bonafide', 'active', default='')
+
+ self.data += ['list', userid]
if subargs.private:
self.data += ['private']
else:
@@ -69,7 +73,11 @@ SUBCOMMANDS:
parser.add_argument('address', nargs=1,
help='email address of the key')
subargs = parser.parse_args(raw_args)
- self.data += ['export', subargs.uid, subargs.address[0]]
+
+ userid = subargs.userid
+ if not userid:
+ userid = self.cfg.get('bonafide', 'active', default='')
+ self.data += ['export', userid, subargs.address[0]]
return self._send(self._print_key)
@@ -88,9 +96,13 @@ SUBCOMMANDS:
help='email address of the key')
subargs = parser.parse_args(raw_args)
+ userid = subargs.userid
+ if not userid:
+ userid = self.cfg.get('bonafide', 'active')
+
with open(subargs.file[0], 'r') as keyfile:
rawkey = keyfile.read()
- self.data += ['insert', subargs.uid, subargs.address[0],
+ self.data += ['insert', userid, subargs.address[0],
subargs.validation, rawkey]
return self._send(self._print_key)
@@ -106,8 +118,12 @@ SUBCOMMANDS:
parser.add_argument('address', nargs=1,
help='email address of the key')
subargs = parser.parse_args(raw_args)
- self.data += ['delete', subargs.uid, subargs.address[0]]
+ userid = subargs.userid
+ if not userid:
+ userid = self.cfg.get('bonafide', 'active')
+
+ self.data += ['delete', userid, subargs.address[0]]
return self._send()
def _print_key_list(self, keys):
diff --git a/src/leap/bitmask/cli/mail.py b/src/leap/bitmask/cli/mail.py
index 7fd574b9..025804eb 100644
--- a/src/leap/bitmask/cli/mail.py
+++ b/src/leap/bitmask/cli/mail.py
@@ -51,8 +51,15 @@ SUBCOMMANDS:
subargs = parser.parse_args(raw_args)
self.data.append('status')
+
+ uid = None
if subargs.uid:
- self.data.append(subargs.uid)
+ uid = subargs.uid
+ else:
+ uid = self.cfg.get('bonafide', 'active', default=None)
+ if uid:
+ self.data.append(uid)
+
return self._send(self._print_status)
def _print_status(self, status, depth=0):
diff --git a/src/leap/bitmask/cli/user.py b/src/leap/bitmask/cli/user.py
index b802d86b..a5cad1b0 100644
--- a/src/leap/bitmask/cli/user.py
+++ b/src/leap/bitmask/cli/user.py
@@ -23,6 +23,7 @@ import sys
from copy import copy
from colorama import Fore
+from twisted.internet import defer
from leap.bitmask.cli import command
@@ -44,10 +45,8 @@ SUBCOMMANDS:
'''.format(name=command.appname)
- commands = ['active']
-
- def __init__(self):
- super(User, self).__init__()
+ def __init__(self, cfg):
+ super(User, self).__init__(cfg)
self.data.append('user')
def create(self, raw_args):
@@ -75,7 +74,7 @@ SUBCOMMANDS:
args.pop(index + 1)
args.pop(index)
- username = self.username(args)
+ username = self._username(args, needed=True)
if not passwd:
passwd = self._getpass_twice()
self.data += ['create', username, passwd,
@@ -89,15 +88,20 @@ SUBCOMMANDS:
passwd = raw_args.pop(index + 1)
raw_args.pop(index)
- username = self.username(raw_args)
+ username = self._username(raw_args, needed=True)
if not passwd:
passwd = getpass.getpass()
self.data += ['authenticate', username, passwd, 'true']
+ self.cfg.set('bonafide', 'active', username)
return self._send(printer=command.default_dict_printer)
def logout(self, raw_args):
- username = self.username(raw_args)
+ username = self._username(raw_args)
self.data += ['logout', username]
+
+ active = self.cfg.get('bonafide', 'active', default=None)
+ if active == username:
+ self.cfg.set('bonafide', 'active', "")
return self._send(printer=command.default_dict_printer)
def list(self, raw_args):
@@ -105,13 +109,19 @@ SUBCOMMANDS:
return self._send(printer=self._print_user_list)
def update(self, raw_args):
- username = self.username(raw_args)
+ username = self._username(raw_args)
current_passwd = getpass.getpass('Current password: ')
new_passwd = self._getpass_twice('New password: ')
self.data += ['update', username, current_passwd, new_passwd]
return self._send(printer=command.default_dict_printer)
- def username(self, raw_args):
+ def active(self, raw_args):
+ username = self.cfg.get('bonafide', 'active', default='<none>')
+ print(Fore.RESET + 'active'.ljust(10) + Fore.GREEN + username +
+ Fore.RESET)
+ return defer.succeed(None)
+
+ def _username(self, raw_args, needed=False):
args = tuple([command.appname] + sys.argv[1:3])
parser = argparse.ArgumentParser(
description='Bitmask user',
@@ -121,7 +131,10 @@ SUBCOMMANDS:
username = subargs.username
if not username:
- self._error("Missing username ID but needed for this command")
+ if needed:
+ self._error("Missing username ID but needed for this command")
+ else:
+ return self.cfg.get('bonafide', 'active')
if '@' not in username:
self._error("Username ID must be in the form <user@example.org>")
diff --git a/src/leap/bitmask/config.py b/src/leap/bitmask/config.py
new file mode 100644
index 00000000..a09a2bc5
--- /dev/null
+++ b/src/leap/bitmask/config.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+# config.py
+# Copyright (C) 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
+# 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/>.
+"""
+Configuration parser/writter
+"""
+import ConfigParser
+import os
+
+from leap.common import files
+from leap.common.config import get_path_prefix
+
+
+DEFAULT_BASEDIR = os.path.join(get_path_prefix(), 'leap')
+
+
+class MissingConfigEntry(Exception):
+ """
+ A required config entry was not found.
+ """
+
+
+class Configuration(object):
+
+ def __init__(self, config_file, basedir=DEFAULT_BASEDIR,
+ default_config=""):
+ path = os.path.abspath(os.path.expanduser(basedir))
+ if not os.path.isdir(path):
+ files.mkdir_p(path)
+ self.config_path = os.path.join(path, config_file)
+ self.default_config = default_config
+
+ self.read()
+
+ def get(self, section, option, default=None, boolean=False):
+ try:
+ if boolean:
+ return self.config.getboolean(section, option)
+
+ item = self.config.get(section, option)
+ return item
+
+ except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
+ if default is None:
+ raise MissingConfigEntry("%s is missing the [%s]%s entry"
+ % self.config_path, section, option)
+ return default
+
+ def set(self, section, option, value):
+ if not self.config.has_section(section):
+ self.config.add_section(section)
+ self.config.set(section, option, value)
+ self.save()
+ self.read()
+ assert self.config.get(section, option) == value
+
+ def read(self):
+ self.config = ConfigParser.SafeConfigParser()
+ if not os.path.isfile(self.config_path):
+ self._create_default_config()
+
+ with open(self.config_path, "rb") as f:
+ self.config.readfp(f)
+
+ def save(self):
+ with open(self.config_path, 'wb') as f:
+ self.config.write(f)
+
+ def _create_default_config(self):
+ with open(self.config_path, 'w') as outf:
+ outf.write(self.default_config)
diff --git a/src/leap/bitmask/core/configurable.py b/src/leap/bitmask/core/configurable.py
index f305cc3c..51a100d6 100644
--- a/src/leap/bitmask/core/configurable.py
+++ b/src/leap/bitmask/core/configurable.py
@@ -17,22 +17,13 @@
"""
Configurable Backend for Bitmask Service.
"""
-import ConfigParser
-import os
-
from twisted.application import service
-from leap.common import files
-from leap.common.config import get_path_prefix
-
-
-DEFAULT_BASEDIR = os.path.join(get_path_prefix(), 'leap')
-
-
-class MissingConfigEntry(Exception):
- """
- A required config entry was not found.
- """
+from leap.bitmask.config import (
+ Configuration,
+ DEFAULT_BASEDIR,
+ MissingConfigEntry
+)
class ConfigurableService(service.MultiService):
@@ -42,59 +33,14 @@ class ConfigurableService(service.MultiService):
def __init__(self, basedir=DEFAULT_BASEDIR):
service.MultiService.__init__(self)
-
- path = os.path.abspath(os.path.expanduser(basedir))
- if not os.path.isdir(path):
- files.mkdir_p(path)
- self.basedir = path
-
- # creates self.config
- self.read_config()
+ self.cfg = Configuration(self.config_file, basedir, DEFAULT_CONFIG)
+ self.basedir = basedir
def get_config(self, section, option, default=None, boolean=False):
- try:
- if boolean:
- return self.config.getboolean(section, option)
-
- item = self.config.get(section, option)
- return item
-
- except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
- if default is None:
- fn = self._get_config_path()
- raise MissingConfigEntry("%s is missing the [%s]%s entry"
- % fn, section, option)
- return default
+ return self.cfg.get(section, option, default=default, boolean=boolean)
def set_config(self, section, option, value):
- if not self.config.has_section(section):
- self.config.add_section(section)
- self.config.set(section, option, value)
- self.save_config()
- self.read_config()
- assert self.config.get(section, option) == value
-
- def read_config(self):
- self.config = ConfigParser.SafeConfigParser()
- bitmaskd_cfg = self._get_config_path()
-
- if not os.path.isfile(bitmaskd_cfg):
- self._create_default_config(bitmaskd_cfg)
-
- with open(bitmaskd_cfg, "rb") as f:
- self.config.readfp(f)
-
- def save_config(self):
- bitmaskd_cfg = self._get_config_path()
- with open(bitmaskd_cfg, 'wb') as f:
- self.config.write(f)
-
- def _create_default_config(self, path):
- with open(path, 'w') as outf:
- outf.write(DEFAULT_CONFIG)
-
- def _get_config_path(self):
- return os.path.join(self.basedir, self.config_file)
+ return self.cfg.set(section, option, value)
DEFAULT_CONFIG = """
@@ -106,3 +52,5 @@ web = True
onion = False
websockets = False
"""
+
+__all__ = ["ConfigurableService", DEFAULT_BASEDIR, MissingConfigEntry]
diff --git a/src/leap/bitmask/core/dispatcher.py b/src/leap/bitmask/core/dispatcher.py
index 2777d9a9..1e95ce28 100644
--- a/src/leap/bitmask/core/dispatcher.py
+++ b/src/leap/bitmask/core/dispatcher.py
@@ -174,10 +174,6 @@ class UserCmd(SubCommand):
return bonafide.do_change_password(
user, current_password, new_password)
- @register_method('str')
- def do_ACTIVE(self, bonafide, *parts):
- return bonafide.do_get_active_user()
-
class EIPCmd(SubCommand):
@@ -200,9 +196,11 @@ class EIPCmd(SubCommand):
@register_method('dict')
def do_START(self, eip, *parts):
- # TODO --- attempt to get active provider
- # TODO or catch the exception and send error
- provider = parts[2]
+ try:
+ provider = parts[2]
+ except IndexError:
+ raise DispatchError(
+ 'wrong number of arguments: expected 1, got none')
d = eip.do_start(provider)
return d
@@ -267,17 +265,15 @@ class KeysCmd(SubCommand):
@register_method("[dict]")
def do_LIST(self, service, *parts, **kw):
+ if len(parts) < 3:
+ raise ValueError("A uid is needed")
uid = parts[2]
private = False
if parts[-1] == 'private':
private = True
- d = defer.succeed(uid)
- if not uid:
- d = self._get_active_user(kw['bonafide'])
- d.addCallback(service.do_list_keys, private)
- return d
+ return service.do_list_keys(uid, private)
@register_method('dict')
def do_EXPORT(self, service, *parts, **kw):
@@ -290,14 +286,9 @@ class KeysCmd(SubCommand):
if parts[-1] == 'private':
private = True
- d = defer.succeed(uid)
- if not uid:
- d = self._get_active_user(kw['bonafide'])
- d.addCallback(service.do_export, address, private)
- return d
+ return service.do_export(uid, address, private)
@register_method('dict')
- @defer.inlineCallbacks
def do_INSERT(self, service, *parts, **kw):
if len(parts) < 6:
raise ValueError("An email address is needed")
@@ -306,14 +297,9 @@ class KeysCmd(SubCommand):
validation = parts[4]
rawkey = parts[5]
- d = defer.succeed(uid)
- if not uid:
- d = self._get_active_user(kw['bonafide'])
- d.addCallback(service.do_insert, address, rawkey, validation)
- return d
+ return service.do_insert(uid, address, rawkey, validation)
@register_method('str')
- @defer.inlineCallbacks
def do_DELETE(self, service, *parts, **kw):
if len(parts) < 4:
raise ValueError("An email address is needed")
@@ -324,16 +310,7 @@ class KeysCmd(SubCommand):
if parts[-1] == 'private':
private = True
- d = defer.succeed(uid)
- if not uid:
- d = self._get_active_user(kw['bonafide'])
- d.addCallback(service.do_delete, address, private)
- return d
-
- def _get_active_user(self, bonafide):
- d = bonafide.do_get_active_user()
- d.addCallback(lambda active: active['user'])
- return d
+ return service.do_delete(uid, address, private)
class EventsCmd(SubCommand):