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 for remote resolve issue #39

Merged
merged 15 commits into from
Jan 12, 2024
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
374 changes: 364 additions & 10 deletions GETTING_STARTED.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ services:
dockerfile: ./images/did-webs-service.dockerfile
depends_on:
- webs
image: did-webs-service:latest
ports:
- 7676:7676
tty: true
volumes:
- ~/VSCode/did-keri-resolver/volume/dkr/examples:/usr/local/var/webs/volume/dkr/examples
- ~/VSCode/did-keri-resolver/volume/dkr/pages:/usr/local/var/webs/volume/dkr/pages
# entrypoint: dkr did webs service --name webserve --config-dir /usr/local/var/webs/volume/dkr/examples/my-scripts --config-file config-docker

did-webs-resolver-service:
did-webs-resolver:
container_name: did-webs-resolver
hostname: did-webs-resolver
build:
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
],
python_requires='>=3.10.4',
install_requires=[
'aiohttp>=3.7.4',
'lmdb>=1.3.0',
'pysodium>=0.7.12',
'blake3>=0.3.1',
Expand Down
2 changes: 1 addition & 1 deletion src/dkr/app/cli/commands/did/keri/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def resolve(self, tymth, tock=0.0, **opts):
_ = yield tock

didresult = didding.generateDIDDoc(self.hby, did=self.did, aid=aid, oobi=self.oobi, metadata=True)
dd = didresult['didDocument']
dd = didresult[didding.DD_FIELD]
result = didresult if self.metadata else dd
data = json.dumps(result, indent=2)

Expand Down
121 changes: 3 additions & 118 deletions src/dkr/app/cli/commands/did/webs/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@

"""
import argparse
import json
import requests
import sys

from hio.base import doing
from keri.app import habbing, oobiing
from keri.app.cli.common import existing
from keri.db import basing
from keri.help import helping

from dkr.core import didding
from dkr.core import webbing
from dkr.core import resolving

parser = argparse.ArgumentParser(description='Resolve a did:webs DID')
parser.set_defaults(handler=lambda args: handler(args),
Expand Down Expand Up @@ -57,115 +51,6 @@ def resolve(self, tymth, tock=0.125, **opts):
self.tock = tock
_ = (yield self.tock)

domain, port, path, aid = didding.parseDIDWebs(self.did)

opt_port = (f':{port}' if port is not None else '')
opt_path = (f"/{path.replace(':', '/')}" if path is not None else '')
base_url = f"http://{domain}{opt_port}{opt_path}/{aid}"

# Load the did doc
dd_url = f"{base_url}/{webbing.DID_JSON}"
print(f"Loading DID Doc from {dd_url}", file=sys.stderr)
dd_actual = didding.fromDidWeb(json.loads(self.loadUrl(dd_url).decode("utf-8")))

# Load the KERI CESR
kc_url = f"{base_url}/{webbing.KERI_CESR}"
print(f"Loading KERI CESR from {kc_url}", file=sys.stderr)
kc_bytes = self.loadUrl(kc_url)
print(f"Got KERI CESR: {kc_bytes.decode('utf-8')}")
self.hby.psr.parse(ims=bytearray(kc_bytes))
print("Waiting for KERI CESR to be processed...")
yield 3.0

didresult = didding.generateDIDDoc(self.hby, did=self.did, aid=aid, oobi=None, metadata=True)
didresult['didDocumentMetadata']['didDocUrl'] = dd_url
didresult['didDocumentMetadata']['keriCesrUrl'] = kc_url

dd_expected = didresult['didDocument']

verified = self.verifyDidDocs(dd_expected, dd_actual)

self.remove(self.toRemove)

if verified:
result = didresult if self.metadata else dd_expected
else:
didresult['didDocument'] = None
didresult['didResolutionMetadata']['error'] = 'notVerified'
didresult['didResolutionMetadata']['errorMessage'] = 'The DID document could not be verified against the KERI event stream'
result = didresult

data = json.dumps(result, indent=2)
print(data)
return result

def loadUrl(self, url):
response = requests.get(f"{url}")
# Ensure the request was successful
response.raise_for_status()
# Convert the content to a bytearray
return response.content
resolving.resolve(hby=self.hby, did=self.did, metadata=self.metadata)

def verifyDidDocs(self, expected, actual):
if expected != actual:
print("DID Doc does not verify", file=sys.stderr)
compare_dicts(expected, actual)
return False
else:
print("DID Doc verified", file=sys.stderr)
return True

def compare_dicts(expected, actual, path=""):
print("Comparing dictionaries:\nexpected:\n{expected} \nand\n \nactual:\n{actual}", file=sys.stderr)

"""Recursively compare two dictionaries and print differences."""
for k in expected.keys():
# Construct current path
current_path = f"{path}.{k}" if path else k
print(f"Comparing key {current_path}", file=sys.stderr)

# Key not present in the actual dictionary
if k not in actual:
print(f"Key {current_path} not found in the actual dictionary", file=sys.stderr)
continue

# If value in expected is a dictionary but not in actual
if isinstance(expected[k], dict) and not isinstance(actual[k], dict):
print(f"{current_path} is a dictionary in expected, but not in actual", file=sys.stderr)
continue

# If value in actual is a dictionary but not in expected
if isinstance(actual[k], dict) and not isinstance(expected[k], dict):
print(f"{current_path} is a dictionary in actual, but not in expected", file=sys.stderr)
continue

# If value is another dictionary, recurse
if isinstance(expected[k], dict) and isinstance(actual[k], dict):
compare_dicts(expected[k], actual[k], current_path)
# Compare non-dict values
elif expected[k] != actual[k]:
print(f"Different values for key {current_path}: {expected[k]} (expected) vs. {actual[k]} (actual)", file=sys.stderr)

# Check for keys in actual that are not present in expected
for k in actual.keys():
current_path = f"{path}.{k}" if path else k
if k not in expected:
print(f"Key {current_path} not found in the expected dictionary", file=sys.stderr)

# # Test with the provided dictionaries
# expected_dict = {
# 'id': 'did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha',
# 'verificationMethod': [{'id': 'did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha#key-0', 'type': 'Ed25519VerificationKey2020', 'controller': 'did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha', 'publicKeyMultibase': 'z2fD7Rmbbggzwa4SNpYKWi6csiiUcVeyUTgGzDtMrqC7b'}]
# }

# actual_dict = {
# "id": "did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha",
# "verificationMethod": [{
# "id": "did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha#key-0",
# "type": "Ed25519VerificationKey2020",
# "controller": "did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha",
# "publicKeyMultibase": "z2fD7Rmbbggzwa4SNpYKWi6csiiUcVeyUTgGzDtMrqC7b"
# }]
# }

# compare_dicts(expected_dict, actual_dict)
self.remove(self.toRemove)
15 changes: 12 additions & 3 deletions src/dkr/core/didding.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@

DID_KERI_RE = re.compile(r'\Adid:keri:(?P<aid>[^:]+)\Z', re.IGNORECASE)
DID_WEBS_RE = re.compile(r'\Adid:web(s)?:(?P<domain>[^%:]+)(?:%3a(?P<port>\d+))?(?::(?P<path>.+?))?(?::(?P<aid>[^:]+))\Z', re.IGNORECASE)

DID_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
DID_TIME_PATTERN = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z")

DES_ALIASES_SCHEMA="EN6Oh5XSD5_q2Hgu-aqpdfbVepdpYpFlgz6zvJL5b_r5"

DID_RES_META_FIELD='didResolutionMetadata'
DD_META_FIELD='didDocumentMetadata'
DD_FIELD='didDocument'
VMETH_FIELD='verificationMethod'

def parseDIDKeri(did):
match = DID_KERI_RE.match(did)
if match is None:
Expand Down Expand Up @@ -54,6 +61,8 @@ def parseDIDWebs(did):


def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, metadata=None, reg_name=None):
print("Generating DID document for", did, "with aid", aid, "using oobi", oobi, "and metadata", metadata, "registry name for creds", reg_name)

hab = None
if aid in hby.habs:
hab = hby.habs[aid]
Expand Down Expand Up @@ -148,7 +157,7 @@ def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, metadata=None, reg_
eq_ids = [s for s in da_ids if s.startswith(dws_pre)]
print(f"Equivalent DIDs: {eq_ids}")

aka_ids = [s for s in da_ids if not s.startswith(dws_pre)]
aka_ids = [s for s in da_ids]
print(f"Also Known As DIDs: {aka_ids}")

didResolutionMetadata = dict(
Expand Down Expand Up @@ -179,13 +188,13 @@ def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, metadata=None, reg_

def toDidWeb(diddoc):
diddoc['id'] = diddoc['id'].replace('did:webs', 'did:web')
for verificationMethod in diddoc['verificationMethod']:
for verificationMethod in diddoc[VMETH_FIELD]:
verificationMethod['controller'] = verificationMethod['controller'].replace('did:webs', 'did:web')
return diddoc

def fromDidWeb(diddoc):
diddoc['id'] = diddoc['id'].replace('did:web', 'did:webs')
for verificationMethod in diddoc['verificationMethod']:
for verificationMethod in diddoc[VMETH_FIELD]:
verificationMethod['controller'] = verificationMethod['controller'].replace('did:web', 'did:webs')
return diddoc

Expand Down
Loading