Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: public did mediator routing keys as did keys #1977

Merged
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ad44b02
fix: public did mediator routing keys as did keys
dbluhm Oct 14, 2022
42cf9d5
fix: remove cls from resolver.dereference() call
cjhowland Oct 20, 2022
2bf13c7
fix: mock dereference
cjhowland Oct 20, 2022
206ccda
feat: convert did key to did key url
cjhowland Oct 20, 2022
795c58f
test: _routing_keys_as_did_key_urls
cjhowland Oct 20, 2022
1f1c19c
test: resolver.dereference() with diddoc passed in
cjhowland Oct 20, 2022
7e8093a
Merge pull request #12 from cjhowland/fix/public-did-mediator-routing…
dbluhm Oct 20, 2022
d669be2
style: fix formatting
dbluhm Oct 20, 2022
1652c0c
Merge branch 'main' into fix/public-did-mediator-routing-keys
swcurran Oct 20, 2022
b8781ab
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Oct 21, 2022
fc47b40
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Oct 25, 2022
f1cac9c
Merge branch 'main' into fix/public-did-mediator-routing-keys
ianco Oct 25, 2022
997d263
fix: account for changes to KeyType
cjhowland Oct 27, 2022
87905a8
fix: remove note
cjhowland Oct 27, 2022
78fc4b0
Merge pull request #13 from cjhowland/fix/public-did-mediator-routing…
dbluhm Oct 27, 2022
99f17de
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Nov 5, 2022
c7aceda
Merge branch 'main' into fix/public-did-mediator-routing-keys
swcurran Nov 8, 2022
ee13c13
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Dec 5, 2022
e9d07cf
fix: black code formatter
cjhowland Dec 6, 2022
7285c18
Merge pull request #14 from cjhowland/fix/public-did-mediator-routing…
dbluhm Dec 6, 2022
3b1a00c
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Dec 13, 2022
20cbd63
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Dec 22, 2022
827263a
Merge branch 'main' into fix/public-did-mediator-routing-keys
ianco Jan 5, 2023
23a8172
Merge branch 'main' into fix/public-did-mediator-routing-keys
dbluhm Jan 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions aries_cloudagent/connections/base_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,16 +269,18 @@ async def resolve_invitation(

endpoint = first_didcomm_service.service_endpoint
recipient_keys: List[VerificationMethod] = [
doc.dereference(url) for url in first_didcomm_service.recipient_keys
await resolver.dereference(self._profile, url, document=doc)
for url in first_didcomm_service.recipient_keys
]
routing_keys: List[VerificationMethod] = [
doc.dereference(url) for url in first_didcomm_service.routing_keys
await resolver.dereference(self._profile, url, document=doc)
for url in first_didcomm_service.routing_keys
]

for key in [*recipient_keys, *routing_keys]:
if not isinstance(key, self.SUPPORTED_KEY_TYPES):
raise BaseConnectionManagerError(
f"Key type {key.type} is not supported"
f"Key type {type(key).__name__} is not supported"
)

return (
Expand Down
2 changes: 0 additions & 2 deletions aries_cloudagent/messaging/jsonld/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from marshmallow import INCLUDE, Schema, fields
from pydid.verification_method import (
Ed25519VerificationKey2018,
KnownVerificationMethods,
)

from ...admin.request_context import AdminRequestContext
Expand Down Expand Up @@ -148,7 +147,6 @@ async def verify(request: web.BaseRequest):
vmethod = await resolver.dereference(
profile,
doc["proof"]["verificationMethod"],
cls=KnownVerificationMethods,
)

if not isinstance(vmethod, SUPPORTED_VERIFICATION_METHOD_TYPES):
Expand Down
26 changes: 13 additions & 13 deletions aries_cloudagent/messaging/jsonld/tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,22 +234,22 @@ async def test_verify_bad_ver_meth_deref_req_error(
assert "error" in mock_response.call_args[0][0]


@pytest.mark.asyncio
async def test_verify_bad_ver_meth_not_ver_meth(
mock_resolver, mock_verify_request, mock_response, request_body
):
request_body["doc"]["proof"][
"verificationMethod"
] = "did:example:1234abcd#did-communication"
await test_module.verify(mock_verify_request(request_body))
assert "error" in mock_response.call_args[0][0]


@pytest.mark.parametrize(
"vmethod",
[
"did:example:1234abcd#key-2",
"did:example:1234abcd#did-communication",
],
)
@pytest.mark.asyncio
async def test_verify_bad_vmethod_unsupported(
mock_resolver, mock_verify_request, mock_response, request_body
mock_resolver,
mock_verify_request,
mock_response,
request_body,
vmethod,
):
request_body["doc"]["proof"]["verificationMethod"] = "did:example:1234abcd#key-2"
request_body["doc"]["proof"]["verificationMethod"] = vmethod
with pytest.raises(web.HTTPBadRequest):
await test_module.verify(mock_verify_request(request_body))

Expand Down
12 changes: 12 additions & 0 deletions aries_cloudagent/protocols/connections/v1_0/tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,9 @@ async def test_fetch_connection_targets_conn_invitation_did_resolver(self):
return_value=self.test_endpoint
)
self.resolver.resolve = async_mock.CoroutineMock(return_value=did_doc)
self.resolver.dereference = async_mock.CoroutineMock(
return_value=did_doc.verification_method[0]
)
self.context.injector.bind_instance(DIDResolver, self.resolver)

local_did = await session.wallet.create_local_did(
Expand Down Expand Up @@ -2137,6 +2140,9 @@ async def test_fetch_connection_targets_conn_invitation_btcr_resolver(self):
return_value=self.test_endpoint
)
self.resolver.resolve = async_mock.CoroutineMock(return_value=did_doc)
self.resolver.dereference = async_mock.CoroutineMock(
return_value=did_doc.verification_method[0]
)
self.context.injector.bind_instance(DIDResolver, self.resolver)
local_did = await session.wallet.create_local_did(
method=SOV,
Expand Down Expand Up @@ -2288,6 +2294,9 @@ async def test_fetch_connection_targets_conn_invitation_unsupported_key_type(sel
return_value=self.test_endpoint
)
self.resolver.resolve = async_mock.CoroutineMock(return_value=did_doc)
self.resolver.dereference = async_mock.CoroutineMock(
return_value=did_doc.verification_method[0]
)
self.context.injector.bind_instance(DIDResolver, self.resolver)
local_did = await session.wallet.create_local_did(
method=SOV,
Expand Down Expand Up @@ -2357,6 +2366,9 @@ async def test_fetch_connection_targets_oob_invitation_svc_did_resolver(self):

self.resolver = async_mock.MagicMock()
self.resolver.resolve = async_mock.CoroutineMock(return_value=did_doc)
self.resolver.dereference = async_mock.CoroutineMock(
return_value=did_doc.verification_method[0]
)
self.context.injector.bind_instance(DIDResolver, self.resolver)

local_did = await session.wallet.create_local_did(
Expand Down
1 change: 1 addition & 0 deletions aries_cloudagent/protocols/out_of_band/v1_0/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ async def create_invitation(
async with self.profile.session() as session:
wallet = session.inject(BaseWallet)
public_did = await wallet.get_public_did()

if not public_did:
raise OutOfBandManagerError(
"Cannot create public invitation with no public DID"
Expand Down
27 changes: 24 additions & 3 deletions aries_cloudagent/resolver/default/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from ...config.injection_context import InjectionContext
from ...core.profile import Profile
from ...did.did_key import DIDKey
from ...ledger.endpoint_type import EndpointType
from ...ledger.error import LedgerError
from ...ledger.multiple_ledger.ledger_requests_executor import (
Expand All @@ -19,7 +20,7 @@
)
from ...messaging.valid import IndyDID
from ...multitenant.base import BaseMultitenantManager

from ...wallet.key_type import ED25519
from ..base import BaseDIDResolver, DIDNotFound, ResolverError, ResolverType

LOGGER = logging.getLogger(__name__)
Expand All @@ -29,6 +30,26 @@ class NoIndyLedger(ResolverError):
"""Raised when there is no Indy ledger instance configured."""


def _routing_keys_as_did_key_urls(routing_keys: Sequence[str]) -> Sequence[str]:
"""Convert raw base58 keys to did:key values.

If a did:key is passed in, convert to a did:key URL.
"""

did_key_urls = []
for routing_key in routing_keys:
if not routing_key.startswith("did:key:"):
did_key_urls.append(DIDKey.from_public_key_b58(routing_key, ED25519).key_id)
else:
if "#" not in routing_key:
did_key_urls.append(
f"{routing_key}#{DIDKey.from_did(routing_key).fingerprint}"
)
else:
return routing_keys
return did_key_urls


class IndyDIDResolver(BaseDIDResolver):
"""Indy DID Resolver."""

Expand Down Expand Up @@ -101,7 +122,7 @@ def add_services(
type_=self.SERVICE_TYPE_DID_COMMUNICATION,
service_endpoint=endpoint,
priority=1,
routing_keys=routing_keys,
routing_keys=_routing_keys_as_did_key_urls(routing_keys),
recipient_keys=[recipient_key.id],
accept=(
service_accept if service_accept else ["didcomm/aip2;env=rfc19"]
Expand All @@ -114,7 +135,7 @@ def add_services(
type_=self.SERVICE_TYPE_DIDCOMM,
service_endpoint=endpoint,
recipient_keys=[recipient_key.id],
routing_keys=routing_keys,
routing_keys=_routing_keys_as_did_key_urls(routing_keys),
# CHECKME
# accept=(service_accept if service_accept else ["didcomm/v2"]),
accept=["didcomm/v2"],
Expand Down
19 changes: 17 additions & 2 deletions aries_cloudagent/resolver/default/tests/test_indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ....multitenant.manager import MultitenantManager

from ...base import DIDNotFound, ResolverError
from ..indy import IndyDIDResolver
from ..indy import IndyDIDResolver, _routing_keys_as_did_key_urls

# pylint: disable=W0621
TEST_DID0 = "did:sov:WgWxqztrNooG92RXvxSTWv"
Expand Down Expand Up @@ -127,7 +127,7 @@ async def test_supports_updated_did_sov_rules(
"""Test that new attrib structure is supported."""
example = {
"endpoint": "https://example.com/endpoint",
"routingKeys": ["a-routing-key"],
"routingKeys": ["HQhjaj4mcaS3Xci27a9QhnBrNpS91VNFUU4TDrtMxa9j"],
"types": ["DIDComm", "did-communication", "endpoint"],
"profile": "https://example.com",
"linked_domains": "https://example.com",
Expand Down Expand Up @@ -177,3 +177,18 @@ async def test_supports_updated_did_sov_rules_no_endpoint_url(
)
def test_process_endpoint_types(self, resolver: IndyDIDResolver, types, result):
assert resolver.process_endpoint_types(types) == result

@pytest.mark.parametrize(
"keys",
[
["3YJCx3TqotDWFGv7JMR5erEvrmgu5y4FDqjR7sKWxgXn"],
["did:key:z6MkgzZFYHiH9RhyMmkoyvNvVwnvgLxkVrJbureLx9HXsuKA"],
[
"did:key:z6MkgzZFYHiH9RhyMmkoyvNvVwnvgLxkVrJbureLx9HXsuKA#z6MkgzZFYHiH9RhyMmkoyvNvVwnvgLxkVrJbureLx9HXsuKA"
],
],
)
def test_routing_keys_as_did_key_urls(self, keys):
for key in _routing_keys_as_did_key_urls(keys):
assert key.startswith("did:key:")
assert "#" in key
31 changes: 18 additions & 13 deletions aries_cloudagent/resolver/did_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
from datetime import datetime
from itertools import chain
import logging
from typing import Optional, List, Sequence, Tuple, Text, Type, TypeVar, Union
from typing import List, Optional, Sequence, Text, Tuple, Union

from pydid import DID, DIDError, DIDUrl, Resource, NonconformantDocument
from pydid.doc.doc import IDNotFoundError
from pydid import DID, DIDError, DIDUrl, Resource
import pydid
from pydid.doc.doc import BaseDIDDocument, IDNotFoundError

from ..core.profile import Profile
from .base import (
Expand All @@ -26,9 +27,6 @@
LOGGER = logging.getLogger(__name__)


ResourceType = TypeVar("ResourceType", bound=Resource)


class DIDResolver:
"""did resolver singleton."""

Expand Down Expand Up @@ -115,8 +113,12 @@ async def _match_did_to_resolver(
return resolvers

async def dereference(
self, profile: Profile, did_url: str, *, cls: Type[ResourceType] = Resource
) -> ResourceType:
self,
profile: Profile,
did_url: str,
*,
document: Optional[BaseDIDDocument] = None,
) -> Resource:
"""Dereference a DID URL to its corresponding DID Doc object."""
# TODO Use cached DID Docs when possible
try:
Expand All @@ -128,12 +130,15 @@ async def dereference(
"Failed to parse DID URL from {}".format(did_url)
) from err

doc_dict = await self.resolve(profile, parsed.did)
# Use non-conformant doc as the "least common denominator"
if document and parsed.did != document.id:
document = None

if not document:
doc_dict = await self.resolve(profile, parsed.did)
document = pydid.deserialize_document(doc_dict)

try:
return NonconformantDocument.deserialize(doc_dict).dereference_as(
cls, parsed
)
return document.dereference(parsed)
except IDNotFoundError as error:
raise ResolverError(
"Failed to dereference DID URL: {}".format(error)
Expand Down
13 changes: 12 additions & 1 deletion aries_cloudagent/resolver/tests/test_did_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pytest

from asynctest import mock as async_mock
from pydid import DID, DIDDocument, VerificationMethod
from pydid import DID, DIDDocument, VerificationMethod, BasicDIDDocument

from ..base import (
BaseDIDResolver,
Expand Down Expand Up @@ -153,6 +153,17 @@ async def test_dereference(resolver, profile):
assert expected == actual.serialize()


@pytest.mark.asyncio
async def test_dereference_diddoc(resolver, profile):
url = "did:example:1234abcd#4"
doc = BasicDIDDocument(
id="did:example:z6Mkmpe2DyE4NsDiAb58d75hpi1BjqbH6wYMschUkjWDEEuR"
)
result = await resolver.dereference(profile, url, document=doc)
assert isinstance(result, VerificationMethod)
assert result.id == url


@pytest.mark.asyncio
async def test_dereference_x(resolver, profile):
url = "non-did"
Expand Down