diff options
author | Ruben Pollan <meskio@sindominio.net> | 2017-02-06 19:38:58 +0100 |
---|---|---|
committer | Ruben Pollan <meskio@sindominio.net> | 2017-02-09 18:35:54 +0100 |
commit | 374bb846b15596f99da77a4a7c9a348187774534 (patch) | |
tree | b76b30ba3240b892817a0006d98523cf75c44199 | |
parent | 546190e59ba11fe109d933f4f22fed5398f86010 (diff) |
[feat] add account based keymanagement API
- Resolves: #8755
-rw-r--r-- | src/leap/bitmask/cli/keys.py | 18 | ||||
-rw-r--r-- | src/leap/bitmask/core/dispatcher.py | 56 | ||||
-rw-r--r-- | src/leap/bitmask/core/mail_services.py | 23 | ||||
-rw-r--r-- | tests/unit/core/test_services.py | 8 | ||||
-rw-r--r-- | ui/app/lib/bitmask.js | 20 |
5 files changed, 84 insertions, 41 deletions
diff --git a/src/leap/bitmask/cli/keys.py b/src/leap/bitmask/cli/keys.py index 4683ac23..65747cb8 100644 --- a/src/leap/bitmask/cli/keys.py +++ b/src/leap/bitmask/cli/keys.py @@ -44,11 +44,13 @@ SUBCOMMANDS: parser = argparse.ArgumentParser( description='Bitmask list keys', prog='%s %s %s' % tuple(sys.argv[:3])) + parser.add_argument('-u', '--userid', default='', + help='Select the userid of the keyring') parser.add_argument('--private', action='store_true', help='Use private keys (by default uses public)') subargs = parser.parse_args(raw_args) - self.data += ['list'] + self.data += ['list', subargs.uid] if subargs.private: self.data += ['private'] else: @@ -60,12 +62,14 @@ SUBCOMMANDS: parser = argparse.ArgumentParser( description='Bitmask export key', prog='%s %s %s' % tuple(sys.argv[:3])) + parser.add_argument('-u', '--userid', default='', + help='Select the userid of the keyring') parser.add_argument('--private', action='store_true', help='Use private keys (by default uses public)') parser.add_argument('address', nargs=1, help='email address of the key') subargs = parser.parse_args(raw_args) - self.data += ['export', subargs.address[0]] + self.data += ['export', subargs.uid, subargs.address[0]] return self._send(self._print_key) @@ -73,6 +77,8 @@ SUBCOMMANDS: parser = argparse.ArgumentParser( description='Bitmask import key', prog='%s %s %s' % tuple(sys.argv[:3])) + parser.add_argument('-u', '--userid', default='', + help='Select the userid of the keyring') parser.add_argument('--validation', choices=list(ValidationLevels), default='Fingerprint', help='Validation level for the key') @@ -84,8 +90,8 @@ SUBCOMMANDS: with open(subargs.file[0], 'r') as keyfile: rawkey = keyfile.read() - self.data += ['insert', subargs.address[0], subargs.validation, - rawkey] + self.data += ['insert', subargs.uid, subargs.address[0], + subargs.validation, rawkey] return self._send(self._print_key) @@ -93,12 +99,14 @@ SUBCOMMANDS: parser = argparse.ArgumentParser( description='Bitmask delete key', prog='%s %s %s' % tuple(sys.argv[:3])) + parser.add_argument('-u', '--userid', default='', + help='Select the userid of the keyring') parser.add_argument('--private', action='store_true', help='Use private keys (by default uses public)') parser.add_argument('address', nargs=1, help='email address of the key') subargs = parser.parse_args(raw_args) - self.data += ['delete', subargs.address[0]] + self.data += ['delete', subargs.uid, subargs.address[0]] return self._send() diff --git a/src/leap/bitmask/core/dispatcher.py b/src/leap/bitmask/core/dispatcher.py index 7c1cdbd4..2777d9a9 100644 --- a/src/leap/bitmask/core/dispatcher.py +++ b/src/leap/bitmask/core/dispatcher.py @@ -267,58 +267,74 @@ class KeysCmd(SubCommand): @register_method("[dict]") def do_LIST(self, service, *parts, **kw): + uid = parts[2] + private = False if parts[-1] == 'private': private = True - bonafide = kw['bonafide'] - d = bonafide.do_get_active_user() + d = defer.succeed(uid) + if not uid: + d = self._get_active_user(kw['bonafide']) d.addCallback(service.do_list_keys, private) return d @register_method('dict') def do_EXPORT(self, service, *parts, **kw): - if len(parts) < 3: - return defer.fail("An email address is needed") - address = parts[2] + if len(parts) < 4: + raise ValueError("An email address is needed") + uid = parts[2] + address = parts[3] private = False if parts[-1] == 'private': private = True - bonafide = kw['bonafide'] - d = bonafide.do_get_active_user() + d = defer.succeed(uid) + if not uid: + d = self._get_active_user(kw['bonafide']) d.addCallback(service.do_export, address, private) return d @register_method('dict') + @defer.inlineCallbacks def do_INSERT(self, service, *parts, **kw): - if len(parts) < 5: - return defer.fail("An email address is needed") - address = parts[2] - validation = parts[3] - rawkey = parts[4] - - bonafide = kw['bonafide'] - d = bonafide.do_get_active_user() + if len(parts) < 6: + raise ValueError("An email address is needed") + uid = parts[2] + address = parts[3] + 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 @register_method('str') + @defer.inlineCallbacks def do_DELETE(self, service, *parts, **kw): - if len(parts) < 3: - return defer.fail("An email address is needed") - address = parts[2] + if len(parts) < 4: + raise ValueError("An email address is needed") + uid = parts[2] + address = parts[3] private = False if parts[-1] == 'private': private = True - bonafide = kw['bonafide'] - d = bonafide.do_get_active_user() + 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 + class EventsCmd(SubCommand): diff --git a/src/leap/bitmask/core/mail_services.py b/src/leap/bitmask/core/mail_services.py index 2842b5d8..b1bdea25 100644 --- a/src/leap/bitmask/core/mail_services.py +++ b/src/leap/bitmask/core/mail_services.py @@ -397,19 +397,31 @@ class KeymanagerService(HookableService): # commands def do_list_keys(self, userid, private=False): - km = self._container.get_instance(userid['user']) + km = self._container.get_instance(userid) + if km is None: + return defer.fail(ValueError("User " + userid + " has no active " + "keymanager")) + d = km.get_all_keys(private=private) d.addCallback(lambda keys: [dict(key) for key in keys]) return d def do_export(self, userid, address, private=False): - km = self._container.get_instance(userid['user']) + km = self._container.get_instance(userid) + if km is None: + return defer.fail(ValueError("User " + userid + " has no active " + "keymanager")) + d = km.get_key(address, private=private, fetch_remote=False) d.addCallback(lambda key: dict(key)) return d def do_insert(self, userid, address, rawkey, validation='Fingerprint'): - km = self._container.get_instance(userid['user']) + km = self._container.get_instance(userid) + if km is None: + return defer.fail(ValueError("User " + userid + " has no active " + "keymanager")) + validation = ValidationLevels.get(validation) d = km.put_raw_key(rawkey, address, validation=validation) d.addCallback(lambda _: km.get_key(address, fetch_remote=False)) @@ -418,7 +430,10 @@ class KeymanagerService(HookableService): @defer.inlineCallbacks def do_delete(self, userid, address, private=False): - km = self._container.get_instance(userid['user']) + km = self._container.get_instance(userid) + if km is None: + raise ValueError("User " + userid + " has no active keymanager") + key = yield km.get_key(address, private=private, fetch_remote=False) km.delete_key(key) defer.returnValue(key.fingerprint) diff --git a/tests/unit/core/test_services.py b/tests/unit/core/test_services.py index bb00dce9..1b0e80c9 100644 --- a/tests/unit/core/test_services.py +++ b/tests/unit/core/test_services.py @@ -9,25 +9,25 @@ class KeymanagerServiceTestCase(unittest.TestCase): @defer.inlineCallbacks def test_keymanager_service_list_call(self): kms = keymanagerServiceFactory() - yield kms.do_list_keys({'user': 'user'}) + yield kms.do_list_keys('user') assert kms._keymanager.loopback == ['get_all_keys'] @defer.inlineCallbacks def test_keymanager_service_export_call(self): kms = keymanagerServiceFactory() - yield kms.do_export({'user': 'user'}, 'foo@bar') + yield kms.do_export('user', 'foo@bar') assert kms._keymanager.loopback == ['get_key'] @defer.inlineCallbacks def test_keymanager_service_insert_call(self): kms = keymanagerServiceFactory() - yield kms.do_insert({'user': 'user'}, 'foo@bar', 'aaaa') + yield kms.do_insert('user', 'foo@bar', 'aaaa') assert kms._keymanager.loopback == ['put_raw_key', 'get_key'] @defer.inlineCallbacks def test_keymanager_service_delete_call(self): kms = keymanagerServiceFactory() - yield kms.do_delete({'user': 'user'}, 'foo@bar') + yield kms.do_delete('user', 'foo@bar') assert kms._keymanager.loopback == ['get_key', 'delete_key'] diff --git a/ui/app/lib/bitmask.js b/ui/app/lib/bitmask.js index 21dbb652..8bcb01fe 100644 --- a/ui/app/lib/bitmask.js +++ b/ui/app/lib/bitmask.js @@ -265,31 +265,34 @@ var bitmask = function(){ /** * List all the keys in the keyring * + * @param {string} uid The uid of the keyring. * @param {boolean} priv Should list private keys? * If it's not provided the public ones will be listed. * * @return {Promise<[KeyObject]>} List of keys in the keyring */ - list: function(priv) { - return call(['keys', 'list', private_str(priv)]); + list: function(uid, priv) { + return call(['keys', 'list', uid, private_str(priv)]); }, /** * Export key * + * @param {string} uid The uid of the keyring. * @param {string} address The email address of the key * @param {boolean} priv Should get the private key? * If it's not provided the public one will be fetched. * * @return {Promise<KeyObject>} The key */ - exprt: function(address, priv) { - return call(['keys', 'export', address, private_str(priv)]); + exprt: function(uid, address, priv) { + return call(['keys', 'export', uid, address, private_str(priv)]); }, /** * Insert key * + * @param {string} uid The uid of the keyring. * @param {string} address The email address of the key * @param {string} rawkey The key material * @param {string} validation The validation level of the key @@ -297,24 +300,25 @@ var bitmask = function(){ * * @return {Promise<KeyObject>} The key */ - insert: function(address, rawkey, validation) { + insert: function(uid, address, rawkey, validation) { if (typeof validation !== 'string') { validation = 'Fingerprint'; } - return call(['keys', 'insert', address, validation, rawkey]); + return call(['keys', 'insert', uid, address, validation, rawkey]); }, /** * Delete a key * + * @param {string} uid The uid of the keyring. * @param {string} address The email address of the key * @param {boolean} priv Should get the private key? * If it's not provided the public one will be deleted. * * @return {Promise<KeyObject>} The key */ - del: function(address, priv) { - return call(['keys', 'delete', address, private_str(priv)]); + del: function(uid, address, priv) { + return call(['keys', 'delete', uid, address, private_str(priv)]); } }, |