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

did peer 4 resolution #2692

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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