diff --git a/.github/workflows/python-formatting.yml b/.github/workflows/python-formatting.yml new file mode 100644 index 0000000..dd4ed9e --- /dev/null +++ b/.github/workflows/python-formatting.yml @@ -0,0 +1,28 @@ +name: Enforce Python Code Formatting + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + format-check: + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.x" + + - name: Install black + run: pip install black + + - name: Run black + run: black --check . diff --git a/setup.py b/setup.py index 6a142e1..6c74b99 100644 --- a/setup.py +++ b/setup.py @@ -31,74 +31,72 @@ from setuptools import find_packages, setup setup( - name='dkr', - version='0.0.7', # also change in src/did-webs-resolver/__init__.py - license='Apache Software License 2.0', - description='did:webs DID Method Resolver', + name="dkr", + version="0.0.7", # also change in src/did-webs-resolver/__init__.py + license="Apache Software License 2.0", + description="did:webs DID Method Resolver", long_description="did:webs DID Method Resolver.", - author='Philip S. Feairheller', - author_email='pfeairheller@gmail.com', - url='https://github.com/hyperledger-labs/did-webs-resolver', - packages=find_packages('src'), - package_dir={'': 'src'}, - py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')], + author="Philip S. Feairheller", + author_email="pfeairheller@gmail.com", + url="https://github.com/hyperledger-labs/did-webs-resolver", + packages=find_packages("src"), + package_dir={"": "src"}, + py_modules=[splitext(basename(path))[0] for path in glob("src/*.py")], include_package_data=True, zip_safe=False, classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: Unix', - 'Operating System :: POSIX', - 'Operating System :: Microsoft :: Windows', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: Implementation :: CPython', - 'Topic :: Utilities', + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: Unix", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Utilities", ], project_urls={ - 'Documentation': 'https://kara.readthedocs.io/', - 'Changelog': 'https://kara.readthedocs.io/en/latest/changelog.html', - 'Issue Tracker': 'https://github.com/WebOfTrust/kara/issues', + "Documentation": "https://kara.readthedocs.io/", + "Changelog": "https://kara.readthedocs.io/en/latest/changelog.html", + "Issue Tracker": "https://github.com/WebOfTrust/kara/issues", }, keywords=[ # eg: 'keyword1', 'keyword2', 'keyword3', ], - python_requires='>=3.10.13', + python_requires=">=3.10.13", install_requires=[ - 'aiohttp>=3.7.4', - 'lmdb>=1.3.0', - 'pysodium>=0.7.12', - 'blake3>=0.3.1', - 'msgpack>=1.0.4', - 'cbor2>=5.4.3', - 'multidict>=6.0.2', - 'ordered-set>=4.1.0', - 'keri>=1.1.4', - 'hio>=0.6.9', - 'multicommand>=1.0.0', - 'jsonschema>=4.17.0', - 'falcon>=3.1.0', - 'hjson>=3.0.2', - 'PyYaml>=6.0', - 'apispec>=6.0.0', - 'mnemonic>=0.20', - 'PrettyTable>=3.5.0', - 'http_sfv>=0.9.8', - 'cryptography>=39.0.2', - 'requests>=2.28', - 'pytest>=6.2.5', - 'pytest-timeout>=2.3.1' + "aiohttp>=3.7.4", + "lmdb>=1.3.0", + "pysodium>=0.7.12", + "blake3>=0.3.1", + "msgpack>=1.0.4", + "cbor2>=5.4.3", + "multidict>=6.0.2", + "ordered-set>=4.1.0", + "keri>=1.1.17", + "hio>=0.6.9", + "multicommand>=1.0.0", + "jsonschema>=4.17.0", + "falcon>=3.1.0", + "hjson>=3.0.2", + "PyYaml>=6.0", + "apispec>=6.0.0", + "mnemonic>=0.20", + "PrettyTable>=3.5.0", + "http_sfv>=0.9.8", + "cryptography>=39.0.2", + "requests>=2.28", + "pytest>=6.2.5", + "pytest-timeout>=2.3.1", ], - extras_require={ - }, + extras_require={}, tests_require=[ - 'coverage>=5.5', - ], - setup_requires=[ + "coverage>=5.5", ], + setup_requires=[], entry_points={ - 'console_scripts': [ - 'dkr = dkr.app.cli.dkr:main', + "console_scripts": [ + "dkr = dkr.app.cli.dkr:main", ] }, ) diff --git a/src/dkr/app/cli/commands/did/keri/resolve.py b/src/dkr/app/cli/commands/did/keri/resolve.py index 6f34541..4fd3fed 100644 --- a/src/dkr/app/cli/commands/did/keri/resolve.py +++ b/src/dkr/app/cli/commands/did/keri/resolve.py @@ -15,27 +15,51 @@ from dkr.core import didding -parser = argparse.ArgumentParser(description='Resolve a did:keri DID') -parser.set_defaults(handler=lambda args: handler(args), - transferable=True) -parser.add_argument('-n', '--name', - action='store', - default="dkr", - help="Name of controller. Default is dkr.") -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran -parser.add_argument("--did", "-d", help="DID to resolve (did:keri method)", required=True) -parser.add_argument("--oobi", "-o", help="OOBI to use for resolving the DID", required=False) -parser.add_argument("--meta", "-m", help="Whether to include metadata (True), or only return the DID document (False)", type=bool, required=False, default=None) +parser = argparse.ArgumentParser(description="Resolve a did:keri DID") +parser.set_defaults(handler=lambda args: handler(args), transferable=True) +parser.add_argument( + "-n", + "--name", + action="store", + default="dkr", + help="Name of controller. Default is dkr.", +) +parser.add_argument( + "--base", + "-b", + help="additional optional prefix to file location of KERI keystore", + required=False, + default="", +) +parser.add_argument( + "--passcode", + help="22 character encryption passcode for keystore (is not saved)", + dest="bran", + default=None, +) # passcode => bran +parser.add_argument( + "--did", "-d", help="DID to resolve (did:keri method)", required=True +) +parser.add_argument( + "--oobi", "-o", help="OOBI to use for resolving the DID", required=False +) +parser.add_argument( + "--meta", + "-m", + help="Whether to include metadata (True), or only return the DID document (False)", + type=bool, + required=False, + default=None, +) def handler(args): hby = existing.setupHby(name=args.name, base=args.base, bran=args.bran) hbyDoer = habbing.HaberyDoer(habery=hby) # setup doer obl = oobiing.Oobiery(hby=hby) - res = KeriResolver(hby=hby, hbyDoer=hbyDoer, obl=obl, did=args.did, oobi=args.oobi, meta=args.meta) + res = KeriResolver( + hby=hby, hbyDoer=hbyDoer, obl=obl, did=args.did, oobi=args.oobi, meta=args.meta + ) return [res] @@ -55,7 +79,7 @@ def __init__(self, hby, hbyDoer, obl, did, oobi, meta): def resolve(self, tymth, tock=0.0, **opts): self.wind(tymth) self.tock = tock - _ = (yield self.tock) + _ = yield self.tock aid = didding.parseDIDKeri(self.did) print(f"From arguments got aid: {aid}", file=sys.stderr) @@ -68,7 +92,9 @@ def resolve(self, tymth, tock=0.0, **opts): while self.hby.db.roobi.get(keys=(self.oobi,)) is None: _ = yield tock - didresult = didding.generateDIDDoc(self.hby, did=self.did, aid=aid, oobi=self.oobi, meta=True) + didresult = didding.generateDIDDoc( + self.hby, did=self.did, aid=aid, oobi=self.oobi, meta=True + ) dd = didresult[didding.DD_FIELD] result = didresult if self.meta else dd data = json.dumps(result, indent=2) @@ -76,5 +102,3 @@ def resolve(self, tymth, tock=0.0, **opts): print(data) self.remove(self.toRemove) return result - - diff --git a/src/dkr/app/cli/commands/did/keri/resolver-service.py b/src/dkr/app/cli/commands/did/keri/resolver-service.py index 96dd9f1..a65d893 100644 --- a/src/dkr/app/cli/commands/did/keri/resolver-service.py +++ b/src/dkr/app/cli/commands/did/keri/resolver-service.py @@ -10,31 +10,51 @@ from dkr.core import resolving -parser = argparse.ArgumentParser(description='Expose did:keri resolver as an HTTP web service') -parser.set_defaults(handler=lambda args: launch(args), - transferable=True) -parser.add_argument('-p', '--http', - action='store', - default=7678, - help="Port on which to listen for did:keri resolution requests. Defaults to 7678") -parser.add_argument('-n', '--name', - action='store', - default="dkr", - help="Name of controller. Default is dkr.") -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran -parser.add_argument("--config-dir", - "-c", - dest="configDir", - help="directory override for configuration data", - default=None) -parser.add_argument('--config-file', - dest="configFile", - action='store', - default=None, - help="configuration filename override") +parser = argparse.ArgumentParser( + description="Expose did:keri resolver as an HTTP web service" +) +parser.set_defaults(handler=lambda args: launch(args), transferable=True) +parser.add_argument( + "-p", + "--http", + action="store", + default=7678, + help="Port on which to listen for did:keri resolution requests. Defaults to 7678", +) +parser.add_argument( + "-n", + "--name", + action="store", + default="dkr", + help="Name of controller. Default is dkr.", +) +parser.add_argument( + "--base", + "-b", + help="additional optional prefix to file location of KERI keystore", + required=False, + default="", +) +parser.add_argument( + "--passcode", + help="22 character encryption passcode for keystore (is not saved)", + dest="bran", + default=None, +) # passcode => bran +parser.add_argument( + "--config-dir", + "-c", + dest="configDir", + help="directory override for configuration data", + default=None, +) +parser.add_argument( + "--config-file", + dest="configFile", + action="store", + default=None, + help="configuration filename override", +) def launch(args, expire=0.0): @@ -46,22 +66,21 @@ def launch(args, expire=0.0): configFile = args.configFile configDir = args.configDir - ks = keeping.Keeper(name=name, - base=base, - temp=False, - reopen=True) + ks = keeping.Keeper(name=name, base=base, temp=False, reopen=True) - aeid = ks.gbls.get('aeid') + aeid = ks.gbls.get("aeid") cf = None if aeid is None: if configFile is not None: - cf = configing.Configer(name=configFile, - base=base, - headDirPath=configDir, - temp=False, - reopen=True, - clear=False) + cf = configing.Configer( + name=configFile, + base=base, + headDirPath=configDir, + temp=False, + reopen=True, + clear=False, + ) hby = habbing.Habery(name=name, base=base, bran=bran, cf=cf) else: diff --git a/src/dkr/app/cli/commands/did/webs/generate.py b/src/dkr/app/cli/commands/did/webs/generate.py index fc5eea5..6b535f5 100644 --- a/src/dkr/app/cli/commands/did/webs/generate.py +++ b/src/dkr/app/cli/commands/did/webs/generate.py @@ -20,29 +20,64 @@ from dkr.core import didding from dkr.core import webbing -parser = argparse.ArgumentParser(description='Generate a did:webs DID document and KEL/TEL file') -parser.set_defaults(handler=lambda args: handler(args), - transferable=True) -parser.add_argument('-n', '--name', - action='store', - default="dkr", - help="Name of controller. Default is dkr.") -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran -parser.add_argument("--did", "-d", help="DID to generate (did:webs method)", required=True) +parser = argparse.ArgumentParser( + description="Generate a did:webs DID document and KEL/TEL file" +) +parser.set_defaults(handler=lambda args: handler(args), transferable=True) +parser.add_argument( + "-n", + "--name", + action="store", + default="dkr", + help="Name of controller. Default is dkr.", +) +parser.add_argument( + "--base", + "-b", + help="additional optional prefix to file location of KERI keystore", + required=False, + default="", +) +parser.add_argument( + "--passcode", + help="22 character encryption passcode for keystore (is not saved)", + dest="bran", + default=None, +) # passcode => bran +parser.add_argument( + "--did", "-d", help="DID to generate (did:webs method)", required=True +) # parser.add_argument("--oobi", "-o", help="OOBI to use for resolving the AID", required=False) -parser.add_argument('-da', '--da_reg', - required=False, - default=None, - help="Name of regery to find designated aliases attestation. Default is None.") -parser.add_argument("--meta", "-m", help="Whether to include metadata (True), or only return the DID document (False)", type=bool, required=False, default=False) +parser.add_argument( + "-da", + "--da_reg", + required=False, + default=None, + help="Name of regery to find designated aliases attestation. Default is None.", +) +parser.add_argument( + "--meta", + "-m", + help="Whether to include metadata (True), or only return the DID document (False)", + type=bool, + required=False, + default=False, +) + def handler(args): - gen = Generator(name=args.name, base=args.base, bran=args.bran, did=args.did, oobi=None, da_reg=args.da_reg, meta=args.meta) + gen = Generator( + name=args.name, + base=args.base, + bran=args.bran, + did=args.did, + oobi=None, + da_reg=args.da_reg, + meta=args.meta, + ) return [gen] + class Generator(doing.DoDoer): def __init__(self, name, base, bran, did, oobi, da_reg, meta=False): @@ -57,7 +92,16 @@ def __init__(self, name, base, bran, did, oobi, da_reg, meta=False): # self.oobi = oobi self.da_reg = da_reg self.meta = meta - print("Generate DID document command", did, "using oobi", oobi, "and metadata", meta, "registry name for creds", da_reg) + print( + "Generate DID document command", + did, + "using oobi", + oobi, + "and metadata", + meta, + "registry name for creds", + da_reg, + ) self.toRemove = [hbyDoer] + obl.doers doers = list(self.toRemove) + [doing.doify(self.generate)] @@ -66,11 +110,11 @@ def __init__(self, name, base, bran, did, oobi, da_reg, meta=False): def generate(self, tymth, tock=0.0, **opts): self.wind(tymth) self.tock = tock - _ = (yield self.tock) + _ = yield self.tock domain, port, path, aid = didding.parseDIDWebs(self.did) - msgs = bytearray() + msgs = bytearray() # if self.oobi is not None or self.oobi == "": # print(f"Using oobi {self.oobi} to get CESR event stream") # obr = basing.OobiRecord(date=helping.nowIso8601()) @@ -83,18 +127,18 @@ def generate(self, tymth, tock=0.0, **opts): # roobi = self.hby.db.roobi.get(keys=(self.oobi,)) # _ = yield tock # print(f"OOBI {self.oobi} resolved {roobi}") - + # oobiHab = self.hby.habs[aid] # print(f"Loading hab for OOBI {self.oobi}:\n {oobiHab}") # msgs = oobiHab.replyToOobi(aid=aid, role="controller", eids=None) # print(f"OOBI {self.oobi} CESR event stream {msgs.decode('utf-8')}") - + print(f"Generating CESR event stream data from hab") - #add KEL + # add KEL self.genKelCesr(aid, msgs) - #add designated aliases TELs and ACDCs + # add designated aliases TELs and ACDCs self.genCredCesr(aid, didding.DES_ALIASES_SCHEMA, msgs) - + # Create the directory (and any intermediate directories in the given path) if it doesn't already exist kc_dir_path = f"{aid}" if not os.path.exists(kc_dir_path): @@ -107,23 +151,30 @@ def generate(self, tymth, tock=0.0, **opts): print(f"Writing CESR events to {kc_file_path}: \n{tmsg}") kcf.write(tmsg) - #generate did doc - result = didding.generateDIDDoc(self.hby, did=self.did, aid=aid, oobi=None, reg_name=self.da_reg, meta=self.meta) - + # generate did doc + result = didding.generateDIDDoc( + self.hby, + did=self.did, + aid=aid, + oobi=None, + reg_name=self.da_reg, + meta=self.meta, + ) + diddoc = result - if(self.meta): + if self.meta: diddoc = result["didDocument"] print("Generated metadata for DID document", result["didDocumentMetadata"]) - + # Create the directory (and any intermediate directories in the given path) if it doesn't already exist dd_dir_path = f"{aid}" if not os.path.exists(dd_dir_path): os.makedirs(dd_dir_path) - + dd_file_path = os.path.join(dd_dir_path, f"{webbing.DID_JSON}") ddf = open(dd_file_path, "w") json.dump(didding.toDidWeb(diddoc), ddf) - + kever = self.hby.kevers[aid] # construct the KEL @@ -157,12 +208,7 @@ def generate(self, tymth, tock=0.0, **opts): except ValueError as e: raise e state = kever.state()._asdict() - result = dict( - didDocument=diddoc, - pre=pre, - state=state, - kel=kel - ) + result = dict(didDocument=diddoc, pre=pre, state=state, kel=kel) didData = json.dumps(result, indent=2) print(didData) @@ -173,28 +219,32 @@ def genKelCesr(self, pre: str, msgs: bytearray): print(f"Generating {pre} KEL CESR events") for msg in self.hby.db.clonePreIter(pre=pre): msgs.extend(msg) - + def genTelCesr(self, reger: viring.Reger, regk: str, msgs: bytearray): print(f"Generating {regk} TEL CESR events") for msg in reger.clonePreIter(pre=regk): msgs.extend(msg) - + def genAcdcCesr(self, aid, creder, msgs: bytearray): # print(f"Generating {creder.crd['d']} ACDC CESR events, issued by {creder.crd['i']}") cmsg = self.hby.habs[aid].endorse(creder) msgs.extend(cmsg) - + def genCredCesr(self, aid: str, schema: str, msgs: bytearray): rgy = credentialing.Regery(hby=self.hby, name=self.hby.name, base=self.hby.base) saids = rgy.reger.issus.get(keys=aid) scads = rgy.reger.schms.get(keys=schema.encode("utf-8")) # self-attested, there is no issuee, and schema is designated aliases - saiders = [saider for saider in saids if saider.qb64 in [saider.qb64 for saider in scads]] + saiders = [ + saider + for saider in saids + if saider.qb64 in [saider.qb64 for saider in scads] + ] for saider in saiders: - + creder, *_ = rgy.reger.cloneCred(said=saider.qb64) - + if creder.regi is not None: self.genTelCesr(rgy.reger, creder.regi, msgs) self.genTelCesr(rgy.reger, creder.said, msgs) diff --git a/src/dkr/app/cli/commands/did/webs/resolve.py b/src/dkr/app/cli/commands/did/webs/resolve.py index 4f6ad5a..c9f6a39 100644 --- a/src/dkr/app/cli/commands/did/webs/resolve.py +++ b/src/dkr/app/cli/commands/did/webs/resolve.py @@ -11,19 +11,37 @@ from dkr.core import resolving -parser = argparse.ArgumentParser(description='Resolve a did:webs DID') -parser.set_defaults(handler=lambda args: handler(args), - transferable=True) -parser.add_argument('-n', '--name', - action='store', - default="dkr", - help="Name of controller. Default is dkr.") -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran +parser = argparse.ArgumentParser(description="Resolve a did:webs DID") +parser.set_defaults(handler=lambda args: handler(args), transferable=True) +parser.add_argument( + "-n", + "--name", + action="store", + default="dkr", + help="Name of controller. Default is dkr.", +) +parser.add_argument( + "--base", + "-b", + help="additional optional prefix to file location of KERI keystore", + required=False, + default="", +) +parser.add_argument( + "--passcode", + help="22 character encryption passcode for keystore (is not saved)", + dest="bran", + default=None, +) # passcode => bran parser.add_argument("--did", "-d", help="DID to resolve", required=True) -parser.add_argument("--meta", "-m", help="Whether to include metadata (True), or only return the DID document (False)", type=bool, required=False, default=None) +parser.add_argument( + "--meta", + "-m", + help="Whether to include metadata (True), or only return the DID document (False)", + type=bool, + required=False, + default=None, +) def handler(args): @@ -49,8 +67,8 @@ def __init__(self, hby, hbyDoer, obl, did, meta): def resolve(self, tymth, tock=0.125, **opts): self.wind(tymth) self.tock = tock - _ = (yield self.tock) + _ = yield self.tock resolving.resolve(hby=self.hby, did=self.did, meta=self.meta) - - self.remove(self.toRemove) \ No newline at end of file + + self.remove(self.toRemove) diff --git a/src/dkr/app/cli/commands/did/webs/resolver-service.py b/src/dkr/app/cli/commands/did/webs/resolver-service.py index 9da3c03..ce3acf1 100644 --- a/src/dkr/app/cli/commands/did/webs/resolver-service.py +++ b/src/dkr/app/cli/commands/did/webs/resolver-service.py @@ -10,31 +10,51 @@ from dkr.core import resolving -parser = argparse.ArgumentParser(description='Expose did:webs resolver as an HTTP web service') -parser.set_defaults(handler=lambda args: launch(args), - transferable=True) -parser.add_argument('-p', '--http', - action='store', - default=7677, - help="Port on which to listen for did:webs resolution requests. Defaults to 7677") -parser.add_argument('-n', '--name', - action='store', - default="dkr", - help="Name of controller. Default is dkr.") -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran -parser.add_argument("--config-dir", - "-c", - dest="configDir", - help="directory override for configuration data", - default=None) -parser.add_argument('--config-file', - dest="configFile", - action='store', - default=None, - help="configuration filename override") +parser = argparse.ArgumentParser( + description="Expose did:webs resolver as an HTTP web service" +) +parser.set_defaults(handler=lambda args: launch(args), transferable=True) +parser.add_argument( + "-p", + "--http", + action="store", + default=7677, + help="Port on which to listen for did:webs resolution requests. Defaults to 7677", +) +parser.add_argument( + "-n", + "--name", + action="store", + default="dkr", + help="Name of controller. Default is dkr.", +) +parser.add_argument( + "--base", + "-b", + help="additional optional prefix to file location of KERI keystore", + required=False, + default="", +) +parser.add_argument( + "--passcode", + help="22 character encryption passcode for keystore (is not saved)", + dest="bran", + default=None, +) # passcode => bran +parser.add_argument( + "--config-dir", + "-c", + dest="configDir", + help="directory override for configuration data", + default=None, +) +parser.add_argument( + "--config-file", + dest="configFile", + action="store", + default=None, + help="configuration filename override", +) def launch(args, expire=0.0): @@ -46,22 +66,21 @@ def launch(args, expire=0.0): configFile = args.configFile configDir = args.configDir - ks = keeping.Keeper(name=name, - base=base, - temp=False, - reopen=True) + ks = keeping.Keeper(name=name, base=base, temp=False, reopen=True) - aeid = ks.gbls.get('aeid') + aeid = ks.gbls.get("aeid") cf = None if aeid is None: if configFile is not None: - cf = configing.Configer(name=configFile, - base=base, - headDirPath=configDir, - temp=False, - reopen=True, - clear=False) + cf = configing.Configer( + name=configFile, + base=base, + headDirPath=configDir, + temp=False, + reopen=True, + clear=False, + ) hby = habbing.Habery(name=name, base=base, bran=bran, cf=cf) else: diff --git a/src/dkr/app/cli/commands/did/webs/service.py b/src/dkr/app/cli/commands/did/webs/service.py index 660789d..13fc899 100644 --- a/src/dkr/app/cli/commands/did/webs/service.py +++ b/src/dkr/app/cli/commands/did/webs/service.py @@ -14,31 +14,51 @@ from dkr.core import webbing -parser = argparse.ArgumentParser(description='Launch web server capable of serving KERI AIDs as did:webs and did:web DIDs') -parser.set_defaults(handler=lambda args: launch(args), - transferable=True) -parser.add_argument('-p', '--http', - action='store', - default=7676, - help="Port on which to listen for did:webs requests") -parser.add_argument('-n', '--name', - action='store', - default="dkr", - help="Name of controller. Default is dkr.") -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran -parser.add_argument("--config-dir", - "-c", - dest="configDir", - help="directory override for configuration data", - default=None) -parser.add_argument('--config-file', - dest="configFile", - action='store', - default="dkr", - help="configuration filename override") +parser = argparse.ArgumentParser( + description="Launch web server capable of serving KERI AIDs as did:webs and did:web DIDs" +) +parser.set_defaults(handler=lambda args: launch(args), transferable=True) +parser.add_argument( + "-p", + "--http", + action="store", + default=7676, + help="Port on which to listen for did:webs requests", +) +parser.add_argument( + "-n", + "--name", + action="store", + default="dkr", + help="Name of controller. Default is dkr.", +) +parser.add_argument( + "--base", + "-b", + help="additional optional prefix to file location of KERI keystore", + required=False, + default="", +) +parser.add_argument( + "--passcode", + help="22 character encryption passcode for keystore (is not saved)", + dest="bran", + default=None, +) # passcode => bran +parser.add_argument( + "--config-dir", + "-c", + dest="configDir", + help="directory override for configuration data", + default=None, +) +parser.add_argument( + "--config-file", + dest="configFile", + action="store", + default="dkr", + help="configuration filename override", +) parser.add_argument("--keypath", action="store", required=False, default=None) parser.add_argument("--certpath", action="store", required=False, default=None) parser.add_argument("--cafilepath", action="store", required=False, default=None) @@ -56,19 +76,18 @@ def launch(args): configFile = args.configFile configDir = args.configDir - ks = keeping.Keeper(name=name, - base=base, - temp=False, - reopen=True) + ks = keeping.Keeper(name=name, base=base, temp=False, reopen=True) - aeid = ks.gbls.get('aeid') + aeid = ks.gbls.get("aeid") - cf = configing.Configer(name=configFile, - base=base, - headDirPath=configDir, - temp=False, - reopen=True, - clear=False) + cf = configing.Configer( + name=configFile, + base=base, + headDirPath=configDir, + temp=False, + reopen=True, + clear=False, + ) if aeid is None: print(f"Creating new habery {name} {base} {bran} {cf}") @@ -82,16 +101,20 @@ def launch(args): app = falcon.App( middleware=falcon.CORSMiddleware( - allow_origins='*', - allow_credentials='*', - expose_headers=['cesr-attachment', 'cesr-date', 'content-type'])) + allow_origins="*", + allow_credentials="*", + expose_headers=["cesr-attachment", "cesr-date", "content-type"], + ) + ) if keypath is not None: - servant = hio.core.tcp.ServerTls(certify=False, - keypath=keypath, - certpath=certpath, - cafilepath=cafilepath, - port=httpPort) + servant = hio.core.tcp.ServerTls( + certify=False, + keypath=keypath, + certpath=certpath, + cafilepath=cafilepath, + port=httpPort, + ) else: servant = None @@ -102,5 +125,7 @@ def launch(args): webbing.setup(app, hby=hby, cf=cf) - print(f"Launched web server capable of serving KERI AIDs as did:webs DIDs on: {httpPort}") + print( + f"Launched web server capable of serving KERI AIDs as did:webs DIDs on: {httpPort}" + ) return doers diff --git a/src/dkr/app/cli/dkr.py b/src/dkr/app/cli/dkr.py index 52dd90d..4f2cd10 100644 --- a/src/dkr/app/cli/dkr.py +++ b/src/dkr/app/cli/dkr.py @@ -20,7 +20,7 @@ def main(): parser = multicommand.create_parser(commands) args = parser.parse_args() - if not hasattr(args, 'handler'): + if not hasattr(args, "handler"): parser.print_help() return diff --git a/src/dkr/core/didding.py b/src/dkr/core/didding.py index dace1a2..619e50f 100644 --- a/src/dkr/core/didding.py +++ b/src/dkr/core/didding.py @@ -14,22 +14,26 @@ from keri import kering from keri.app import oobiing, habbing from keri.app.cli.common import terming -from keri.core import coring,scheming +from keri.core import coring, scheming from keri.help import helping from keri.vdr import credentialing, verifying -DID_KERI_RE = re.compile(r'\Adid:keri:(?P[^:]+)\Z', re.IGNORECASE) -DID_WEBS_RE = re.compile(r'\Adid:web(s)?:(?P[^%:]+)(?:%3a(?P\d+))?(?::(?P.+?))?(?::(?P[^:]+))\Z', re.IGNORECASE) +DID_KERI_RE = re.compile(r"\Adid:keri:(?P[^:]+)\Z", re.IGNORECASE) +DID_WEBS_RE = re.compile( + r"\Adid:web(s)?:(?P[^%:]+)(?:%3a(?P\d+))?(?::(?P.+?))?(?::(?P[^:]+))\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" +DES_ALIASES_SCHEMA = "EN6Oh5XSD5_q2Hgu-aqpdfbVepdpYpFlgz6zvJL5b_r5" + +DID_RES_META_FIELD = "didResolutionMetadata" +DD_META_FIELD = "didDocumentMetadata" +DD_FIELD = "didDocument" +VMETH_FIELD = "verificationMethod" -DID_RES_META_FIELD='didResolutionMetadata' -DD_META_FIELD='didDocumentMetadata' -DD_FIELD='didDocument' -VMETH_FIELD='verificationMethod' def parseDIDKeri(did): match = DID_KERI_RE.match(did) @@ -45,6 +49,7 @@ def parseDIDKeri(did): return aid + def parseDIDWebs(did): match = DID_WEBS_RE.match(did) if match is None: @@ -63,12 +68,23 @@ def parseDIDWebs(did): def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, meta=False, reg_name=None): if (did and aid) and not did.endswith(aid): raise ValueError(f"{did} does not end with {aid}") - print("Generating DID document for", did, "with aid", aid, "using oobi", oobi, "and metadata", meta, "registry name for creds", reg_name) - + print( + "Generating DID document for", + did, + "with aid", + aid, + "using oobi", + oobi, + "and metadata", + meta, + "registry name for creds", + reg_name, + ) + hab = None if aid in hby.habs: hab = hby.habs[aid] - + if oobi is not None: obr = hby.db.roobi.get(keys=(oobi,)) if obr is None or obr.state == oobiing.Result.failed: @@ -80,76 +96,77 @@ def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, meta=False, reg_nam if aid in hby.kevers: kever = hby.kevers[aid] else: - print(f"Habery does not have a kever for {did}. Did you parse the keri.cesr file?") + print( + f"Habery does not have a kever for {did}. Did you parse the keri.cesr file?" + ) for kev in hby.kevers: print("Known kevers: ", kev) hby.kevers[aid] - + vms = [] for idx, verfer in enumerate(kever.verfers): kid = verfer.qb64 - x = urlsafe_b64encode(verfer.raw).rstrip(b'=').decode('utf-8') - vms.append(dict( - id=f"#{verfer.qb64}", - type="JsonWebKey", - controller=did, - publicKeyJwk=dict( - kid=f"{kid}", - kty="OKP", - crv="Ed25519", - x=f"{x}" + x = urlsafe_b64encode(verfer.raw).rstrip(b"=").decode("utf-8") + vms.append( + dict( + id=f"#{verfer.qb64}", + type="JsonWebKey", + controller=did, + publicKeyJwk=dict(kid=f"{kid}", kty="OKP", crv="Ed25519", x=f"{x}"), ) - )) + ) if isinstance(kever.tholder.thold, int): if kever.tholder.thold > 1: conditions = [vm.get("id") for vm in vms] - vms.append(dict( - id=f"#{aid}", - type="ConditionalProof2022", - controller=did, - threshold=kever.tholder.thold, - conditionThreshold=conditions - )) + vms.append( + dict( + id=f"#{aid}", + type="ConditionalProof2022", + controller=did, + threshold=kever.tholder.thold, + conditionThreshold=conditions, + ) + ) elif isinstance(kever.tholder.thold, list): lcd = int(math.lcm(*[fr.denominator for fr in kever.tholder.thold[0]])) - threshold = float(lcd/2) - numerators = [int(fr.numerator * lcd / fr.denominator) for fr in kever.tholder.thold[0]] + threshold = float(lcd / 2) + numerators = [ + int(fr.numerator * lcd / fr.denominator) for fr in kever.tholder.thold[0] + ] conditions = [] for idx, verfer in enumerate(kever.verfers): - conditions.append(dict( - condition=vms[idx]['id'], - weight=numerators[idx] - )) - vms.append(dict( - id=f"#{aid}", - type="ConditionalProof2022", - controller=did, - threshold=threshold, - conditionWeightedThreshold=conditions - )) - - x = [(keys[1], loc.url) for keys, loc in - hby.db.locs.getItemIter(keys=(aid,)) if loc.url] + conditions.append(dict(condition=vms[idx]["id"], weight=numerators[idx])) + vms.append( + dict( + id=f"#{aid}", + type="ConditionalProof2022", + controller=did, + threshold=threshold, + conditionWeightedThreshold=conditions, + ) + ) + + x = [ + (keys[1], loc.url) + for keys, loc in hby.db.locs.getItemIter(keys=(aid,)) + if loc.url + ] witnesses = [] for idx, eid in enumerate(kever.wits): keys = (eid,) for (tid, scheme), loc in hby.db.locs.getItemIter(keys): - witnesses.append(dict( - idx=idx, - scheme=scheme, - url=loc.url - )) - - sEnds=[] + witnesses.append(dict(idx=idx, scheme=scheme, url=loc.url)) + + sEnds = [] # hab.fetchRoleUrls(hab.pre).get("controller").get("EGadHcyW9IfVIPrFUAa_I0z4dF8QzQAvUvfaUTJk8Jre").get("http") == "http://127.0.0.1:7777" - if hab and hasattr(hab, 'fetchRoleUrls'): + if hab and hasattr(hab, "fetchRoleUrls"): ends = hab.fetchRoleUrls(aid) sEnds.extend(addEnds(ends)) ends = hab.fetchWitnessUrls(aid) sEnds.extend(addEnds(ends)) - + # similar to kli vc list --name "$alias" --alias "$alias" --issued --said --schema "${d_alias_schema}") eq_ids = [] aka_ids = [] @@ -158,49 +175,51 @@ def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, meta=False, reg_nam dws_pre = "did:webs" 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] print(f"Also Known As DIDs: {aka_ids}") - + didResolutionMetadata = dict( contentType="application/did+json", - retrieved=datetime.datetime.now(datetime.UTC).strftime(DID_TIME_FORMAT) + retrieved=datetime.datetime.now(datetime.UTC).strftime(DID_TIME_FORMAT), ) didDocumentMetadata = dict( witnesses=witnesses, versionId=f"{kever.sner.num}", equivalentId=eq_ids, ) - diddoc = dict( - id=did, - verificationMethod=vms, - service=sEnds, - alsoKnownAs=aka_ids - ) + diddoc = dict(id=did, verificationMethod=vms, service=sEnds, alsoKnownAs=aka_ids) if meta is True: resolutionResult = dict( didDocument=diddoc, didResolutionMetadata=didResolutionMetadata, - didDocumentMetadata=didDocumentMetadata + didDocumentMetadata=didDocumentMetadata, ) return resolutionResult else: return diddoc + def toDidWeb(diddoc): - diddoc['id'] = diddoc['id'].replace('did:webs', 'did:web') + diddoc["id"] = diddoc["id"].replace("did:webs", "did:web") for verificationMethod in diddoc[VMETH_FIELD]: - verificationMethod['controller'] = verificationMethod['controller'].replace('did:webs', 'did:web') + verificationMethod["controller"] = verificationMethod["controller"].replace( + "did:webs", "did:web" + ) return diddoc + def fromDidWeb(diddoc): - diddoc['id'] = diddoc['id'].replace('did:web', 'did:webs') + diddoc["id"] = diddoc["id"].replace("did:web", "did:webs") for verificationMethod in diddoc[VMETH_FIELD]: - verificationMethod['controller'] = verificationMethod['controller'].replace('did:web', 'did:webs') + verificationMethod["controller"] = verificationMethod["controller"].replace( + "did:web", "did:webs" + ) return diddoc -def desAliases(hby: habbing.Habery, aid: str, reg_name: str=None): + +def desAliases(hby: habbing.Habery, aid: str, reg_name: str = None): """ Returns the credentialer for the des-aliases schema, or None if it doesn't exist. """ @@ -210,28 +229,36 @@ def desAliases(hby: habbing.Habery, aid: str, reg_name: str=None): reg_name = hby.habs[aid].name rgy = credentialing.Regery(hby=hby, name=reg_name) vry = verifying.Verifier(hby=hby, reger=rgy.reger) - + saids = rgy.reger.issus.get(keys=aid) scads = rgy.reger.schms.get(keys=DES_ALIASES_SCHEMA.encode("utf-8")) # self-attested, there is no issuee, and schmea is designated aliases - saids = [saider for saider in saids if saider.qb64 in [saider.qb64 for saider in scads]] + saids = [ + saider + for saider in saids + if saider.qb64 in [saider.qb64 for saider in scads] + ] # for saider in saiders: - creds = rgy.reger.cloneCreds(saids,hby.habs[aid].db) + creds = rgy.reger.cloneCreds(saids, hby.habs[aid].db) for idx, cred in enumerate(creds): - sad = cred['sad'] + sad = cred["sad"] status = cred["status"] - schema = sad['s'] + schema = sad["s"] scraw = vry.resolver.resolve(schema) schemer = scheming.Schemer(raw=scraw) print(f"Credential #{idx+1}: {sad['d']}") print(f" Type: {schemer.sed['title']}") - if status['et'] == 'iss' or status['et'] == 'bis': - print(f" Status: Issued {terming.Colors.OKGREEN}{terming.Symbols.CHECKMARK}{terming.Colors.ENDC}") - da_ids = sad['a']['ids'] - elif status['et'] == 'rev' or status['et'] == 'brv': - print(f" Status: Revoked {terming.Colors.FAIL}{terming.Symbols.FAILED}{terming.Colors.ENDC}") + if status["et"] == "iss" or status["et"] == "bis": + print( + f" Status: Issued {terming.Colors.OKGREEN}{terming.Symbols.CHECKMARK}{terming.Colors.ENDC}" + ) + da_ids = sad["a"]["ids"] + elif status["et"] == "rev" or status["et"] == "brv": + print( + f" Status: Revoked {terming.Colors.FAIL}{terming.Symbols.FAILED}{terming.Colors.ENDC}" + ) else: print(f" Status: Unknown") print(f" Issued by {sad['i']}") @@ -239,6 +266,7 @@ def desAliases(hby: habbing.Habery, aid: str, reg_name: str=None): return da_ids + def addEnds(ends): # wurls = hab.fetchWitnessUrls(hab.pre) # wwits = wurls.getall("witness") @@ -247,8 +275,8 @@ def addEnds(ends): # wwit2 = wwits[1] # wse2 = wwit2.get("BAjTuhnzPDB0oU0qHXACnvzachJpYjUAtH1N9Tsb_MdE") # assert wse2.get("http") == "http://127.0.0.1:9999" - - sEnds=list() + + sEnds = list() for role in ends: rList = ends.getall(role) for eList in rList: @@ -257,12 +285,8 @@ def addEnds(ends): sDict = dict() for proto in val: host = val[proto] - sDict[proto]=f"{host}" - v = dict( - id=f"#{eid}/{role}", - type=role, - serviceEndpoint=sDict - ) + sDict[proto] = f"{host}" + v = dict(id=f"#{eid}/{role}", type=role, serviceEndpoint=sDict) if v not in sEnds: sEnds.append(v) return sEnds diff --git a/src/dkr/core/resolving.py b/src/dkr/core/resolving.py index a9a2a68..ce94f2b 100644 --- a/src/dkr/core/resolving.py +++ b/src/dkr/core/resolving.py @@ -19,12 +19,13 @@ import requests import sys + def getSrcs(did: str, resq: queue.Queue = None): print(f"Parsing DID {did}") domain, port, path, aid = didding.parseDIDWebs(did=did) - opt_port = (f':{port}' if port is not None else '') - opt_path = (f"/{path.replace(':', '/')}" if path is not None else '') + 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 @@ -38,37 +39,50 @@ def getSrcs(did: str, resq: queue.Queue = None): print(f"Loading KERI CESR from {kc_url}") kc_res = loadUrl(kc_url, resq=resq) print(f"Got KERI CESR: {kc_res.content.decode('utf-8')}") - + if resq is not None: resq.put(aid) resq.put(dd_res) resq.put(kc_res) return aid, dd_res, kc_res -def saveCesr(hby: habbing.Habery, kc_res: requests.Response, aid: str = None): - print("Saving KERI CESR to hby", kc_res.content.decode('utf-8')) - hby.psr.parse(ims=bytearray(kc_res.content)) - if(aid): - - assert aid in hby.kevers, f"KERI CESR parsing failed, KERI AID {aid} not found in habery" -def getComp(hby: habbing.Habery, did: str, aid: str, dd_res: requests.Response, kc_res: requests.Response): +def saveCesr(hby: habbing.Habery, kc_res: requests.Response, aid: str = None): + print("Saving KERI CESR to hby", kc_res.content.decode("utf-8")) + hby.psr.parse(ims=bytearray(kc_res.content), local=True) + if aid: + + assert ( + aid in hby.kevers + ), f"KERI CESR parsing failed, KERI AID {aid} not found in habery" + + +def getComp( + hby: habbing.Habery, + did: str, + aid: str, + dd_res: requests.Response, + kc_res: requests.Response, +): dd = didding.generateDIDDoc(hby, did=did, aid=aid, oobi=None, meta=True) - dd[didding.DD_META_FIELD]['didDocUrl'] = dd_res.url - dd[didding.DD_META_FIELD]['keriCesrUrl'] = kc_res.url + dd[didding.DD_META_FIELD]["didDocUrl"] = dd_res.url + dd[didding.DD_META_FIELD]["keriCesrUrl"] = kc_res.url dd_actual = didding.fromDidWeb(json.loads(dd_res.content.decode("utf-8"))) print(f"Got DID Doc: {dd_actual}") return dd, dd_actual + def verify(dd, dd_actual, meta: bool = False): dd_exp = dd if didding.DD_FIELD in dd_exp: dd_exp = dd[didding.DD_FIELD] # TODO verify more than verificationMethod - verified = _verifyDidDocs(dd_exp[didding.VMETH_FIELD], dd_actual[didding.VMETH_FIELD]) - + verified = _verifyDidDocs( + dd_exp[didding.VMETH_FIELD], dd_actual[didding.VMETH_FIELD] + ) + result = None if verified: result = dd if meta else dd[didding.DD_FIELD] @@ -78,13 +92,16 @@ def verify(dd, dd_actual, meta: bool = False): didresult[didding.DD_FIELD] = None if didding.DID_RES_META_FIELD not in didresult: didresult[didding.DID_RES_META_FIELD] = dict() - didresult[didding.DID_RES_META_FIELD]['error'] = 'notVerified' - didresult[didding.DID_RES_META_FIELD]['errorMessage'] = 'The DID document could not be verified against the KERI event stream' + didresult[didding.DID_RES_META_FIELD]["error"] = "notVerified" + didresult[didding.DID_RES_META_FIELD][ + "errorMessage" + ] = "The DID document could not be verified against the KERI event stream" result = didresult print(f"DID verification failed") return result - + + def _verifyDidDocs(expected, actual): # TODO determine what to do with BADA RUN things like services (witnesses) etc. if expected != actual: @@ -94,12 +111,16 @@ def _verifyDidDocs(expected, actual): else: print("DID Doc verified", file=sys.stderr) return True - + + def _compare_dicts(expected, actual, path=""): - print(f"Comparing dictionaries:\nexpected:\n{expected}\n \nand\n \nactual:\n{actual}", file=sys.stderr) - + print( + f"Comparing dictionaries:\nexpected:\n{expected}\n \nand\n \nactual:\n{actual}", + file=sys.stderr, + ) + """Recursively compare two dictionaries and print differences.""" - if isinstance(expected,dict): + if isinstance(expected, dict): for k in expected.keys(): # Construct current path current_path = f"{path}.{k}" if path else k @@ -107,17 +128,26 @@ def _compare_dicts(expected, actual, path=""): # 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) + 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) + 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) + print( + f"{current_path} is a dictionary in actual, but not in expected", + file=sys.stderr, + ) continue # If value is another dictionary, recurse @@ -125,34 +155,51 @@ def _compare_dicts(expected, actual, path=""): _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) + print( + f"Different values for key {current_path}: {expected[k]} (expected) vs. {actual[k]} (actual)", + file=sys.stderr, + ) - if isinstance(actual,dict): + if isinstance(actual, dict): # 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) + print( + f"Key {current_path} not found in the expected dictionary", + file=sys.stderr, + ) else: - print(f"Expecting actual did document to contain dictionary {expected}", file=sys.stderr) - elif isinstance(expected,list): + print( + f"Expecting actual did document to contain dictionary {expected}", + file=sys.stderr, + ) + elif isinstance(expected, list): if len(expected) != len(actual): - print(f"Expected list {expected} and actual list {actual} are not the same length", file=sys.stderr) + print( + f"Expected list {expected} and actual list {actual} are not the same length", + file=sys.stderr, + ) else: for i in range(len(expected)): _compare_dicts(expected[i], actual[i], path) else: if expected != actual: - print(f"Different values for key {path}: {expected} (expected) vs. {actual} (actual)", file=sys.stderr) + print( + f"Different values for key {path}: {expected} (expected) vs. {actual} (actual)", + file=sys.stderr, + ) + def resolve(hby, did, meta=False, resq: queue.Queue = None): aid, dd_res, kc_res = getSrcs(did=did, resq=resq) - saveCesr(hby=hby,kc_res=kc_res, aid=aid) - dd, dd_actual = getComp(hby=hby, did=did, aid=aid, dd_res=dd_res, kc_res=kc_res) + saveCesr(hby=hby, kc_res=kc_res, aid=aid) + dd, dd_actual = getComp(hby=hby, did=did, aid=aid, dd_res=dd_res, kc_res=kc_res) vresult = verify(dd, dd_actual, meta=meta) - print("Resolution result: ", vresult) + print("Resolution result: ", vresult) return vresult + # # Test with the provided dictionaries # expected_dict = { # 'id': 'did:webs:127.0.0.1%3a7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha', @@ -171,8 +218,9 @@ def resolve(hby, did, meta=False, resq: queue.Queue = None): # compare_dicts(expected_dict, actual_dict) + def setup(hby, hbyDoer, obl, *, httpPort): - """ Setup serving package and endpoints + """Setup serving package and endpoints Parameters: hby (Habery): identifier database environment @@ -182,9 +230,11 @@ def setup(hby, hbyDoer, obl, *, httpPort): print(f"Setup resolving") app = falcon.App( middleware=falcon.CORSMiddleware( - allow_origins='*', - allow_credentials='*', - expose_headers=['cesr-attachment', 'cesr-date', 'content-type'])) + allow_origins="*", + allow_credentials="*", + expose_headers=["cesr-attachment", "cesr-date", "content-type"], + ) + ) server = http.Server(port=httpPort, app=app) httpServerDoer = http.ServerDoer(server=server) @@ -199,7 +249,7 @@ def setup(hby, hbyDoer, obl, *, httpPort): def loadEnds(app, *, hby, hbyDoer, obl, prefix=""): print(f"Loading resolving endpoints") resolveEnd = ResolveResource(hby=hby, hbyDoer=hbyDoer, obl=obl) - result = app.add_route('/1.0/identifiers/{did}', resolveEnd) + result = app.add_route("/1.0/identifiers/{did}", resolveEnd) print(f"Loaded resolving endpoints: {app}") return [resolveEnd] @@ -212,7 +262,7 @@ class ResolveResource(doing.DoDoer): """ def __init__(self, hby, hbyDoer, obl): - """ Create Endpoints for discovery and resolution of OOBIs + """Create Endpoints for discovery and resolution of OOBIs Parameters: hby (Habery): identifier database environment @@ -233,23 +283,23 @@ def on_get(self, req, rep, did, meta=False): rep.text = "invalid resolution request body, 'did' is required" return - if 'oobi' in req.params: - oobi = req.params['oobi'] + if "oobi" in req.params: + oobi = req.params["oobi"] print(f"From parameters {req.params} got oobi: {oobi}") else: oobi = None - if did.startswith('did:webs:'): - #res = WebsResolver(hby=self.hby, hbyDoer=self.hbyDoer, obl=self.obl, did=did) - #tymth = None # ??? - #data = res.resolve(tymth) + if did.startswith("did:webs:"): + # res = WebsResolver(hby=self.hby, hbyDoer=self.hbyDoer, obl=self.obl, did=did) + # tymth = None # ??? + # data = res.resolve(tymth) cmd = f"dkr did webs resolve --name dkr --did {did} --meta {meta}" stream = os.popen(cmd) data = stream.read() - elif did.startswith('did:keri'): - #res = KeriResolver(hby=self.hby, hbyDoer=self.hbyDoer, obl=self.obl, did=did, oobi=oobi, metadata=False) - #tymth = None # ??? - #data = res.resolve(tymth) + elif did.startswith("did:keri"): + # res = KeriResolver(hby=self.hby, hbyDoer=self.hbyDoer, obl=self.obl, did=did, oobi=oobi, metadata=False) + # tymth = None # ??? + # data = res.resolve(tymth) cmd = f"dkr did keri resolve --name dkr --did {did} --oobi {oobi} --meta {meta}" stream = os.popen(cmd) data = stream.read() @@ -259,23 +309,26 @@ def on_get(self, req, rep, did, meta=False): return rep.status = falcon.HTTP_200 - rep.set_header('Content-Type', "application/did+ld+json") + rep.set_header("Content-Type", "application/did+ld+json") rep.body = data return + def loadFile(file_path): # Read the file in binary mode - with open(file_path, 'rb') as file: + with open(file_path, "rb") as file: msgs = file.read() return msgs - + + def loadJsonFile(file_path): # Read the file in binary mode - with open(file_path, 'r', encoding="utf-8") as file: + with open(file_path, "r", encoding="utf-8") as file: msgs = json.load(file) return msgs - + + def loadUrl(url: str, resq: queue.Queue = None): response = requests.get(url=url) # Ensure the request was successful @@ -285,22 +338,23 @@ def loadUrl(url: str, resq: queue.Queue = None): resq.put(response) return response + def splitCesr(s, char): # Find the last occurrence of the character index = s.rfind(char) - + # If the character is not found, return the whole string and an empty string if index == -1: - return s, '' - - json_str = s[:index+1] + return s, "" + + json_str = s[: index + 1] # quote escaped starts with single quote and double quote and the split will lose the closing single/double quote - if(json_str.startswith('"')): + if json_str.startswith('"'): json_str = json_str + '"' - - cesr_sig = s[index + 1:] - if(cesr_sig.endswith('"')): + + cesr_sig = s[index + 1 :] + if cesr_sig.endswith('"'): cesr_sig = '"' + json_str # Split the string into two parts - return json_str, cesr_sig \ No newline at end of file + return json_str, cesr_sig diff --git a/src/dkr/core/webbing.py b/src/dkr/core/webbing.py index a09aba2..ac73138 100644 --- a/src/dkr/core/webbing.py +++ b/src/dkr/core/webbing.py @@ -24,7 +24,7 @@ def setup(app, hby, cf): - """ Set up webbing endpoints to serve configured KERI AIDs as `did:web` DIDs + """Set up webbing endpoints to serve configured KERI AIDs as `did:web` DIDs Parameters: app (App): Falcon app to register endpoints against @@ -41,15 +41,20 @@ def setup(app, hby, cf): # loadEnds(app, hby, web) if DD_DIR_CFG in data: - print(f"Using config property {DD_DIR_CFG} to look for {DID_JSON} files: {data[DD_DIR_CFG]}") + print( + f"Using config property {DD_DIR_CFG} to look for {DID_JSON} files: {data[DD_DIR_CFG]}" + ) ddir = data[DD_DIR_CFG] if DD_DIR_CFG in data else DD_DEFAULT_DIR - dend = DidJsonResourceEnd(app,ddir) - + dend = DidJsonResourceEnd(app, ddir) + if KC_DIR_CFG in data: - print(f"Using config property {KC_DIR_CFG} to look for {KERI_CESR} files: {data[KC_DIR_CFG]}") + print( + f"Using config property {KC_DIR_CFG} to look for {KERI_CESR} files: {data[KC_DIR_CFG]}" + ) cdir = data[KC_DIR_CFG] if KC_DIR_CFG in data else KC_DEFAULT_DIR print(f"Using keri cesr dir {cdir}") - kend = KeriCesrWebResourceEnd(app,cdir,hby) + kend = KeriCesrWebResourceEnd(app, cdir, hby) + # def loadEnds(app, hby, web): # """ Load endpoints for all AIDs or configured AIDs only @@ -79,17 +84,18 @@ def setup(app, hby, cf): # print(f"Added route {path}") # app.add_route(path, res) -class DIDWebResourceEnd() : + +class DIDWebResourceEnd: def __init__(self, app, dpath, ftype): self.lookup = {} self.app = app - self.dpath=dpath + self.dpath = dpath self.ftype = ftype self.loadFileEnds() def add_lookup(self, aid, fpath): - self.lookup[aid] = fpath - + self.lookup[aid] = fpath + def loadFileEnds(self): print(f"Loading {self.ftype} files from directory {self.dpath}") @@ -99,13 +105,14 @@ def loadFileEnds(self): print(f"Looking for {self.ftype} file {aPath}") fpath = os.path.join(aPath, self.ftype) if os.path.isfile(fpath): - path=f"/{aid}/{self.ftype}" + path = f"/{aid}/{self.ftype}" print(f"registering {path}") self.app.add_route(f"/{{aid}}/" + self.ftype, self) self.add_lookup(aid, fpath) else: print(f"Skipping {fpath} as it is not a file") + # class DIDWebResourceEnd: # def __init__(self, hby): @@ -152,16 +159,17 @@ def loadFileEnds(self): # rep.content_type = "application/json" # rep.data = json.dumps(result, indent=2).encode("utf-8") + class DidJsonResourceEnd(DIDWebResourceEnd): - - def __init__(self,app,ddir): + + def __init__(self, app, ddir): """ Parameters: """ - super().__init__(app,ddir,DID_JSON) - + super().__init__(app, ddir, DID_JSON) + def on_get(self, req, rep, aid): - """ GET endpoint for acessing {DID_JSON} stream for AID + """GET endpoint for acessing {DID_JSON} stream for AID Parameters: req (Request) Falcon HTTP Request object: @@ -171,12 +179,16 @@ def on_get(self, req, rep, aid): """ # Read the DID from the parameter extracted from path or manually extract if not req.path.endswith(f"/{DID_JSON}"): - raise falcon.HTTPBadRequest(description=f"invalid {DID_JSON} DID URL {req.path}") + raise falcon.HTTPBadRequest( + description=f"invalid {DID_JSON} DID URL {req.path}" + ) self.loadFileEnds() if not aid in self.lookup: - raise falcon.HTTPNotFound(description=f"{DID_JSON} for KERI AID {aid} not found") + raise falcon.HTTPNotFound( + description=f"{DID_JSON} for KERI AID {aid} not found" + ) print("Serving DID Doc data for", aid) port = "" @@ -192,8 +204,9 @@ def on_get(self, req, rep, aid): rep.content_type = ending.Mimes.json rep.data = json.dumps(content, indent=2).encode("utf-8") + class KeriCesrWebResourceEnd(DIDWebResourceEnd): - + def __init__(self, app, cdir, hby): """ Parameters: @@ -201,23 +214,27 @@ def __init__(self, app, cdir, hby): """ self.hby = hby - super().__init__(app,cdir,KERI_CESR) - + super().__init__(app, cdir, KERI_CESR) + def add_lookup(self, aid, fpath): # if aid is None: # aid = os.path.basename(os.path.normpath(path.rstrip(f"/{KERI_CESR}"))) # ahab = habbing..makeHab(name=aid, temp=True) # kvy = eventing.Kevery(db=ahab.db, lax=False, local=False) - with open(fpath, 'rb') as file: - self.hby.psr.parse(ims=bytearray(file.read())) - if(aid and aid in self.hby.kevers): - print(f"KERI CESR parsing {fpath} succeeded, KERI AID {aid} found in habery") + with open(fpath, "rb") as file: + self.hby.psr.parse(ims=bytearray(file.read()), local=True) + if aid and aid in self.hby.kevers: + print( + f"KERI CESR parsing {fpath} succeeded, KERI AID {aid} found in habery" + ) self.lookup[aid] = fpath else: - print(f"FAILED: KERI CESR parsing {fpath} failed, KERI AID {aid} not found in habery") - + print( + f"FAILED: KERI CESR parsing {fpath} failed, KERI AID {aid} not found in habery" + ) + def on_get(self, req, rep, aid): - """ GET endpoint for acessing {KERI_CESR} stream for AID + """GET endpoint for acessing {KERI_CESR} stream for AID Parameters: req (Request) Falcon HTTP Request object: @@ -227,12 +244,16 @@ def on_get(self, req, rep, aid): """ # Read the DID from the parameter extracted from path or manually extract if not req.path.endswith(f"/{KERI_CESR}"): - raise falcon.HTTPBadRequest(description=f"invalid {KERI_CESR} DID URL {req.path}") + raise falcon.HTTPBadRequest( + description=f"invalid {KERI_CESR} DID URL {req.path}" + ) self.loadFileEnds() if not aid in self.lookup: - raise falcon.HTTPNotFound(description=f"keri.cesr for KERI AID {aid} not found") + raise falcon.HTTPNotFound( + description=f"keri.cesr for KERI AID {aid} not found" + ) # 404 if AID not recognized # if aid not in self.hby.kevers: @@ -246,8 +267,8 @@ def on_get(self, req, rep, aid): # Open the file in read mode with open(f"{self.lookup[aid]}", "r", encoding="utf-8") as f: content = f.read() - print("KERI CESR content for",aid,content) + print("KERI CESR content for", aid, content) rep.status = falcon.HTTP_200 rep.content_type = CESR_MIME - rep.data = content.encode("utf-8") \ No newline at end of file + rep.data = content.encode("utf-8") diff --git a/src/dkr/didcomm/hello-world.py b/src/dkr/didcomm/hello-world.py index 915137a..2328278 100644 --- a/src/dkr/didcomm/hello-world.py +++ b/src/dkr/didcomm/hello-world.py @@ -1,4 +1,9 @@ -from utils import createKeriDid, SecretsResolverInMemory, DidKeriResolver, validateLongDid +from utils import ( + createKeriDid, + SecretsResolverInMemory, + DidKeriResolver, + validateLongDid, +) from didcomm.message import Message from didcomm.unpack import unpack from didcomm.common.resolvers import ResolversConfig @@ -7,90 +12,98 @@ import json alice = createKeriDid() -print("Alice's DID:", alice['did']) -print("Alice's Long DID:", alice['long_did'],"\n") +print("Alice's DID:", alice["did"]) +print("Alice's Long DID:", alice["long_did"], "\n") bob = createKeriDid() -print("Bob's DID:", bob['did']) -print("Bob's Long DID:", bob['long_did'],"\n") +print("Bob's DID:", bob["did"]) +print("Bob's Long DID:", bob["long_did"], "\n") -print("Compare length with Peer DID: did:peer:2.Vz6MkfiT7uT2EQnuNhGP2xxNsh2v7seoV3fzZWRpydJnF3K6z.Ez6LSfpsWUKP7g4LGTpXFPWZzThQtG1VuQqxtToKYtkXdRdc8.SeyJpZCI6IiNzZXJ2aWNlLTEiLCJ0IjoiZG0iLCJzIjoiZGlkOnBlZXI6Mi5FejZMU2U3U3FCUmJmWEdFNXJpVEZYYU5zZ2dWUFB6YThtNXdyR21ON0dRY0d5dHI2LlZ6Nk1ra3dmNWhWcUJVYXhFU3YxVHhra0pIQWNKRldnTXROY1g2Q1pyRkZpZllNQTkuU2V5SnBaQ0k2SW01bGR5MXBaQ0lzSW5RaU9pSmtiU0lzSW5NaU9pSm9kSFJ3Y3pvdkwyMWxaR2xoZEc5eUxuSnZiM1J6YVdRdVkyeHZkV1FpTENKaElqcGJJbVJwWkdOdmJXMHZkaklpWFgwIn","\n") +print( + "Compare length with Peer DID: did:peer:2.Vz6MkfiT7uT2EQnuNhGP2xxNsh2v7seoV3fzZWRpydJnF3K6z.Ez6LSfpsWUKP7g4LGTpXFPWZzThQtG1VuQqxtToKYtkXdRdc8.SeyJpZCI6IiNzZXJ2aWNlLTEiLCJ0IjoiZG0iLCJzIjoiZGlkOnBlZXI6Mi5FejZMU2U3U3FCUmJmWEdFNXJpVEZYYU5zZ2dWUFB6YThtNXdyR21ON0dRY0d5dHI2LlZ6Nk1ra3dmNWhWcUJVYXhFU3YxVHhra0pIQWNKRldnTXROY1g2Q1pyRkZpZllNQTkuU2V5SnBaQ0k2SW01bGR5MXBaQ0lzSW5RaU9pSmtiU0lzSW5NaU9pSm9kSFJ3Y3pvdkwyMWxaR2xoZEc5eUxuSnZiM1J6YVdRdVkyeHZkV1FpTENKaElqcGJJbVJwWkdOdmJXMHZkaklpWFgwIn", + "\n", +) -print("Alice's long DID validation:", validateLongDid(alice['long_did'])) -print("Bob's long DID validation:", validateLongDid(bob['long_did']),"\n") +print("Alice's long DID validation:", validateLongDid(alice["long_did"])) +print("Bob's long DID validation:", validateLongDid(bob["long_did"]), "\n") -store = { - alice['did']: alice, - bob['did']: bob -} +store = {alice["did"]: alice, bob["did"]: bob} secrets_resolver = SecretsResolverInMemory(store) did_resolver = DidKeriResolver(store) # Alice creates a basic message -alice_message = Message( - id = "123", - type = "https://didcomm.org/basicmessage/2.0/message", - body = {'content': 'Hello Bob!'}, +alice_message = Message( + id="123", + type="https://didcomm.org/basicmessage/2.0/message", + body={"content": "Hello Bob!"}, ) -print('1-Alice creates a basic message:',alice_message.body,"\n") +print("1-Alice creates a basic message:", alice_message.body, "\n") # Alice encrypts the message for Bob -alice_message_packed = asyncio.run( pack_encrypted( - resolvers_config = ResolversConfig( - secrets_resolver = secrets_resolver, - did_resolver = did_resolver - ), - message = alice_message, - frm = alice['long_did'], - to = bob['long_did'], - sign_frm = None, - pack_config = PackEncryptedConfig(protect_sender_id=False) -)) -print('2-Alice encrypts the message for Bob:') -print(alice_message_packed.packed_msg,"\n") +alice_message_packed = asyncio.run( + pack_encrypted( + resolvers_config=ResolversConfig( + secrets_resolver=secrets_resolver, did_resolver=did_resolver + ), + message=alice_message, + frm=alice["long_did"], + to=bob["long_did"], + sign_frm=None, + pack_config=PackEncryptedConfig(protect_sender_id=False), + ) +) +print("2-Alice encrypts the message for Bob:") +print(alice_message_packed.packed_msg, "\n") # Bob decrypts the message -bob_message_unpacked = asyncio.run( unpack( - resolvers_config=ResolversConfig( - secrets_resolver=secrets_resolver, - did_resolver=did_resolver - ), - packed_msg= alice_message_packed.packed_msg -)) -print('3-Bob decrypts the message:', bob_message_unpacked.message.body,"\n") +bob_message_unpacked = asyncio.run( + unpack( + resolvers_config=ResolversConfig( + secrets_resolver=secrets_resolver, did_resolver=did_resolver + ), + packed_msg=alice_message_packed.packed_msg, + ) +) +print("3-Bob decrypts the message:", bob_message_unpacked.message.body, "\n") # Bob creates a basic message response -bob_message = Message( - id = "124", - type = "https://didcomm.org/basicmessage/2.0/message", - body = {'content': 'Hello Alice!'}, +bob_message = Message( + id="124", + type="https://didcomm.org/basicmessage/2.0/message", + body={"content": "Hello Alice!"}, ) -print('4-Bob creates a response using short DIDs:',bob_message.body,"\n") +print("4-Bob creates a response using short DIDs:", bob_message.body, "\n") # Bob encrypts the message for Alice -bob_message_packed = asyncio.run( pack_encrypted( - resolvers_config = ResolversConfig( - secrets_resolver = secrets_resolver, - did_resolver = did_resolver - ), - message = bob_message, - frm = bob['did'], - to = alice['did'], - sign_frm = bob['did'], - pack_config = PackEncryptedConfig(protect_sender_id=False) -)) -print('5-Bob encrypts and sign the message for Alice:') -print(bob_message_packed.packed_msg,"\n") +bob_message_packed = asyncio.run( + pack_encrypted( + resolvers_config=ResolversConfig( + secrets_resolver=secrets_resolver, did_resolver=did_resolver + ), + message=bob_message, + frm=bob["did"], + to=alice["did"], + sign_frm=bob["did"], + pack_config=PackEncryptedConfig(protect_sender_id=False), + ) +) +print("5-Bob encrypts and sign the message for Alice:") +print(bob_message_packed.packed_msg, "\n") # Alice decrypts the message -alice_message_unpacked = asyncio.run( unpack( - resolvers_config=ResolversConfig( - secrets_resolver=secrets_resolver, - did_resolver=did_resolver - ), - packed_msg= bob_message_packed.packed_msg -)) -print('6-Alice decrypts the message with short DIDs:', alice_message_unpacked.message.body,"\n") +alice_message_unpacked = asyncio.run( + unpack( + resolvers_config=ResolversConfig( + secrets_resolver=secrets_resolver, did_resolver=did_resolver + ), + packed_msg=bob_message_packed.packed_msg, + ) +) +print( + "6-Alice decrypts the message with short DIDs:", + alice_message_unpacked.message.body, + "\n", +) -print(asyncio.run(did_resolver.resolve(alice['did']))) +print(asyncio.run(did_resolver.resolve(alice["did"]))) diff --git a/src/dkr/didcomm/utils.py b/src/dkr/didcomm/utils.py index d456728..2f25e07 100644 --- a/src/dkr/didcomm/utils.py +++ b/src/dkr/didcomm/utils.py @@ -1,10 +1,15 @@ from keri.core import eventing, coring -from didcomm.common.types import DID, VerificationMethodType, VerificationMaterial, VerificationMaterialFormat +from didcomm.common.types import ( + DID, + VerificationMethodType, + VerificationMaterial, + VerificationMaterialFormat, +) from didcomm.common.resolvers import SecretsResolver from didcomm.did_doc.did_doc import DIDDoc, VerificationMethod, DIDCommService from didcomm.did_doc.did_resolver import DIDResolver -from didcomm.secrets.secrets_resolver_demo import Secret +from didcomm.secrets.secrets_resolver_demo import Secret from typing import Optional, List @@ -14,13 +19,14 @@ from pprint import pp -''' +""" Utilities for DIDComm packing and unpacking using did:keri as alternative to Peer DID - Use SICPA didcomm-python library - Authcryypt message only - AID is Ed25519 and derive X25519 key pair from same private key - Transferable AID but with no next key that makes it non transferable (no key rotations) -''' +""" + def createKeriDid(): salt = coring.Salter() @@ -28,148 +34,154 @@ def createKeriDid(): X25519_pubkey = pysodium.crypto_sign_pk_to_box_pk(signerEd25519.verfer.raw) # Manual CESR coding - X25519_pubkey_qb64 = 'C'+ (base64.urlsafe_b64encode(bytes([0]) + X25519_pubkey).decode('utf-8'))[1:] + X25519_pubkey_qb64 = ( + "C" + (base64.urlsafe_b64encode(bytes([0]) + X25519_pubkey).decode("utf-8"))[1:] + ) # Or using karipy - X25519_pubkey_qb64 = coring.Matter(raw = X25519_pubkey, code=coring.MtrDex.X25519).qb64 + X25519_pubkey_qb64 = coring.Matter( + raw=X25519_pubkey, code=coring.MtrDex.X25519 + ).qb64 serder = eventing.incept( - keys=[signerEd25519.verfer.qb64], - data=[ - {"e":X25519_pubkey_qb64}, - {"se": "https://example.coom/"} - ], - code=coring.MtrDex.Blake3_256 # code is for self-addressing + keys=[signerEd25519.verfer.qb64], + data=[{"e": X25519_pubkey_qb64}, {"se": "https://example.coom/"}], + code=coring.MtrDex.Blake3_256, # code is for self-addressing ) - did = 'did:keri:'+serder.ked['i'] - kelb64 = base64.urlsafe_b64encode(bytes(json.dumps(serder.ked), 'utf-8')).decode('utf-8') - long_did = did+'?icp='+kelb64 + did = "did:keri:" + serder.ked["i"] + kelb64 = base64.urlsafe_b64encode(bytes(json.dumps(serder.ked), "utf-8")).decode( + "utf-8" + ) + long_did = did + "?icp=" + kelb64 # pp(serder.ked) - return { - 'did': did, - 'long_did': long_did, - 'signer': signerEd25519 - } + return {"did": did, "long_did": long_did, "signer": signerEd25519} + def validateLongDid(long_did): # TODO validate URL and make parsing safer - did = long_did.split('?')[0] - kelb64 = long_did.split('=')[1]+"==" + did = long_did.split("?")[0] + kelb64 = long_did.split("=")[1] + "==" kel_decoded = json.loads(base64.urlsafe_b64decode(kelb64)) prefixer = coring.Prefixer(ked=kel_decoded) - return prefixer.qb64b.decode("utf-8") == did.split(':')[2] + return prefixer.qb64b.decode("utf-8") == did.split(":")[2] + class SecretsResolverInMemory(SecretsResolver): def __init__(self, store: dict): self._store = store async def get_key(self, kid: str) -> Optional[Secret]: - - did, kident = kid.split('#') - signer = self._store[did]['signer'] + did, kident = kid.split("#") + + signer = self._store[did]["signer"] X25519_pubkey = pysodium.crypto_sign_pk_to_box_pk(signer.verfer.raw) - X25519_pubkey_b64 = base64.urlsafe_b64encode(X25519_pubkey).decode('utf-8') - X25519_prikey = pysodium.crypto_sign_sk_to_box_sk(signer.raw + signer.verfer.raw) - X25519_prikey_b64 = base64.urlsafe_b64encode(X25519_prikey).decode('utf-8') + X25519_pubkey_b64 = base64.urlsafe_b64encode(X25519_pubkey).decode("utf-8") + X25519_prikey = pysodium.crypto_sign_sk_to_box_sk( + signer.raw + signer.verfer.raw + ) + X25519_prikey_b64 = base64.urlsafe_b64encode(X25519_prikey).decode("utf-8") Ed25519_pubkey_raw = signer.verfer.raw - Ed25519_pubkey_b64 = base64.urlsafe_b64encode(Ed25519_pubkey_raw).decode('utf-8') - + Ed25519_pubkey_b64 = base64.urlsafe_b64encode(Ed25519_pubkey_raw).decode( + "utf-8" + ) + Ed25519_prikey_raw = signer.raw - Ed25519_prikey_b64 = base64.urlsafe_b64encode(Ed25519_prikey_raw).decode('utf-8') + Ed25519_prikey_b64 = base64.urlsafe_b64encode(Ed25519_prikey_raw).decode( + "utf-8" + ) secret = Secret( - kid= kid, - type= VerificationMethodType.JSON_WEB_KEY_2020, - verification_material= VerificationMaterial( - format=VerificationMaterialFormat.JWK, - value= json.dumps( - { - 'kty': 'OKP', - 'crv': 'X25519', - 'd': X25519_prikey_b64, - 'x': X25519_pubkey_b64, - 'kid': kid - } if kident == "key-1" else - { - 'kty': 'OKP', - 'crv': 'Ed25519', - 'd': Ed25519_prikey_b64, - 'x': Ed25519_pubkey_b64, - 'kid': kid - } - ) - ) - ) + kid=kid, + type=VerificationMethodType.JSON_WEB_KEY_2020, + verification_material=VerificationMaterial( + format=VerificationMaterialFormat.JWK, + value=json.dumps( + { + "kty": "OKP", + "crv": "X25519", + "d": X25519_prikey_b64, + "x": X25519_pubkey_b64, + "kid": kid, + } + if kident == "key-1" + else { + "kty": "OKP", + "crv": "Ed25519", + "d": Ed25519_prikey_b64, + "x": Ed25519_pubkey_b64, + "kid": kid, + } + ), + ), + ) return secret async def get_keys(self, kids: List[str]) -> List[str]: return kids + class DidKeriResolver(DIDResolver): def __init__(self, store: dict): self._store = store + async def resolve(self, did: DID) -> DIDDoc: # TODO validate URL and make parsing safer - short_did = did.split('?')[0] - if len(did.split('=')) > 1: - kelb64 = did.split('=')[1]+"==" + short_did = did.split("?")[0] + if len(did.split("=")) > 1: + kelb64 = did.split("=")[1] + "==" ked = json.loads(base64.urlsafe_b64decode(kelb64)) - self._store[short_did]['ked'] = ked + self._store[short_did]["ked"] = ked else: - ked = self._store[short_did]['ked'] + ked = self._store[short_did]["ked"] # Manual CESR Decoding - ed25519_pubkey_qb64 = ked['k'][0] + ed25519_pubkey_qb64 = ked["k"][0] ed25519_pubkey_b64 = "A" + ed25519_pubkey_qb64[1:] ed25519_pubkey_raw = base64.urlsafe_b64decode(ed25519_pubkey_b64)[1:] - x1 = base64.urlsafe_b64encode(ed25519_pubkey_raw).decode('utf-8') + x1 = base64.urlsafe_b64encode(ed25519_pubkey_raw).decode("utf-8") # Or using keripy: - x1 = base64.urlsafe_b64encode(coring.Matter(qb64=ked['k'][0]).raw).decode('utf-8') + x1 = base64.urlsafe_b64encode(coring.Matter(qb64=ked["k"][0]).raw).decode( + "utf-8" + ) - x2 = base64.urlsafe_b64encode(coring.Matter(qb64=ked['a'][0]['e']).raw).decode('utf-8') + x2 = base64.urlsafe_b64encode(coring.Matter(qb64=ked["a"][0]["e"]).raw).decode( + "utf-8" + ) return DIDDoc( did=did, - key_agreement_kids = [short_did+'#key-1'], - authentication_kids = [short_did+'#key-2'], - verification_methods = [ + key_agreement_kids=[short_did + "#key-1"], + authentication_kids=[short_did + "#key-2"], + verification_methods=[ VerificationMethod( - id = short_did+'#key-1', - type = VerificationMethodType.JSON_WEB_KEY_2020, - controller = did, - verification_material = VerificationMaterial( - format = VerificationMaterialFormat.JWK, - value = json.dumps({ - 'kty': 'OKP', - 'crv': 'X25519', - 'x': x2 - }) - ) + id=short_did + "#key-1", + type=VerificationMethodType.JSON_WEB_KEY_2020, + controller=did, + verification_material=VerificationMaterial( + format=VerificationMaterialFormat.JWK, + value=json.dumps({"kty": "OKP", "crv": "X25519", "x": x2}), + ), ), VerificationMethod( - id = short_did+'#key-2', - type = VerificationMethodType.JSON_WEB_KEY_2020, - controller = did, - verification_material = VerificationMaterial( - format = VerificationMaterialFormat.JWK, - value = json.dumps({ - 'kty': 'OKP', - 'crv': 'Ed25519', - 'x': x1 - }) - ) - ) + id=short_did + "#key-2", + type=VerificationMethodType.JSON_WEB_KEY_2020, + controller=did, + verification_material=VerificationMaterial( + format=VerificationMaterialFormat.JWK, + value=json.dumps({"kty": "OKP", "crv": "Ed25519", "x": x1}), + ), + ), ], - didcomm_services = [ + didcomm_services=[ DIDCommService( - id='endpoint-1', - service_endpoint=ked['a'][1]['se'], + id="endpoint-1", + service_endpoint=ked["a"][1]["se"], routing_keys=[], - accept=["didcomm/v2"] + accept=["didcomm/v2"], ) - ] - ) \ No newline at end of file + ], + ) diff --git a/tests/conftest.py b/tests/conftest.py index feec611..1f66643 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ https://docs.pytest.org/en/latest/pythonpath.html """ + import os import shutil import multicommand @@ -114,7 +115,7 @@ def seedWitEnds(db, witHabs, protocols=None): msgs.extend( hab.makeLocScheme(url=url, scheme=scheme, stamp=help.nowIso8601()) ) - psr.parse(ims=msgs) + psr.parse(ims=msgs, local=True) @staticmethod def seedWatcherEnds(db, protocols=None): @@ -465,7 +466,7 @@ def seedSchema(db): "additionalProperties": False, "required": ["d", "dt", "ids"], } - + _, sad = coring.Saider.saidify(sad, label=coring.Saids.dollar) schemer = scheming.Schemer(sed=sad) db.schema.pin(schemer.said, schemer) diff --git a/tests/dkr/app/cli/commands/did/webs/test_resolve.py b/tests/dkr/app/cli/commands/did/webs/test_resolve.py index d43ca36..179418d 100644 --- a/tests/dkr/app/cli/commands/did/webs/test_resolve.py +++ b/tests/dkr/app/cli/commands/did/webs/test_resolve.py @@ -16,15 +16,15 @@ import queue import threading import time - + + class PingResource: - def on_get(self, req, resp): - """Handles GET requests""" - resp.status = falcon.HTTP_200 - resp.content_type = falcon.MEDIA_TEXT - resp.text = ( - 'Pong' - ) + def on_get(self, req, resp): + """Handles GET requests""" + resp.status = falcon.HTTP_200 + resp.content_type = falcon.MEDIA_TEXT + resp.text = "Pong" + # @pytest.mark.timeout(60) # def test_resolver(): @@ -78,7 +78,7 @@ def on_get(self, req, resp): # ptres = queue.Queue() # pt = threading.Thread(target=resolving.loadUrl, args=(purl,ptres)) # pt.start() - + # ddstat = None # ddtres = queue.Queue() # ddt = threading.Thread(target=resolving.loadUrl, args=(ddurl,ddtres)) @@ -86,12 +86,12 @@ def on_get(self, req, resp): # time.sleep(1) # doist.recur() - + # kcstat = None # kctres = queue.Queue() # kct = threading.Thread(target=resolving.loadUrl, args=(kcurl,kctres)) # kct.start() - + # time.sleep(2) # doist.recur() @@ -99,12 +99,12 @@ def on_get(self, req, resp): # pstat = resp.status_code # assert pstat == 200 # print("Got example response content", resp.content) - + # resp = ddtres.get() # ddstat = resp.status_code # assert ddstat == 200 # print("Got dd response content", resp.content) - + # resp = kctres.get() # kcstat = resp.status_code # assert kcstat == 200 @@ -122,28 +122,28 @@ def on_get(self, req, resp): # time.sleep(2) # doist.recur() - + # mid_dd = rtres.get() # print("\nGot resolve dd response",mid_dd) # time.sleep(2) # doist.recur() - + # mid_kc = rtres.get() # print("\nGot resolve kc response",mid_kc) # time.sleep(2) # doist.recur() - + # raid = rtres.get() # print("\nGot resolve aid response",raid) # assert raid == aid - + # did_web_dd = resolving.loadJsonFile(f"./volume/dkr/pages/{aid}/did.json") # rdd = rtres.get() # print("\nGot resolve dd response",rdd) # assert json.loads(rdd.content) == did_web_dd - + # rkc_expected = resolving.loadFile(f"./volume/dkr/pages/{aid}/keri.cesr") # rkc_expected, sig_exp = resolving.splitCesr(rkc_expected.decode(), '}') # rkc_exp_json = json.loads(rkc_expected) @@ -153,15 +153,15 @@ def on_get(self, req, resp): # # double the json.loads calls to compensate for the quote escaping? # json_no_sig = json.loads(str_no_sig) # assert json_no_sig == rkc_exp_json - + # if not rtres.empty(): # assert False, "Expected no more responses" - + # assert aid not in vhby.kevers # resolving.saveCesr(hby=vhby,kc_res=rkc, aid=aid) # assert aid in vhby.kevers -# dd, dd_actual = resolving.getComp(hby=vhby, did=did_webs, aid=aid, dd_res=rdd, kc_res=rkc) +# dd, dd_actual = resolving.getComp(hby=vhby, did=did_webs, aid=aid, dd_res=rdd, kc_res=rkc) # assert dd[didding.DD_FIELD][didding.VMETH_FIELD] != did_web_dd[didding.VMETH_FIELD] # assert dd[didding.DD_FIELD][didding.VMETH_FIELD] == dd_actual[didding.VMETH_FIELD] @@ -179,7 +179,7 @@ def on_get(self, req, resp): # dd_actual_bad[didding.VMETH_FIELD][0]["id"] = dd_actual_bad[didding.VMETH_FIELD][0]["id"][:-1] # vresult = resolving.verify(dd, dd_actual_bad, meta=True) # assert vresult[didding.DID_RES_META_FIELD]['error'] == 'notVerified' - + # # TODO test services, alsoKnownAs, etc. # # TODO test a resolution failure @@ -190,12 +190,13 @@ def on_get(self, req, resp): # doist.exit() # """Done Test""" - + + class HandleCORS(object): def process_request(self, req, resp): - resp.set_header('Access-Control-Allow-Origin', '*') - resp.set_header('Access-Control-Allow-Methods', '*') - resp.set_header('Access-Control-Allow-Headers', '*') - resp.set_header('Access-Control-Max-Age', 1728000) # 20 days - if req.method == 'OPTIONS': - raise http_status.HTTPStatus(falcon.HTTP_200, text='\n') \ No newline at end of file + resp.set_header("Access-Control-Allow-Origin", "*") + resp.set_header("Access-Control-Allow-Methods", "*") + resp.set_header("Access-Control-Allow-Headers", "*") + resp.set_header("Access-Control-Max-Age", 1728000) # 20 days + if req.method == "OPTIONS": + raise http_status.HTTPStatus(falcon.HTTP_200, text="\n") diff --git a/tests/dkr/core/common.py b/tests/dkr/core/common.py index 3e4b4fa..1699b34 100644 --- a/tests/dkr/core/common.py +++ b/tests/dkr/core/common.py @@ -6,7 +6,7 @@ from hio.core import http from keri.app import habbing, grouping, signing -from keri.core import coring, eventing, parsing, scheming +from keri.core import coring, eventing, parsing, scheming, signing from keri.db import basing from keri.end import ending from keri.help import helping @@ -15,20 +15,26 @@ from keri.vdr import credentialing, verifying from keri.vdr.credentialing import Credentialer, proving + @pytest.fixture def setup_habs(): with habbing.openHby(name="test", temp=True) as hby, habbing.openHby( - name="wes", salt=coring.Salter(raw=b"wess-the-witness").qb64, temp=True + name="wes", salt=signing.Salter(raw=b"wess-the-witness").qb64, temp=True ) as wesHby, habbing.openHby( - name="wis", salt=coring.Salter(raw=b"wiss-the-witness").qb64, temp=True - ) as wisHby, habbing.openHab(name="agent", temp=True) as (agentHby, agentHab): + name="wis", salt=signing.Salter(raw=b"wiss-the-witness").qb64, temp=True + ) as wisHby, habbing.openHab( + name="agent", temp=True + ) as ( + agentHby, + agentHab, + ): print() wesHab = wesHby.makeHab(name="wes", isith="1", icount=1, transferable=False) assert not wesHab.kever.prefixer.transferable # create non-local kevery for Wes to process nonlocal msgs wesKvy = eventing.Kevery(db=wesHab.db, lax=False, local=False) - + wisHab = wisHby.makeHab(name="wis", isith="1", icount=1, transferable=False) assert not wisHab.kever.prefixer.transferable # create non-local kevery for Wes to process nonlocal msgs @@ -50,7 +56,7 @@ def setup_habs(): kvy = eventing.Kevery(db=hab.db, lax=False, local=False) icpMsg = hab.makeOwnInception() rctMsgs = [] # list of receipts from each witness - parsing.Parser().parse(ims=bytearray(icpMsg), kvy=wesKvy) + parsing.Parser().parse(ims=bytearray(icpMsg), kvy=wesKvy, local=True) # assert wesKvy.kevers[hab.pre].sn == 0 # accepted event # assert len(wesKvy.cues) == 2 # queued receipt cue rctMsg = wesHab.processCues(wesKvy.cues) # process cue returns rct msg @@ -58,23 +64,23 @@ def setup_habs(): rctMsgs.append(rctMsg) for msg in rctMsgs: # process rct msgs from all witnesses - parsing.Parser().parse(ims=bytearray(msg), kvy=kvy) + parsing.Parser().parse(ims=bytearray(msg), kvy=kvy, local=True) assert wesHab.pre in kvy.kevers - - rctMsgs = [] - parsing.Parser().parse(ims=bytearray(icpMsg), kvy=wisKvy) + + rctMsgs = [] + parsing.Parser().parse(ims=bytearray(icpMsg), kvy=wisKvy, local=True) assert wisKvy.kevers[hab.pre].sn == 0 # accepted event - assert len(wisKvy.cues) == 2 # queued receipt cue + assert len(wisKvy.cues) == 1 # queued receipt cue rctMsg = wisHab.processCues(wisKvy.cues) # process cue returns rct msg assert len(rctMsg) == 626 rctMsgs.append(rctMsg) for msg in rctMsgs: # process rct msgs from all witnesses - parsing.Parser().parse(ims=bytearray(msg), kvy=kvy) + parsing.Parser().parse(ims=bytearray(msg), kvy=kvy, local=True) assert wisHab.pre in kvy.kevers agentIcpMsg = agentHab.makeOwnInception() - parsing.Parser().parse(ims=bytearray(agentIcpMsg), kvy=kvy) + parsing.Parser().parse(ims=bytearray(agentIcpMsg), kvy=kvy, local=True) assert agentHab.pre in kvy.kevers msgs = bytearray() @@ -91,7 +97,7 @@ def setup_habs(): stamp=helping.nowIso8601(), ) ) - wesHab.psr.parse(ims=bytearray(msgs)) + wesHab.psr.parse(ims=bytearray(msgs), local=True) msgs.extend( wisHab.makeEndRole( @@ -114,8 +120,8 @@ def setup_habs(): stamp=helping.nowIso8601(), ) ) - - wisHab.psr.parse(ims=bytearray(msgs)) + + wisHab.psr.parse(ims=bytearray(msgs), local=True) # Set up msgs.extend( @@ -131,7 +137,7 @@ def setup_habs(): stamp=helping.nowIso8601(), ) ) - hab.psr.parse(ims=msgs) + hab.psr.parse(ims=msgs, local=True) msgs = bytearray() msgs.extend( @@ -152,7 +158,9 @@ def setup_habs(): msgs.extend( hab.makeEndRole( - eid=agentHab.pre, role=kering.Roles.registrar, stamp=helping.nowIso8601() + eid=agentHab.pre, + role=kering.Roles.registrar, + stamp=helping.nowIso8601(), ) ) @@ -162,16 +170,22 @@ def setup_habs(): ) ) - agentHab.psr.parse(ims=bytearray(msgs)) - hab.psr.parse(ims=bytearray(msgs)) + agentHab.psr.parse(ims=bytearray(msgs), local=True) + hab.psr.parse(ims=bytearray(msgs), local=True) rurls = hab.fetchRoleUrls(hab.pre) ctlr = rurls.get("controller") ctlr1 = ctlr.get(hab.pre) ctlrHttp = ctlr1.get("http") assert ctlrHttp == "http://127.0.0.1:7777" - assert rurls.get("registrar").get("EBErgFZoM3PBQNTpTuK9bax_U8HLJq1Re2RM1cdifaTJ").get("http") == "http://127.0.0.1:6666" - assert rurls.get("mailbox").get("EBErgFZoM3PBQNTpTuK9bax_U8HLJq1Re2RM1cdifaTJ").get("http") == "http://127.0.0.1:6666" + reg = rurls.get("registrar") + reg1 = reg.get(agentHab.pre) + reg1Http = reg1.get("http") + assert reg1Http == "http://127.0.0.1:6666" + assert ( + rurls.get("mailbox").get(agentHab.pre).get("http") + == "http://127.0.0.1:6666" + ) wurls = hab.fetchWitnessUrls(hab.pre) wwits = wurls.getall("witness") wwit1 = wwits[0].get("BN8t3n1lxcV0SWGJIIF46fpSUqA7Mqre5KJNN3nbx3mr") @@ -179,8 +193,9 @@ def setup_habs(): wwit2 = wwits[1] wse2 = wwit2.get("BAjTuhnzPDB0oU0qHXACnvzachJpYjUAtH1N9Tsb_MdE") assert wse2.get("http") == "http://127.0.0.1:9999" - - yield hby, hab, wesHby, wesHab + + yield hby, hab, wesHby, wesHab, agentHab + def da_cred(): """ @@ -322,8 +337,12 @@ def setup_cred(hab, registry, verifier: verifying.Verifier, seqner): missing = False try: # Specify an anchor directly in the KEL - verifier.processCredential(creder=creder, prefixer=prefixer, seqner=seqner, - saider=coring.Saider(qb64=hab.kever.serder.said)) + verifier.processCredential( + creder=creder, + prefixer=prefixer, + seqner=seqner, + saider=coring.Saider(qb64=hab.kever.serder.said), + ) except kering.MissingRegistryError: missing = True @@ -343,13 +362,13 @@ def issue_cred(hab, regery, registry, creder): hab.interact(data=[rseal]) seqner = coring.Seqner(sn=hab.kever.sn) saider = coring.Saider(qb64=hab.kever.serder.said) - registry.anchorMsg( - pre=iss.pre, regd=iss.said, seqner=seqner, saider=saider - ) + registry.anchorMsg(pre=iss.pre, regd=iss.said, seqner=seqner, saider=saider) regery.processEscrows() state = registry.tever.vcState(vci=creder.said) if state is None or state.et not in (coring.Ilks.iss): - raise kering.ValidationError(f"credential {creder.said} not is correct state for issuance") + raise kering.ValidationError( + f"credential {creder.said} not is correct state for issuance" + ) def revoke_cred(hab, regery, registry: credentialing.Registry, creder): @@ -358,18 +377,17 @@ def revoke_cred(hab, regery, registry: credentialing.Registry, creder): hab.interact(data=[rseal]) seqner = coring.Seqner(sn=hab.kever.sn) saider = coring.Saider(qb64=hab.kever.serder.said) - registry.anchorMsg( - pre=rev.pre, regd=rev.said, seqner=seqner, saider=saider - ) + registry.anchorMsg(pre=rev.pre, regd=rev.said, seqner=seqner, saider=saider) regery.processEscrows() state = registry.tever.vcState(vci=creder["sad"]["d"]) if state is None or state.et not in (coring.Ilks.rev): - raise kering.ValidationError(f"credential {creder.said} not is correct state for revocation") + raise kering.ValidationError( + f"credential {creder.said} not is correct state for revocation" + ) def issue_desig_aliases(seeder, hby, hab, whby, whab, registryName="cam"): seeder.seedSchema(db=hby.db) - assert hab.pre == "ECCoHcHP1jTAW8Dr44rI2kWzfF71_U0sZwvV-J_q4YE7" # kli vc registry incept --name "$alias" --alias "$alias" --registry-name "$reg_name" regery, registry, reg_anc = setup_rgy(hby, hab, registryName) @@ -386,4 +404,4 @@ def issue_desig_aliases(seeder, hby, hab, whby, whab, registryName="cam"): scads = regery.reger.schms.get(keys=didding.DES_ALIASES_SCHEMA) assert len(scads) == 1 - return Credentialer(hby, regery, None, verifier) \ No newline at end of file + return Credentialer(hby, regery, None, verifier) diff --git a/tests/dkr/core/test_didding.py b/tests/dkr/core/test_didding.py index 7fc3ee1..11d2901 100644 --- a/tests/dkr/core/test_didding.py +++ b/tests/dkr/core/test_didding.py @@ -23,11 +23,10 @@ from keri.vdr.credentialing import Credentialer, proving import sys + sys.path.append(os.path.join(os.path.dirname(__file__))) from common import issue_desig_aliases, revoke_cred, setup_habs -wdid = "did:webs:127.0.0.1:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" -did = "did:webs:127.0.0.1:ECCoHcHP1jTAW8Dr44rI2kWzfF71_U0sZwvV-J_q4YE7" def test_parse_keri_did(): # Valid did:keri DID @@ -98,6 +97,7 @@ def test_parse_webs_did(): assert "my:path" == path assert aid, "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" + def test_parse_web_did(): with pytest.raises(ValueError): did = "did:web:127.0.0.1:1234567" @@ -111,9 +111,7 @@ def test_parse_web_did(): assert aid == "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" # port url should be url encoded with %3a according to the spec - did_port_bad = ( - "did:web:127.0.0.1:7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" - ) + did_port_bad = "did:web:127.0.0.1:7676:BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" domain, port, path, aid = didding.parseDIDWebs(did_port_bad) assert "127.0.0.1" == domain assert None == port @@ -154,27 +152,17 @@ def test_parse_web_did(): assert "my:path" == path assert aid, "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" + def test_gen_did_doc(setup_habs): - hby, hab, wesHby, wesHab = setup_habs + hby, hab, wesHby, wesHab, agentHab = setup_habs + did = f"did:webs:127.0.0.1:{hab.pre}" didDoc = didding.generateDIDDoc(hby, did, hab.pre, oobi=None, meta=False) - assert ( - didDoc["id"] - == f"{did}" - ) + assert didDoc["id"] == f"{did}" - assert didDoc[didding.VMETH_FIELD] == [ - { - "id": "#DCQbRBx58zbRPs8R9cXl-MMbPaxH1EPHdWp3ICSdQSyp", - "type": "JsonWebKey", - "controller": f"{did}", - "publicKeyJwk": { - "kid": "DCQbRBx58zbRPs8R9cXl-MMbPaxH1EPHdWp3ICSdQSyp", - "kty": "OKP", - "crv": "Ed25519", - "x": "JBtEHHnzNtE-zxH1xeX4wxs9rEfUQ8d1ancgJJ1BLKk", - }, - } - ] + vmeth = didDoc[didding.VMETH_FIELD][0] + assert vmeth["controller"] == did + assert vmeth["type"] == "JsonWebKey" + assert vmeth["publicKeyJwk"]["crv"] == "Ed25519" assert len(didDoc["service"]) == 6 assert didDoc["service"][0] == { @@ -183,12 +171,12 @@ def test_gen_did_doc(setup_habs): "serviceEndpoint": {"http": "http://127.0.0.1:7777"}, } assert didDoc["service"][1] == { - "id": "#EBErgFZoM3PBQNTpTuK9bax_U8HLJq1Re2RM1cdifaTJ/mailbox", + "id": f"#{agentHab.pre}/mailbox", "type": "mailbox", "serviceEndpoint": {"http": "http://127.0.0.1:6666"}, } assert didDoc["service"][2] == { - "id": "#EBErgFZoM3PBQNTpTuK9bax_U8HLJq1Re2RM1cdifaTJ/registrar", + "id": f"#{agentHab.pre}/registrar", "type": "registrar", "serviceEndpoint": {"http": "http://127.0.0.1:6666"}, } @@ -200,31 +188,23 @@ def test_gen_did_doc(setup_habs): assert didDoc["service"][4] == { "id": "#BAjTuhnzPDB0oU0qHXACnvzachJpYjUAtH1N9Tsb_MdE/witness", "type": "witness", - "serviceEndpoint": {"http": "http://127.0.0.1:9999", "tcp": "tcp://127.0.0.1:9991"}, + "serviceEndpoint": { + "http": "http://127.0.0.1:9999", + "tcp": "tcp://127.0.0.1:9991", + }, } def test_gen_did_doc_with_meta(setup_habs): - hby, hab, wesHby, wesHab = setup_habs + hby, hab, wesHby, wesHab, agentHab = setup_habs + did = f"did:webs:127.0.0.1:{hab.pre}" didDoc = didding.generateDIDDoc(hby, did, hab.pre, oobi=None, meta=True) - assert ( - didDoc[didding.DD_FIELD]["id"] - == f"{did}" - ) + assert didDoc[didding.DD_FIELD]["id"] == f"{did}" - assert didDoc[didding.DD_FIELD][didding.VMETH_FIELD] == [ - { - "id": "#DCQbRBx58zbRPs8R9cXl-MMbPaxH1EPHdWp3ICSdQSyp", - "type": "JsonWebKey", - "controller": f"{did}", - "publicKeyJwk": { - "kid": "DCQbRBx58zbRPs8R9cXl-MMbPaxH1EPHdWp3ICSdQSyp", - "kty": "OKP", - "crv": "Ed25519", - "x": "JBtEHHnzNtE-zxH1xeX4wxs9rEfUQ8d1ancgJJ1BLKk", - }, - } - ] + vmeth = didDoc[didding.DD_FIELD][didding.VMETH_FIELD][0] + assert vmeth["controller"] == did + assert vmeth["type"] == "JsonWebKey" + assert vmeth["publicKeyJwk"]["crv"] == "Ed25519" assert len(didDoc[didding.DD_FIELD]["service"]) == 6 assert didDoc[didding.DD_FIELD]["service"][0] == { @@ -233,12 +213,12 @@ def test_gen_did_doc_with_meta(setup_habs): "serviceEndpoint": {"http": "http://127.0.0.1:7777"}, } assert didDoc[didding.DD_FIELD]["service"][1] == { - "id": "#EBErgFZoM3PBQNTpTuK9bax_U8HLJq1Re2RM1cdifaTJ/mailbox", + "id": f"#{agentHab.pre}/mailbox", "type": "mailbox", "serviceEndpoint": {"http": "http://127.0.0.1:6666"}, } assert didDoc[didding.DD_FIELD]["service"][2] == { - "id": "#EBErgFZoM3PBQNTpTuK9bax_U8HLJq1Re2RM1cdifaTJ/registrar", + "id": f"#{agentHab.pre}/registrar", "type": "registrar", "serviceEndpoint": {"http": "http://127.0.0.1:6666"}, } @@ -250,16 +230,22 @@ def test_gen_did_doc_with_meta(setup_habs): assert didDoc[didding.DD_FIELD]["service"][4] == { "id": "#BAjTuhnzPDB0oU0qHXACnvzachJpYjUAtH1N9Tsb_MdE/witness", "type": "witness", - "serviceEndpoint": {"http": "http://127.0.0.1:9999", "tcp": "tcp://127.0.0.1:9991"}, + "serviceEndpoint": { + "http": "http://127.0.0.1:9999", + "tcp": "tcp://127.0.0.1:9991", + }, } assert ( - re.match(didding.DID_TIME_PATTERN, didDoc[didding.DID_RES_META_FIELD]["retrieved"]) + re.match( + didding.DID_TIME_PATTERN, didDoc[didding.DID_RES_META_FIELD]["retrieved"] + ) != None ) + def test_gen_did_doc_no_hab(setup_habs): - hby, hab, wesHby, wesHab = setup_habs + hby, hab, wesHby, wesHab, agentHab = setup_habs aid = "ENro7uf0ePmiK3jdTo2YCdXLqW7z7xoP6qhhBou6gBLe" did = f"did:web:did-webs-service%3a7676:{aid}" @@ -267,65 +253,58 @@ def test_gen_did_doc_no_hab(setup_habs): didDoc = didding.generateDIDDoc(hby, did, aid, oobi=None, meta=False) except KeyError as e: assert str(e) == f"'{aid}'" - + msgs = resolving.loadFile(f"./volume/dkr/pages/{aid}/keri.cesr") - hby.psr.parse(ims=msgs) - + hby.psr.parse(ims=msgs, local=True) + didDoc = didding.generateDIDDoc(hby, did, aid, oobi=None, meta=False) - + expected = resolving.loadJsonFile(f"./volume/dkr/pages/{aid}/did.json") - - assert (didDoc["id"] == expected["id"]) - assert (didDoc["id"].startswith("did:web:")) - assert (didDoc["id"].endswith(f"{aid}")) + + assert didDoc["id"] == expected["id"] + assert didDoc["id"].startswith("did:web:") + assert didDoc["id"].endswith(f"{aid}") assert didDoc[didding.VMETH_FIELD] == expected[didding.VMETH_FIELD] assert len(didDoc["service"]) == 0 + def test_gen_desig_aliases(setup_habs, seeder): - hby, hab, wesHby, wesHab = setup_habs + hby, hab, wesHby, wesHab, agentHab = setup_habs crdntler = issue_desig_aliases( seeder, hby, hab, whby=wesHby, whab=wesHab, registryName="dAliases" ) + did = f"did:webs:127.0.0.1:{hab.pre}" didDoc = didding.generateDIDDoc( hby, did, hab.pre, oobi=None, meta=True, reg_name=crdntler.rgy.name ) - assert ( - didDoc[didding.DD_FIELD]["id"] - == f"{did}" - ) + assert didDoc[didding.DD_FIELD]["id"] == f"{did}" - assert didDoc[didding.DD_FIELD][didding.VMETH_FIELD] == [ - { - "id": "#DCQbRBx58zbRPs8R9cXl-MMbPaxH1EPHdWp3ICSdQSyp", - "type": "JsonWebKey", - "controller": f"{did}", - "publicKeyJwk": { - "kid": "DCQbRBx58zbRPs8R9cXl-MMbPaxH1EPHdWp3ICSdQSyp", - "kty": "OKP", - "crv": "Ed25519", - "x": "JBtEHHnzNtE-zxH1xeX4wxs9rEfUQ8d1ancgJJ1BLKk", - }, - } - ] + vmeth = didDoc[didding.DD_FIELD][didding.VMETH_FIELD][0] + assert vmeth["controller"] == did + assert vmeth["type"] == "JsonWebKey" + assert vmeth["publicKeyJwk"]["crv"] == "Ed25519" assert didDoc[didding.DD_META_FIELD]["equivalentId"] == [ "did:webs:foo.com:ENro7uf0ePmiK3jdTo2YCdXLqW7z7xoP6qhhBou6gBLe" ] assert didDoc[didding.DD_FIELD]["alsoKnownAs"] == [ "did:webs:foo.com:ENro7uf0ePmiK3jdTo2YCdXLqW7z7xoP6qhhBou6gBLe", - "did:web:example.com:ENro7uf0ePmiK3jdTo2YCdXLqW7z7xoP6qhhBou6gBLe" + "did:web:example.com:ENro7uf0ePmiK3jdTo2YCdXLqW7z7xoP6qhhBou6gBLe", ] assert ( - re.match(didding.DID_TIME_PATTERN, didDoc[didding.DID_RES_META_FIELD]["retrieved"]) + re.match( + didding.DID_TIME_PATTERN, didDoc[didding.DID_RES_META_FIELD]["retrieved"] + ) != None ) + def test_gen_desig_aliases_revoked(setup_habs, seeder): - hby, hab, wesHby, wesHab = setup_habs + hby, hab, wesHby, wesHab, agentHab = setup_habs crdntler = issue_desig_aliases( seeder, hby, hab, whby=wesHby, whab=wesHab, registryName="dAliases" @@ -334,17 +313,13 @@ def test_gen_desig_aliases_revoked(setup_habs, seeder): saiders = crdntler.rgy.reger.schms.get( keys=didding.DES_ALIASES_SCHEMA.encode("utf-8") ) - creds = crdntler.rgy.reger.cloneCreds(saiders,hab.db) + creds = crdntler.rgy.reger.cloneCreds(saiders, hab.db) revoke_cred(hab, crdntler.rgy, crdntler.rgy.registryByName("dAliases"), creds[0]) - didDoc = didding.generateDIDDoc( - hby, did, hab.pre, oobi=None, meta=True - ) - assert ( - didDoc[didding.DD_FIELD]["id"] - == f"{did}" - ) + did = f"did:webs:127.0.0.1:{hab.pre}" + didDoc = didding.generateDIDDoc(hby, did, hab.pre, oobi=None, meta=True) + assert didDoc[didding.DD_FIELD]["id"] == f"{did}" assert didDoc[didding.DD_FIELD][didding.VMETH_FIELD] == [ { @@ -364,6 +339,8 @@ def test_gen_desig_aliases_revoked(setup_habs, seeder): assert didDoc[didding.DD_FIELD]["alsoKnownAs"] == [] assert ( - re.match(didding.DID_TIME_PATTERN, didDoc[didding.DID_RES_META_FIELD]["retrieved"]) + re.match( + didding.DID_TIME_PATTERN, didDoc[didding.DID_RES_META_FIELD]["retrieved"] + ) != None ) diff --git a/tests/dkr/core/test_webbing.py b/tests/dkr/core/test_webbing.py index 8f6ee91..042d326 100644 --- a/tests/dkr/core/test_webbing.py +++ b/tests/dkr/core/test_webbing.py @@ -1,6 +1,7 @@ import json import os import sys + sys.path.append(os.path.join(os.path.dirname(__file__))) from common import setup_habs from dkr.core import didding, resolving, webbing @@ -18,25 +19,25 @@ import queue import threading import time - + + class PingResource: - def on_get(self, req, resp): - """Handles GET requests""" - resp.status = falcon.HTTP_200 - resp.content_type = falcon.MEDIA_TEXT - resp.text = ( - 'Pong' - ) - + def on_get(self, req, resp): + """Handles GET requests""" + resp.status = falcon.HTTP_200 + resp.content_type = falcon.MEDIA_TEXT + resp.text = "Pong" + + # @pytest.mark.timeout(60) # def test_service(setup_habs): # port = 7676 - + # with habbing.openHby(name="service") as shby: # hab = shby.makeHab(name="service") # aid = "ELCUOZXs-0xn3jOihm0AJ-L8XTFVT8SnIpmEDhFF9Kz_" # did = f"did:web:127.0.0.1%3a{port}:{aid}" - + # print("Current working dir", os.getcwd()) # cf = configing.Configer(name="config-test", # headDirPath="./volume/dkr/examples/my-scripts", @@ -79,17 +80,17 @@ def on_get(self, req, resp): # ptres = queue.Queue() # pt = threading.Thread(target=resolving.loadUrl, args=(purl,ptres)) # pt.start() - + # ddstat = None # ddtres = queue.Queue() # ddt = threading.Thread(target=resolving.loadUrl, args=(ddurl,ddtres)) # ddt.start() - + # kcstat = None # kctres = queue.Queue() # kct = threading.Thread(target=resolving.loadUrl, args=(kcurl,kctres)) # kct.start() - + # while pstat == None or ddtres == None or kctres == None: # time.sleep(2) # doist.recur() @@ -98,17 +99,17 @@ def on_get(self, req, resp): # pstat = resp.status_code # assert pstat == 200 # print("Got ping response content", resp.content) - + # resp = ddtres.get() # ddstat = resp.status_code # assert ddstat == 200 # print("Got dd response content", resp.content) - + # resp = kctres.get() # kcstat = resp.status_code # assert kcstat == 200 # print("Got kc response content", resp.content) - + # ohby, ohab, wesHby, wesHab = setup_habs # odid = f"did:web:127.0.0.1%3a{port}:{ohab.pre}" # didDoc = didding.generateDIDDoc(ohby, odid, ohab.pre, oobi=None, metadata=False) @@ -122,32 +123,32 @@ def on_get(self, req, resp): # print(f"Writing test did:webs for {webbing.DID_JSON} to file {apath}") # fpath = os.path.join(apath, webbing.DID_JSON) # json.dump(didDoc, open(f"{fpath}", "w")) - + # ddnew = queue.Queue() # ddnurl = f'http://127.0.0.1:{port}/{ohab.pre}/did.json' # ddnt = threading.Thread(target=resolving.loadUrl, args=(ddnurl,ddnew)) # ddnt.start() - + # while ddnew == None: # time.sleep(2) # doist.recur() - + # resp = ddtres.get() # ddstat = resp.status_code # assert ddstat == 200 # print("Got dd new response content", resp.content) - + # doist.exit() - # """Done Test""" - + + class HandleCORS(object): def process_request(self, req, resp): - resp.set_header('Access-Control-Allow-Origin', '*') - resp.set_header('Access-Control-Allow-Methods', '*') - resp.set_header('Access-Control-Allow-Headers', '*') - resp.set_header('Access-Control-Max-Age', 1728000) # 20 days - if req.method == 'OPTIONS': - raise http_status.HTTPStatus(falcon.HTTP_200, text='\n') \ No newline at end of file + resp.set_header("Access-Control-Allow-Origin", "*") + resp.set_header("Access-Control-Allow-Methods", "*") + resp.set_header("Access-Control-Allow-Headers", "*") + resp.set_header("Access-Control-Max-Age", 1728000) # 20 days + if req.method == "OPTIONS": + raise http_status.HTTPStatus(falcon.HTTP_200, text="\n")