diff --git a/aries_cloudagent/wallet/askar.py b/aries_cloudagent/wallet/askar.py index efea7120bb..6b09c31365 100644 --- a/aries_cloudagent/wallet/askar.py +++ b/aries_cloudagent/wallet/askar.py @@ -115,7 +115,7 @@ async def create_key( ) from None raise WalletError("Error creating signing key") from err - return KeyInfo(verkey=verkey, metadata=metadata, key_type=key_type) + return KeyInfo(verkey=verkey, metadata=metadata, key_type=key_type, kid=kid) async def assign_kid_to_key(self, verkey: str, kid: str) -> KeyInfo: """Assign a KID to a key. @@ -143,7 +143,7 @@ async def assign_kid_to_key(self, verkey: str, kid: str) -> KeyInfo: raise WalletError(f"Unknown key type {key.algorithm.value}") await self._session.handle.update_key(name=verkey, tags={"kid": kid}) - return KeyInfo(verkey=verkey, metadata=metadata, key_type=key_type) + return KeyInfo(verkey=verkey, metadata=metadata, key_type=key_type, kid=kid) async def get_key_by_kid(self, kid: str) -> KeyInfo: """Fetch a key by looking up its kid. @@ -194,7 +194,7 @@ async def get_signing_key(self, verkey: str) -> KeyInfo: raise WalletNotFoundError("Unknown key: {}".format(verkey)) metadata = json.loads(key.metadata or "{}") # FIXME implement key types - return KeyInfo(verkey=verkey, metadata=metadata, key_type=ED25519) + return KeyInfo(verkey=verkey, metadata=metadata, key_type=ED25519, kid=key.kid) async def replace_signing_key_metadata(self, verkey: str, metadata: dict): """Replace the metadata associated with a signing keypair. diff --git a/aries_cloudagent/wallet/did_info.py b/aries_cloudagent/wallet/did_info.py index 3ef891a966..e5a2458a3c 100644 --- a/aries_cloudagent/wallet/did_info.py +++ b/aries_cloudagent/wallet/did_info.py @@ -7,9 +7,14 @@ INVITATION_REUSE_KEY = "invitation_reuse" -KeyInfo = NamedTuple( - "KeyInfo", [("verkey", str), ("metadata", dict), ("key_type", KeyType)] -) + +class KeyInfo(NamedTuple): + verkey: str + metadata: dict + key_type: KeyType + kid: str = None + + DIDInfo = NamedTuple( "DIDInfo", [ diff --git a/aries_cloudagent/wallet/in_memory.py b/aries_cloudagent/wallet/in_memory.py index cbd1f00960..f798e2264a 100644 --- a/aries_cloudagent/wallet/in_memory.py +++ b/aries_cloudagent/wallet/in_memory.py @@ -95,6 +95,7 @@ async def create_key( verkey=verkey_enc, metadata=self.profile.keys[verkey_enc]["metadata"].copy(), key_type=key_type, + kid=kid, ) async def assign_kid_to_key(self, verkey: str, kid: str) -> KeyInfo: @@ -120,6 +121,7 @@ async def assign_kid_to_key(self, verkey: str, kid: str) -> KeyInfo: verkey=key["verkey"], metadata=key["metadata"].copy(), key_type=key["key_type"], + kid=kid, ) async def get_key_by_kid(self, kid: str) -> KeyInfo: @@ -138,6 +140,7 @@ async def get_key_by_kid(self, kid: str) -> KeyInfo: verkey=key["verkey"], metadata=key["metadata"].copy(), key_type=key["key_type"], + kid=key["kid"], ) raise WalletNotFoundError(f"Key not found with kid {kid}") @@ -162,6 +165,7 @@ async def get_signing_key(self, verkey: str) -> KeyInfo: verkey=key["verkey"], metadata=key["metadata"].copy(), key_type=key["key_type"], + kid=key["kid"], ) async def replace_signing_key_metadata(self, verkey: str, metadata: dict): diff --git a/aries_cloudagent/wallet/keys/askar.py b/aries_cloudagent/wallet/keys/askar.py deleted file mode 100644 index 3d38a5f1b0..0000000000 --- a/aries_cloudagent/wallet/keys/askar.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import List, Optional, Sequence, Tuple, Union, cast -from ..base import BaseWallet -from ..util import b58_to_bytes, bytes_to_b58 -from aries_askar import Key - - -class AskarWallet(BaseWallet): - """Aries-Askar wallet implementation.""" - - async def get_local_keys(self): - """Get list of defined local DIDs. - - Returns: - A list of locally stored DIDs as `DIDInfo` instances - - """ - key_entries = await self._session.handle.fetch_all_keys( - # tag_filter={"kid": kid}, limit=2 - ) - entry = key_entries[0] - key = cast(Key, entry.key) - verkey = bytes_to_b58(key.get_public_bytes()) - return verkey - - async def get_local_key(self, kid: str): - """Get list of defined local DIDs. - - Returns: - A list of locally stored DIDs as `DIDInfo` instances - - """ - key_entries = await self._session.handle.fetch_all_keys( - tag_filter={"kid": kid}, limit=2 - ) - entry = key_entries[0] - key = cast(Key, entry.key) - verkey = bytes_to_b58(key.get_public_bytes()) - return verkey diff --git a/aries_cloudagent/wallet/keys/manager.py b/aries_cloudagent/wallet/keys/manager.py index b653eefbe7..df42c62309 100644 --- a/aries_cloudagent/wallet/keys/manager.py +++ b/aries_cloudagent/wallet/keys/manager.py @@ -7,13 +7,10 @@ from ...utils.multiformats import multibase ALG_MAPPINGS = { - "ed25519": { - 'key_type': ED25519, - 'prefix_hex': 'ed01', - 'prefix_lenght': 2 - } + "ed25519": {"key_type": ED25519, "prefix_hex": "ed01", "prefix_lenght": 2} } + class MultikeyManagerError(Exception): """Generic MultikeyManager Error.""" @@ -26,12 +23,12 @@ def __init__(self, profile=Profile): self.profile = profile def _multikey_to_verkey(self, multikey, alg="ed25519"): - prefix_lenght = ALG_MAPPINGS[alg]['prefix_lenght'] + prefix_lenght = ALG_MAPPINGS[alg]["prefix_lenght"] public_bytes = bytes(bytearray(multibase.decode(multikey))[prefix_lenght:]) return bytes_to_b58(public_bytes) def _verkey_to_multikey(self, verkey, alg="ed25519"): - prefix_hex = ALG_MAPPINGS[alg]['prefix_hex'] + prefix_hex = ALG_MAPPINGS[alg]["prefix_hex"] prefixed_key_hex = f"{prefix_hex}{b58_to_bytes(verkey).hex()}" return multibase.encode(bytes.fromhex(prefixed_key_hex), "base58btc") @@ -48,7 +45,10 @@ async def from_multikey(self, multikey: str): wallet = session.inject(BaseWallet) verkey = self._multikey_to_verkey(multikey) key_info = await wallet.get_signing_key(verkey=verkey) - return self._verkey_to_multikey(key_info.verkey) + return { + "kid": key_info.kid, + "multikey": self._verkey_to_multikey(key_info.verkey), + } async def create(self, seed=None, kid=None, alg="ed25519"): """Create a new key pair.""" @@ -62,11 +62,12 @@ async def create(self, seed=None, kid=None, alg="ed25519"): except: pass - key_type = ALG_MAPPINGS[alg]['key_type'] - key_info = await wallet.create_key( - key_type=key_type, seed=seed, kid=kid - ) - return self._verkey_to_multikey(key_info.verkey) + key_type = ALG_MAPPINGS[alg]["key_type"] + key_info = await wallet.create_key(key_type=key_type, seed=seed, kid=kid) + return { + "kid": key_info.kid, + "multikey": self._verkey_to_multikey(key_info.verkey), + } async def update(self, multikey: str, kid: str): """Assign a new kid to a key pair.""" @@ -82,10 +83,9 @@ async def update(self, multikey: str, kid: str): try: verkey = self._multikey_to_verkey(multikey) except: - raise MultikeyManagerError( - f"Invalid multikey value {multikey}." - ) - key_info = await wallet.assign_kid_to_key( - verkey=verkey, kid=kid - ) - return self._verkey_to_multikey(key_info.verkey) + raise MultikeyManagerError(f"Invalid multikey value {multikey}.") + key_info = await wallet.assign_kid_to_key(verkey=verkey, kid=kid) + return { + "kid": key_info.kid, + "multikey": self._verkey_to_multikey(key_info.verkey), + } diff --git a/aries_cloudagent/wallet/keys/routes.py b/aries_cloudagent/wallet/keys/routes.py index cb8b12b269..a7a816148d 100644 --- a/aries_cloudagent/wallet/keys/routes.py +++ b/aries_cloudagent/wallet/keys/routes.py @@ -3,8 +3,8 @@ import logging from aiohttp import web -from aiohttp_apispec import docs, querystring_schema, request_schema, response_schema -from marshmallow import fields, validate +from aiohttp_apispec import docs, request_schema, response_schema +from marshmallow import fields from ...admin.decorators.auth import tenant_authentication from ...admin.request_context import AdminRequestContext @@ -42,7 +42,14 @@ class CreateKeyResponseSchema(OpenAPISchema): multikey = fields.Str( metadata={ "description": "The Public Key Multibase format (multikey)", - "example": "", + "example": "z6MkgKA7yrw5kYSiDuQFcye4bMaJpcfHFry3Bx45pdWh3s8i", + }, + ) + + kid = fields.Str( + metadata={ + "description": "The associated kid", + "example": "did:web:example.com#key-01", }, ) @@ -54,7 +61,7 @@ class UpdateKeyRequestSchema(OpenAPISchema): required=True, metadata={ "description": "Multikey of the key pair to update", - "example": "", + "example": "z6MkgKA7yrw5kYSiDuQFcye4bMaJpcfHFry3Bx45pdWh3s8i", }, ) @@ -74,7 +81,14 @@ class UpdateKeyResponseSchema(OpenAPISchema): multikey = fields.Str( metadata={ "description": "The Public Key Multibase format (multikey)", - "example": "", + "example": "z6MkgKA7yrw5kYSiDuQFcye4bMaJpcfHFry3Bx45pdWh3s8i", + }, + ) + + kid = fields.Str( + metadata={ + "description": "The associated kid", + "example": "did:web:example.com#key-01", }, ) @@ -85,7 +99,14 @@ class FetchKeyResponseSchema(OpenAPISchema): multikey = fields.Str( metadata={ "description": "The Public Key Multibase format (multikey)", - "example": "", + "example": "z6MkgKA7yrw5kYSiDuQFcye4bMaJpcfHFry3Bx45pdWh3s8i", + }, + ) + + kid = fields.Str( + metadata={ + "description": "The associated kid", + "example": "did:web:example.com#key-01", }, ) @@ -103,14 +124,10 @@ async def fetch_key(request: web.BaseRequest): context: AdminRequestContext = request["context"] multikey = request.match_info["multikey"] try: - key_info = await MultikeyManager(context.profile).fetch( + key_info = await MultikeyManager(context.profile).from_multikey( multikey=multikey, ) - print(key_info) - return web.json_response( - {}, - status=200, - ) + return web.json_response(key_info, status=200) except (MultikeyManagerError, WalletDuplicateError, WalletNotFoundError) as err: return web.json_response({"message": str(err)}, status=400) @@ -131,22 +148,19 @@ async def create_key(request: web.BaseRequest): """ context: AdminRequestContext = request["context"] body = await request.json() - + seed = body.get("seed") or None if seed and not context.settings.get("wallet.allow_insecure_seed"): raise web.HTTPBadRequest(reason="Seed support is not enabled.") - - kid = body.get("verification_method") or None - + + kid = body.get("verificationMethod") or None + try: - multikey = await MultikeyManager(context.profile).create( + key_info = await MultikeyManager(context.profile).create( seed=seed, kid=kid, ) - return web.json_response( - {"multikey": multikey}, - status=201, - ) + return web.json_response(key_info, status=201) except (MultikeyManagerError, WalletDuplicateError, WalletNotFoundError) as err: return web.json_response({"message": str(err)}, status=400) @@ -167,19 +181,16 @@ async def update_key(request: web.BaseRequest): """ context: AdminRequestContext = request["context"] body = await request.json() - + multikey = body.get("multikey") - kid = body.get("verification_method") - + kid = body.get("verificationMethod") + try: - multikey = await MultikeyManager(context.profile).update( + key_info = await MultikeyManager(context.profile).update( multikey=multikey, kid=kid, ) - return web.json_response( - {"multikey": multikey}, - status=200, - ) + return web.json_response(key_info, status=200) except (MultikeyManagerError, WalletDuplicateError, WalletNotFoundError) as err: return web.json_response({"message": str(err)}, status=400) diff --git a/aries_cloudagent/wallet/keys/tests/test_key_operations.py b/aries_cloudagent/wallet/keys/tests/test_key_operations.py index 6beb743978..2443af715c 100644 --- a/aries_cloudagent/wallet/keys/tests/test_key_operations.py +++ b/aries_cloudagent/wallet/keys/tests/test_key_operations.py @@ -18,19 +18,11 @@ async def test_key_creation(self): assert multikey == self.multikey async def test_key_binding(self): - multikey = await self.manager.create( - seed=self.seed, kid=self.kid - ) + multikey = await self.manager.create(seed=self.seed, kid=self.kid) assert multikey == self.multikey - multikey = await self.manager.from_kid( - kid=self.kid - ) + multikey = await self.manager.from_kid(kid=self.kid) assert multikey == self.multikey - multikey = await self.manager.update( - multikey=multikey, kid=self.new_kid - ) + multikey = await self.manager.update(multikey=multikey, kid=self.new_kid) assert multikey == self.multikey - multikey = await self.manager.from_kid( - kid=self.new_kid - ) + multikey = await self.manager.from_kid(kid=self.new_kid) assert multikey == self.multikey