Skip to content

Commit

Permalink
Merge branch 'main' into feature/plugin-config-by-file
Browse files Browse the repository at this point in the history
  • Loading branch information
dbluhm authored Jun 6, 2021
2 parents d925877 + b538cb9 commit 100ef67
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 1 deletion.
14 changes: 14 additions & 0 deletions aries_cloudagent/messaging/valid.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,20 @@ def __init__(self):
)


class DIDWeb(Regexp):
"""Validate value against did:web specification."""

EXAMPLE = "did:web:example.com"
PATTERN = re.compile(r"^(did:web:)?([a-zA-Z0-9%._-]*:)*[a-zA-Z0-9%._-]+$")

def __init__(self):
"""Initializer."""

super().__init__(
DIDWeb.PATTERN, error="Value {input} is not in W3C did:web format"
)


class DIDPosture(OneOf):
"""Validate value against defined DID postures."""

Expand Down
6 changes: 6 additions & 0 deletions aries_cloudagent/resolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ async def setup(context: InjectionContext):
registry.register(indy_resolver)
else:
LOGGER.warning("Ledger is not configured, not loading IndyDIDResolver")

web_resolver = ClassProvider(
"aries_cloudagent.resolver.default.web.WebDIDResolver"
).provide(context.settings, context.injector)
await web_resolver.setup(context)
registry.register(web_resolver)
27 changes: 27 additions & 0 deletions aries_cloudagent/resolver/default/tests/test_web.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Test did:web Resolver."""

import pytest
from ..web import WebDIDResolver


@pytest.fixture
def resolver():
yield WebDIDResolver()


def test_transformation_domain_only(resolver):
did = "did:web:example.com"
url = resolver._WebDIDResolver__transform_to_url(did)
assert url == "https://example.com/.well-known/did.json"


def test_transformation_domain_with_path(resolver):
did = "did:web:example.com:department:example"
url = resolver._WebDIDResolver__transform_to_url(did)
assert url == "https://example.com/department/example/did.json"


def test_transformation_domain_with_port(resolver):
did = "did:web:localhost%3A443"
url = resolver._WebDIDResolver__transform_to_url(did)
assert url == "https://localhost:443/.well-known/did.json"
83 changes: 83 additions & 0 deletions aries_cloudagent/resolver/default/web.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""Web DID Resolver."""

import urllib.parse

from typing import Sequence, Pattern

import aiohttp

from pydid import DID, DIDDocument

from ...config.injection_context import InjectionContext
from ...core.profile import Profile
from ...messaging.valid import DIDWeb

from ..base import (
BaseDIDResolver,
DIDNotFound,
ResolverError,
ResolverType,
)


class WebDIDResolver(BaseDIDResolver):
"""Web DID Resolver."""

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

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

@property
def supported_did_regex(self) -> Pattern:
"""Return supported_did_regex of Web DID Resolver."""
return DIDWeb.PATTERN

def supported_methods(self) -> Sequence[str]:
"""Return list of supported methods."""
return ["web"]

def __transform_to_url(self, did):
"""
Transform did to url.
according to
https://w3c-ccg.github.io/did-method-web/#read-resolve
"""

as_did = DID(did)
method_specific_id = as_did.method_specific_id
if ":" in method_specific_id:
# contains path
url = method_specific_id.replace(":", "/")
else:
# bare domain needs /.well-known path
url = method_specific_id + "/.well-known"

# Support encoded ports (See: https://github.com/w3c-ccg/did-method-web/issues/7)
url = urllib.parse.unquote(url)

return "https://" + url + "/did.json"

async def _resolve(self, profile: Profile, did: str) -> dict:
"""Resolve did:web DIDs."""

url = self.__transform_to_url(did)
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
if response.status == 200:
try:
# Validate DIDDoc with pyDID
did_doc = DIDDocument.from_json(await response.text())
return did_doc.serialize()
except Exception as err:
raise ResolverError(
"Response was incorrectly formatted"
) from err
if response.status == 404:
raise DIDNotFound(f"No document found for {did}")
raise ResolverError(
"Could not find doc for {}: {}".format(did, await response.text())
)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ pyld~=2.0.3
pyyaml~=5.4.0
ConfigArgParse~=1.2.3
pyjwt~=1.7.1
pydid~=0.2.3
pydid~=0.2.6

0 comments on commit 100ef67

Please sign in to comment.