Skip to content

Commit 3d89b09

Browse files
committed
feat: add did key resolver
Signed-off-by: Daniel Bluhm <[email protected]>
1 parent eb108ad commit 3d89b09

File tree

5 files changed

+136
-7
lines changed

5 files changed

+136
-7
lines changed

didcomm_messaging/resolver/key.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""DID Key Resolver."""
2+
3+
from didcomm_messaging.resolver import DIDResolver
4+
5+
6+
class DIDKey(DIDResolver):
7+
"""did:key resolver."""
8+
9+
async def is_resolvable(self, did: str) -> bool:
10+
"""Check to see if DID is resolvable by this resolver."""
11+
return did.startswith("did:key:")
12+
13+
async def resolve(self, did: str) -> dict:
14+
"""Resolve a did:key."""
15+
_, multikey = did.split("did:key:")
16+
id = f"{did}#{multikey}"
17+
return {
18+
"@context": [
19+
"https://www.w3.org/ns/did/v1",
20+
"https://w3id.org/security/multikey/v1",
21+
],
22+
"id": did,
23+
"verificationMethod": [
24+
{
25+
"id": id,
26+
"type": "Multikey",
27+
"controller": did,
28+
"publicKeyMultibase": multikey,
29+
}
30+
],
31+
**{
32+
rel: [id]
33+
for rel in (
34+
"authentication",
35+
"assertionMethod",
36+
"capabilityDelegation",
37+
"capabilityInvocation",
38+
)
39+
},
40+
}

didcomm_messaging/v1/messaging.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pydid.service import DIDCommV1Service
1111

1212
from didcomm_messaging.crypto import P, S, SecretsManager
13+
from didcomm_messaging.crypto.jwe import JweEnvelope
1314
from didcomm_messaging.resolver import DIDResolver
1415
from didcomm_messaging.v1.crypto.base import V1CryptoService
1516
from didcomm_messaging.v1.packaging import V1PackagingService
@@ -222,7 +223,7 @@ async def unpack(
222223
crypto: V1CryptoService[P, S],
223224
secrets: SecretsManager[S],
224225
packaging: V1PackagingService[P, S],
225-
encoded_message: bytes,
226+
encoded_message: Union[JweEnvelope, str, bytes, dict, Any],
226227
**options,
227228
) -> V1UnpackResult:
228229
"""Unpack a message."""
@@ -285,7 +286,7 @@ async def pack(
285286

286287
async def unpack(
287288
self,
288-
encoded_message: bytes,
289+
encoded_message: Union[JweEnvelope, str, bytes, dict, Any],
289290
**options,
290291
) -> V1UnpackResult:
291292
"""Unpack a message."""

didcomm_messaging/v1/packaging.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""V1PackagingService interface."""
22

3-
from typing import Generic, Optional, Sequence, Tuple, Union
3+
from typing import Any, Generic, Optional, Sequence, Tuple, Union
44

55
from didcomm_messaging.crypto.base import P, S, SecretsManager
66
from didcomm_messaging.crypto.jwe import JweEnvelope, JweRecipient
@@ -82,7 +82,7 @@ async def unpack(
8282
self,
8383
crypto: V1CryptoService[P, S],
8484
secrets: SecretsManager[S],
85-
enc_message: Union[JweEnvelope, str, bytes],
85+
enc_message: Union[JweEnvelope, str, bytes, dict, Any],
8686
) -> V1CryptoUnpackResult:
8787
"""Unpack a DIDComm v1 message."""
8888
if isinstance(enc_message, (str, bytes)):
@@ -92,8 +92,10 @@ async def unpack(
9292
raise V1PackagingServiceError("Invalid packed message")
9393
elif isinstance(enc_message, JweEnvelope):
9494
wrapper = enc_message
95+
elif isinstance(enc_message, dict):
96+
wrapper = JweEnvelope.deserialize(enc_message)
9597
else:
96-
raise TypeError("Invalid enc_message")
98+
raise TypeError("Invalid enc_message; expect envelope, str, bytes, or dict")
9799

98100
recip_key, recip_data = await self.extract_packed_message_metadata(
99101
secrets, wrapper

tests/v1/conftest.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import pytest_asyncio
77

88
from didcomm_messaging.crypto.backend.askar import AskarKey, AskarSecretsManager
9-
from didcomm_messaging.resolver import DIDResolver
9+
from didcomm_messaging.resolver import DIDResolver, PrefixResolver
10+
from didcomm_messaging.resolver.key import DIDKey
1011
from didcomm_messaging.resolver.peer import Peer4
1112
from didcomm_messaging.v1.crypto.askar import AskarV1CryptoService
1213
from didcomm_messaging.v1.crypto.nacl import (
@@ -51,7 +52,12 @@ def packer():
5152

5253
@pytest.fixture
5354
def resolver():
54-
yield Peer4()
55+
yield PrefixResolver(
56+
{
57+
"did:peer:4": Peer4(),
58+
"did:key": DIDKey(),
59+
}
60+
)
5561

5662

5763
@pytest.fixture

tests/v1/test_forward.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""Test forwarding."""
2+
3+
from aries_askar import Key, KeyAlg, Store
4+
import base58
5+
import did_peer_4
6+
from did_peer_4.input_doc import KeySpec, input_doc_from_keys_and_services
7+
import pytest
8+
from didcomm_messaging.crypto.backend.askar import AskarKey
9+
from didcomm_messaging.v1.crypto.nacl import EdPublicKey, InMemSecretsManager
10+
from didcomm_messaging.v1.messaging import V1DIDCommMessaging
11+
12+
13+
@pytest.mark.asyncio
14+
async def test_nacl_forward(
15+
alice: V1DIDCommMessaging,
16+
nacl_secrets: InMemSecretsManager,
17+
):
18+
"""Test nacl crypto forwarding."""
19+
local_key = EdPublicKey(nacl_secrets.create().verkey)
20+
routing_key = EdPublicKey(nacl_secrets.create().verkey)
21+
doc = input_doc_from_keys_and_services(
22+
[KeySpec(local_key.multikey, relationships=["authentication"])],
23+
[
24+
{
25+
"id": "#didcomm",
26+
"type": "did-communication",
27+
"recipientKeys": ["#key-0"],
28+
"routingKeys": [f"did:key:{routing_key.multikey}#{routing_key.multikey}"],
29+
"serviceEndpoint": "https://example.com",
30+
}
31+
],
32+
)
33+
did = did_peer_4.encode(doc)
34+
msg = b"hello world"
35+
packed = await alice.pack(msg, did, did)
36+
unpacked = await alice.unpack(packed.message)
37+
forward = unpacked.message
38+
assert forward["@type"] == "https://didcomm.org/routing/1.0/forward"
39+
unwrapped = await alice.unpack(forward["msg"])
40+
assert unwrapped.unpacked == msg
41+
42+
43+
@pytest.mark.asyncio
44+
async def test_askar_forward(
45+
bob: V1DIDCommMessaging,
46+
store: Store,
47+
):
48+
"""Test nacl crypto forwarding."""
49+
key = Key.generate(KeyAlg.ED25519)
50+
kid = base58.b58encode(key.get_public_bytes()).decode()
51+
async with store.session() as session:
52+
await session.insert_key(kid, key)
53+
local_key = AskarKey(key, kid)
54+
55+
key = Key.generate(KeyAlg.ED25519)
56+
kid = base58.b58encode(key.get_public_bytes()).decode()
57+
async with store.session() as session:
58+
await session.insert_key(kid, key)
59+
routing_key = AskarKey(key, kid)
60+
61+
doc = input_doc_from_keys_and_services(
62+
[KeySpec(local_key.multikey, relationships=["authentication"])],
63+
[
64+
{
65+
"id": "#didcomm",
66+
"type": "did-communication",
67+
"recipientKeys": ["#key-0"],
68+
"routingKeys": [f"did:key:{routing_key.multikey}#{routing_key.multikey}"],
69+
"serviceEndpoint": "https://example.com",
70+
}
71+
],
72+
)
73+
did = did_peer_4.encode(doc)
74+
msg = b"hello world"
75+
packed = await bob.pack(msg, did, did)
76+
unpacked = await bob.unpack(packed.message)
77+
forward = unpacked.message
78+
assert forward["@type"] == "https://didcomm.org/routing/1.0/forward"
79+
unwrapped = await bob.unpack(forward["msg"])
80+
assert unwrapped.unpacked == msg

0 commit comments

Comments
 (0)