Skip to content

Commit

Permalink
Merge pull request #3 from dbluhm/feature/didresolver
Browse files Browse the repository at this point in the history
Feature/didresolver
  • Loading branch information
burdettadam authored Feb 4, 2021
2 parents 80b35bf + e4ba21f commit 22d790a
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 104 deletions.
10 changes: 5 additions & 5 deletions aries_cloudagent/resolver/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
from typing import Sequence

from .diddoc import ResolvedDIDDoc
from ..core.profile import ProfileSession
from ..core.profile import Profile


class ResolverError(Exception):
"""Base class for resolver exceptions."""


class DidNotFound(ResolverError):
class DIDNotFound(ResolverError):
"""Raised when DID is not found in verifiable data registry."""


class DidMethodNotSupported(ResolverError):
class DIDMethodNotSupported(ResolverError):
"""Raised when no resolver is registered for a given did method."""


Expand All @@ -39,7 +39,7 @@ def __init__(self, type_: ResolverType = None):
self.type = type_ or ResolverType.NON_NATIVE

@abstractmethod
async def setup(self, session: ProfileSession):
async def setup(self, profile: Profile):
"""Do asynchronous resolver setup."""

@property
Expand All @@ -57,5 +57,5 @@ def supports(self, method: str):
return method in self.supported_methods

@abstractmethod
async def resolve(self, session: ProfileSession, did: str) -> ResolvedDIDDoc:
async def resolve(self, profile: Profile, did: str) -> ResolvedDIDDoc:
"""Resolve a DID using this resolver."""
12 changes: 6 additions & 6 deletions aries_cloudagent/resolver/default/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"""
from typing import Sequence

from ...core.profile import ProfileSession
from ...core.profile import Profile
from ...ledger.indy import IndySdkLedger
from ...ledger.error import LedgerError
from ..base import BaseDIDResolver, DidNotFound, ResolverError, ResolverType
from ..base import BaseDIDResolver, DIDNotFound, ResolverError, ResolverType
from ..did import DID
from ..diddoc import ResolvedDIDDoc

Expand All @@ -25,17 +25,17 @@ def __init__(self):
"""Initialize Indy Resolver."""
super().__init__(ResolverType.NATIVE)

async def setup(self, session: ProfileSession):
async def setup(self, profile: Profile):
"""Perform required setup for Indy DID resolution."""

@property
def supported_methods(self) -> Sequence[str]:
"""Return supported methods of Indy DID Resolver."""
return ["sov"]

async def resolve(self, session: ProfileSession, did: str) -> ResolvedDIDDoc:
async def resolve(self, profile: Profile, did: str) -> ResolvedDIDDoc:
"""Resolve an indy DID."""
ledger = session.inject(IndySdkLedger, required=False)
ledger = profile.inject(IndySdkLedger, required=False)
if not ledger:
raise NoIndyLedger("No Indy ledger isntance is configured.")

Expand All @@ -46,7 +46,7 @@ async def resolve(self, session: ProfileSession, did: str) -> ResolvedDIDDoc:
recipient_key = await ledger.get_key_for_did(str(did))
endpoint = await ledger.get_endpoint_for_did(str(did))
except LedgerError as err:
raise DidNotFound(f"DID {did} could not be resolved") from err
raise DIDNotFound(f"DID {did} could not be resolved") from err

doc = ResolvedDIDDoc(
{
Expand Down
30 changes: 15 additions & 15 deletions aries_cloudagent/resolver/default/tests/test_indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

from ..indy import IndyDIDResolver
from ....core.in_memory import InMemoryProfile
from ....core.profile import ProfileSession
from ....core.profile import Profile
from ....ledger.indy import IndySdkLedger
from ....ledger.error import LedgerError
from ...tests.test_did import TEST_DID0
from ...base import ResolverError, DidNotFound
from ...base import ResolverError, DIDNotFound

# pylint: disable=W0621

Expand All @@ -30,11 +30,11 @@ def ledger():


@pytest.fixture
def session(ledger):
"""Session fixture."""
session = InMemoryProfile.test_session()
session.context.injector.bind_instance(IndySdkLedger, ledger)
yield session
def profile(ledger):
"""Profile fixture."""
profile = InMemoryProfile.test_profile()
profile.context.injector.bind_instance(IndySdkLedger, ledger)
yield profile


def test_supported_methods(resolver: IndyDIDResolver):
Expand All @@ -44,24 +44,24 @@ def test_supported_methods(resolver: IndyDIDResolver):


@pytest.mark.asyncio
async def test_resolve(resolver: IndyDIDResolver, session: ProfileSession):
async def test_resolve(resolver: IndyDIDResolver, profile: Profile):
"""Test resolve method."""
assert await resolver.resolve(session, TEST_DID0)
assert await resolver.resolve(profile, TEST_DID0)


@pytest.mark.asyncio
async def test_resolve_x_no_ledger(resolver: IndyDIDResolver, session: ProfileSession):
async def test_resolve_x_no_ledger(resolver: IndyDIDResolver, profile: Profile):
"""Test resolve method with no ledger."""
session.context.injector.clear_binding(IndySdkLedger)
profile.context.injector.clear_binding(IndySdkLedger)
with pytest.raises(ResolverError):
await resolver.resolve(session, TEST_DID0)
await resolver.resolve(profile, TEST_DID0)


@pytest.mark.asyncio
async def test_resolve_x_did_not_found(
resolver: IndyDIDResolver, ledger: IndySdkLedger, session: ProfileSession
resolver: IndyDIDResolver, ledger: IndySdkLedger, profile: Profile
):
"""Test resolve method when no did is found."""
ledger.get_key_for_did.side_effect = LedgerError
with pytest.raises(DidNotFound):
await resolver.resolve(session, TEST_DID0)
with pytest.raises(DIDNotFound):
await resolver.resolve(profile, TEST_DID0)
59 changes: 21 additions & 38 deletions aries_cloudagent/resolver/did_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
"""

import logging
from typing import Union
from itertools import chain
from ..resolver.diddoc import ResolvedDIDDoc # , ExternalResourceError
from ..resolver.base import BaseDIDResolver, DidMethodNotSupported, DidNotFound
from typing import Union

from ..core.profile import Profile
from ..resolver.base import BaseDIDResolver, DIDMethodNotSupported, DIDNotFound
from ..resolver.did import DID, DIDUrl # , DID_PATTERN
from ..resolver.diddoc import ResolvedDIDDoc # , ExternalResourceError
from .did_resolver_registry import DIDResolverRegistry

LOGGER = logging.getLogger(__name__)
Expand All @@ -21,20 +23,23 @@ class DIDResolver:

def __init__(self, registry: DIDResolverRegistry):
"""Initialize a `didresolver` instance."""
self.did_resolver_registery = registry
self.did_resolver_registry = registry

async def resolve(self, did: Union[str, DID]) -> ResolvedDIDDoc:
async def resolve(
self, profile: Profile, did: Union[str, DID]
) -> ResolvedDIDDoc:
"""Retrieve did doc from public registry."""
# TODO Cache results
if isinstance(did, str):
did = DID(did)
for resolver in self._match_did_to_resolver(did):
try:
LOGGER.debug("Resolving DID %s with %s", did, resolver)
return await resolver.resolve(did)
except DidNotFound:
return await resolver.resolve(profile, did)
except DIDNotFound:
LOGGER.debug("DID %s not found by resolver %s", did, resolver)

raise DidNotFound(f"DID {did} could not be resolved.")
raise DIDNotFound(f"DID {did} could not be resolved.")

def _match_did_to_resolver(self, did: DID) -> BaseDIDResolver:
"""Generate supported DID Resolvers.
Expand All @@ -45,7 +50,7 @@ def _match_did_to_resolver(self, did: DID) -> BaseDIDResolver:
valid_resolvers = list(
filter(
lambda resolver: resolver.supports(did.method),
self.did_resolver_registery.did_resolvers,
self.did_resolver_registry.resolvers,
)
)
native_resolvers = filter(lambda resolver: resolver.native, valid_resolvers)
Expand All @@ -54,36 +59,14 @@ def _match_did_to_resolver(self, did: DID) -> BaseDIDResolver:
)
resolvers = list(chain(native_resolvers, non_native_resolvers))
if not resolvers:
raise DidMethodNotSupported(f"{did.method} not supported")
raise DIDMethodNotSupported(f"{did.method} not supported")
return resolvers

async def dereference_external(self, did_url: str) -> ResolvedDIDDoc:
"""Retrieve an external did in doc service from a public registry."""
async def dereference(
self, profile: Profile, did_url: str
) -> ResolvedDIDDoc:
"""Dereference a DID URL to its corresponding DID Doc object."""
# TODO Use cached DID Docs when possible
did_url = DIDUrl.parse(did_url)
doc = await self.resolve(did_url.did)
doc = await self.resolve(profile, did_url.did)
return doc.dereference(did_url)

'''async def fully_dereference(self, doc: ResolvedDIDDoc):
"""Recursivly retrieve all doc service dids from public registries."""
async def _visit(value, doc):
if isinstance(value, dict):
doc_dict = {}
for key, value in value.items():
doc_dict[key] = await _visit(value, doc)
return doc
elif isinstance(value, list):
return [await _visit(item, doc) for item in value]
elif isinstance(value, str):
if DID_PATTERN.match(value): # string is a did_url pattern
did_url = DIDUrl.parse(value)
did_str = ""
try: # dereference from diddoc
did_str = doc.dereference(did_url)
except ExternalResourceError: # dereference from a resolver
did_str = await self.dereference_external(did_url)
did_str = await _visit(did_str, doc)
return did_str
return value
return await _visit(doc._doc, doc)'''
3 changes: 1 addition & 2 deletions aries_cloudagent/resolver/did_resolver_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ class DIDResolverRegistry:
def __init__(self):
"""Initialize list for did resolvers."""
self._resolvers = []
LOGGER.debug("Resolvers listed")

@property
def did_resolvers(
def resolvers(
self,
) -> Sequence[str]:
"""Accessor for a list of all did resolvers."""
Expand Down
4 changes: 2 additions & 2 deletions aries_cloudagent/resolver/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ class ExampleDIDResolver(BaseDIDResolver):
def __init__(self):
super().__init__()

async def setup(self, session):
async def setup(self, profile):
pass

@property
def supported_methods(self):
return ["test"]

async def resolve(self, session, did: str) -> ResolvedDIDDoc:
async def resolve(self, profile, did: str) -> ResolvedDIDDoc:
return ResolvedDIDDoc({"id": "did:example:123"})


Expand Down
Loading

0 comments on commit 22d790a

Please sign in to comment.