diff --git a/aries_cloudagent/protocols/out_of_band/v1_0/manager.py b/aries_cloudagent/protocols/out_of_band/v1_0/manager.py index 532d7fcd0c..aa3cb14435 100644 --- a/aries_cloudagent/protocols/out_of_band/v1_0/manager.py +++ b/aries_cloudagent/protocols/out_of_band/v1_0/manager.py @@ -6,6 +6,7 @@ from ....config.injection_context import InjectionContext from ....core.error import BaseError from ....ledger.base import BaseLedger +from ....wallet.util import did_key_to_naked, naked_to_did_key from ....protocols.connections.v1_0.manager import ConnectionManager from ....protocols.connections.v1_0.messages.connection_invitation import ( ConnectionInvitation, @@ -142,8 +143,14 @@ async def create_invitation( service = ServiceMessage( _id="#inline", _type="did-communication", - recipient_keys=connection_invitation.recipient_keys, - routing_keys=connection_invitation.routing_keys, + recipient_keys=[ + naked_to_did_key(key) + for key in connection_invitation.recipient_keys or [] + ], + routing_keys=[ + naked_to_did_key(key) + for key in connection_invitation.routing_keys or [] + ], service_endpoint=connection_invitation.endpoint, ).validate() @@ -196,17 +203,19 @@ async def receive_invitation( # Get the single service item if invitation_message.service_blocks: service = invitation_message.service_blocks[0] + else: # If it's in the did format, we need to convert to a full service block service_did = invitation_message.service_dids[0] async with ledger: verkey = await ledger.get_key_for_did(service_did) + did_key = naked_to_did_key(verkey) endpoint = await ledger.get_endpoint_for_did(service_did) service = ServiceMessage.deserialize( { "id": "#inline", "type": "did-communication", - "recipientKeys": [verkey], + "recipientKeys": [did_key], "routingKeys": [], "serviceEndpoint": endpoint, } @@ -224,6 +233,14 @@ async def receive_invitation( "request block must be empty for invitation message type." ) + # Transform back to 'naked' verkey + service.recipient_keys = [ + did_key_to_naked(key) for key in service.recipient_keys or [] + ] + service.routing_keys = [ + did_key_to_naked(key) for key in service.routing_keys + ] or [] + # Convert to the old message format connection_invitation = ConnectionInvitation.deserialize( { diff --git a/aries_cloudagent/protocols/out_of_band/v1_0/messages/service.py b/aries_cloudagent/protocols/out_of_band/v1_0/messages/service.py index 44368ce5cd..f10f53ee29 100644 --- a/aries_cloudagent/protocols/out_of_band/v1_0/messages/service.py +++ b/aries_cloudagent/protocols/out_of_band/v1_0/messages/service.py @@ -5,7 +5,7 @@ from marshmallow import EXCLUDE, fields from .....messaging.models.base import BaseModel, BaseModelSchema -from .....messaging.valid import INDY_DID, INDY_RAW_PUBLIC_KEY +from .....messaging.valid import INDY_DID, DID_KEY class Service(BaseModel): @@ -59,14 +59,14 @@ class Meta: did = fields.Str(required=False, description="", **INDY_DID) recipient_keys = fields.List( - fields.Str(description="Recipient public key", **INDY_RAW_PUBLIC_KEY), + fields.Str(description="Recipient public key", **DID_KEY), data_key="recipientKeys", required=False, description="List of recipient keys", ) routing_keys = fields.List( - fields.Str(description="Routing key", **INDY_RAW_PUBLIC_KEY), + fields.Str(description="Routing key", **DID_KEY), data_key="routingKeys", required=False, description="List of routing keys", diff --git a/aries_cloudagent/wallet/tests/test_util.py b/aries_cloudagent/wallet/tests/test_util.py index 827cef78e5..a032a44671 100644 --- a/aries_cloudagent/wallet/tests/test_util.py +++ b/aries_cloudagent/wallet/tests/test_util.py @@ -11,6 +11,8 @@ str_to_b64, set_urlsafe_b64, unpad, + naked_to_did_key, + did_key_to_naked, ) @@ -62,3 +64,15 @@ def test_pad(self): def test_b58(self): b58 = bytes_to_b58(BYTES) assert b58_to_bytes(b58) == BYTES + + def test_naked_to_did_key(self): + assert ( + naked_to_did_key("8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K") + == "did:key:z6MkmjY8GnV5i9YTDtPETC2uUAW6ejw3nk5mXF5yci5ab7th" + ) + + def test_did_key_to_naked(self): + assert ( + did_key_to_naked("did:key:z6MkmjY8GnV5i9YTDtPETC2uUAW6ejw3nk5mXF5yci5ab7th") + == "8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K" + ) diff --git a/aries_cloudagent/wallet/util.py b/aries_cloudagent/wallet/util.py index 808391172c..7987bbaf51 100644 --- a/aries_cloudagent/wallet/util.py +++ b/aries_cloudagent/wallet/util.py @@ -3,6 +3,8 @@ import base58 import base64 +from multicodec import add_prefix, remove_prefix + def pad(val: str) -> str: """Pad base64 values if need be: JWT calls to omit trailing padding.""" @@ -57,3 +59,19 @@ def b58_to_bytes(val: str) -> bytes: def bytes_to_b58(val: bytes) -> str: """Convert a byte string to base 58.""" return base58.b58encode(val).decode("ascii") + + +def naked_to_did_key(key: str) -> str: + """Convert a naked ed25519 verkey to did:key format.""" + key_bytes = b58_to_bytes(key) + prefixed_key_bytes = add_prefix("ed25519-pub", key_bytes) + did_key = f"did:key:z{bytes_to_b58(prefixed_key_bytes)}" + return did_key + + +def did_key_to_naked(did_key: str) -> str: + """Convert a did:key to naked ed25519 verkey format.""" + stripped_key = did_key.split("did:key:z").pop() + stripped_key_bytes = b58_to_bytes(stripped_key) + naked_key_bytes = remove_prefix(stripped_key_bytes) + return bytes_to_b58(naked_key_bytes) diff --git a/requirements.txt b/requirements.txt index b5f5c6e37d..ea89d1c2fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,5 @@ msgpack~=0.6.1 prompt_toolkit~=2.0.9 pynacl~=1.3.0 requests~=2.23.0 -pyld==2.0.1 \ No newline at end of file +pyld==2.0.1 +py_multicodec==0.2.1 \ No newline at end of file