Skip to content

Commit

Permalink
Merge pull request #2692 from Jsyro/feature/did-peer-4-resolution
Browse files Browse the repository at this point in the history
did peer 4 resolution
  • Loading branch information
dbluhm authored Jan 3, 2024
2 parents 4d7bc80 + 0e279a2 commit 44655fa
Show file tree
Hide file tree
Showing 5 changed files with 565 additions and 266 deletions.
7 changes: 6 additions & 1 deletion aries_cloudagent/resolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from ..config.injection_context import InjectionContext
from ..config.provider import ClassProvider

from ..resolver.did_resolver import DIDResolver

LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -74,3 +73,9 @@ async def setup(context: InjectionContext):
).provide(context.settings, context.injector)
await peer_did_3_resolver.setup(context)
registry.register_resolver(peer_did_3_resolver)

peer_did_4_resolver = ClassProvider(
"aries_cloudagent.resolver.default.peer4.PeerDID4Resolver"
).provide(context.settings, context.injector)
await peer_did_4_resolver.setup(context)
registry.register_resolver(peer_did_4_resolver)
78 changes: 78 additions & 0 deletions aries_cloudagent/resolver/default/peer4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""Peer DID 4 Resolver.
Resolution is performed using the peer-did-python library https://github.com/decentralized-identity/did-peer-4.
"""

from re import compile
from typing import Optional, Pattern, Sequence, Text

from did_peer_4 import (
LONG_PATTERN,
SHORT_PATTERN,
long_to_short,
resolve,
resolve_short,
)

from ...config.injection_context import InjectionContext
from ...core.profile import Profile
from ...storage.base import BaseStorage
from ...storage.error import StorageNotFoundError
from ...storage.record import StorageRecord
from ..base import BaseDIDResolver, DIDNotFound, ResolverType


class PeerDID4Resolver(BaseDIDResolver):
"""Peer DID 4 Resolver."""

RECORD_TYPE = "long_peer_did_4_doc"

def __init__(self):
"""Initialize Key Resolver."""
super().__init__(ResolverType.NATIVE)

async def setup(self, context: InjectionContext):
"""Perform required setup for Key DID resolution."""

@property
def supported_did_regex(self) -> Pattern:
"""Return supported_did_regex of Key DID Resolver."""
# accepts both, return a Regex OR
return compile(f"{LONG_PATTERN.pattern}|{SHORT_PATTERN.pattern}")

async def _resolve(
self,
profile: Profile,
did: str,
service_accept: Optional[Sequence[Text]] = None,
) -> dict:
"""Resolve a Key DID."""
if LONG_PATTERN.match(did):
short_did_peer_4 = long_to_short(did)
# resolve and save long form
async with profile.session() as session:
storage = session.inject(BaseStorage)
try:
record = await storage.get_record(
self.RECORD_TYPE, short_did_peer_4
)
except StorageNotFoundError:
record = StorageRecord(self.RECORD_TYPE, did, {}, short_did_peer_4)
await storage.add_record(record)
document = resolve(did)

elif SHORT_PATTERN.match(did):
async with profile.session() as session:
storage = session.inject(BaseStorage)
try:
record = await storage.get_record(self.RECORD_TYPE, did)
except StorageNotFoundError:
raise DIDNotFound(
f"short did:peer:4 does not correspond to a \
known long did:peer:4 {did}"
)
document = resolve_short(record.value)
else:
raise ValueError(f"{did} did not match long or short form of did:peer:4")

return document
57 changes: 57 additions & 0 deletions aries_cloudagent/resolver/default/tests/test_peer4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Test PeerDIDResolver."""

import pytest

from aries_cloudagent.core.event_bus import EventBus

from ....core.in_memory import InMemoryProfile
from ....core.profile import Profile
from .. import peer4 as test_module
from ..peer4 import PeerDID4Resolver

# https://identity.foundation/peer-did-method-spec/#method-4-short-form-and-long-form
TEST_LONG_DP4 = "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd:z2M1k7h4psgp4CmJcnQn2Ljp7Pz7ktsd7oBhMU3dWY5s4fhFNj17qcRTQ427C7QHNT6cQ7T3XfRh35Q2GhaNFZmWHVFq4vL7F8nm36PA9Y96DvdrUiRUaiCuXnBFrn1o7mxFZAx14JL4t8vUWpuDPwQuddVo1T8myRiVH7wdxuoYbsva5x6idEpCQydJdFjiHGCpNc2UtjzPQ8awSXkctGCnBmgkhrj5gto3D4i3EREXYq4Z8r2cWGBr2UzbSmnxW2BuYddFo9Yfm6mKjtJyLpF74ytqrF5xtf84MnGFg1hMBmh1xVx1JwjZ2BeMJs7mNS8DTZhKC7KH38EgqDtUZzfjhpjmmUfkXg2KFEA3EGbbVm1DPqQXayPYKAsYPS9AyKkcQ3fzWafLPP93UfNhtUPL8JW5pMcSV3P8v6j3vPXqnnGknNyBprD6YGUVtgLiAqDBDUF3LSxFQJCVYYtghMTv8WuSw9h1a1SRFrDQLGHE4UrkgoRvwaGWr64aM87T1eVGkP5Dt4L1AbboeK2ceLArPScrdYGTpi3BpTkLwZCdjdiFSfTy9okL1YNRARqUf2wm8DvkVGUU7u5nQA3ZMaXWJAewk6k1YUxKd7LvofGUK4YEDtoxN5vb6r1Q2godrGqaPkjfL3RoYPpDYymf9XhcgG8Kx3DZaA6cyTs24t45KxYAfeCw4wqUpCH9HbpD78TbEUr9PPAsJgXBvBj2VVsxnr7FKbK4KykGcg1W8M1JPz21Z4Y72LWgGQCmixovrkHktcTX1uNHjAvKBqVD5C7XmVfHgXCHj7djCh3vzLNuVLtEED8J1hhqsB1oCBGiuh3xXr7fZ9wUjJCQ1HYHqxLJKdYKtoCiPmgKM7etVftXkmTFETZmpM19aRyih3bao76LdpQtbw636r7a3qt8v4WfxsXJetSL8c7t24SqQBcAY89FBsbEnFNrQCMK3JEseKHVaU388ctvRD45uQfe5GndFxthj4iSDomk4uRFd1uRbywoP1tRuabHTDX42UxPjz"
TEST_SHORT_DP4 = "did:peer:4zQmd8CpeFPci817KDsbSAKWcXAE2mjvCQSasRewvbSF54Bd"


@pytest.fixture
def event_bus():
yield EventBus()


@pytest.fixture
def profile(event_bus: EventBus):
"""Profile fixture."""
profile = InMemoryProfile.test_profile()
profile.context.injector.bind_instance(EventBus, event_bus)
yield profile


@pytest.fixture
async def resolver(profile):
"""Resolver fixture."""
instance = PeerDID4Resolver()
await instance.setup(profile.context)
yield instance


@pytest.mark.asyncio
async def test_resolve_2_then_3(profile: Profile, resolver: PeerDID4Resolver):
"""Test resolver setup."""
assert resolver.supported_did_regex
assert await resolver.supports(profile, TEST_LONG_DP4)
assert await resolver.supports(profile, TEST_SHORT_DP4)

long_doc = await resolver.resolve(profile, TEST_LONG_DP4)
short_doc = await resolver.resolve(profile, TEST_SHORT_DP4)

assert long_doc["id"] == TEST_LONG_DP4
assert TEST_SHORT_DP4 in long_doc["alsoKnownAs"]
assert short_doc["id"] == TEST_SHORT_DP4


@pytest.mark.asyncio
async def test_resolve_x_no_long(profile: Profile, resolver: PeerDID4Resolver):
"""Test resolver setup."""
with pytest.raises(test_module.DIDNotFound):
await resolver.resolve(profile, TEST_SHORT_DP4)
Loading

0 comments on commit 44655fa

Please sign in to comment.