Skip to content

Commit

Permalink
Merge pull request #29 from 2byrds/feat/desig_aliases_equivid_aka
Browse files Browse the repository at this point in the history
Feat/desig aliases equivid aka
  • Loading branch information
2byrds authored Dec 14, 2023
2 parents 33a7bc2 + 121660e commit e81f14a
Show file tree
Hide file tree
Showing 5 changed files with 1,424 additions and 231 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
'cbor2>=5.4.3',
'multidict>=6.0.2',
'ordered-set>=4.1.0',
'keri @ git+https://[email protected]/WebOfTrust/keripy.git',
'keri @ git+https://[email protected]/WebOfTrust/keripy.git@main',
'hio>=0.6.9',
'multicommand>=1.0.0',
'jsonschema>=4.17.0',
Expand Down
82 changes: 66 additions & 16 deletions src/dkr/app/cli/commands/did/webs/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@

from hio.base import doing
from keri.core import coring, eventing
from keri.app import habbing, oobiing
from keri.app import directing, habbing, oobiing
from keri.app.cli.common import existing
from keri.app.cli.commands.vc import export
from keri.vc import proving
from keri.vdr import credentialing, viring
from keri.db import basing, dbing
from keri.help import helping

Expand All @@ -30,22 +33,28 @@
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.")

def handler(args):
gen = Generator(name=args.name, base=args.base, bran=args.bran, did=args.did, oobi=args.oobi)
gen = Generator(name=args.name, base=args.base, bran=args.bran, did=args.did, oobi=args.oobi, da_reg=args.da_reg)
return [gen]


class Generator(doing.DoDoer):

def __init__(self, name, base, bran, did, oobi):

def __init__(self, name, base, bran, did, oobi, da_reg):
self.name = name
self.base = base
self.bran = bran
self.hby = existing.setupHby(name=name, base=base, bran=bran)
self.bran = bran
hbyDoer = habbing.HaberyDoer(habery=self.hby) # setup doer
obl = oobiing.Oobiery(hby=self.hby)
self.did = did
self.oobi = oobi
self.da_reg = da_reg

self.toRemove = [hbyDoer] + obl.doers
doers = list(self.toRemove) + [doing.doify(self.generate)]
Expand All @@ -57,15 +66,25 @@ def generate(self, tymth, tock=0.0, **opts):
_ = (yield self.tock)

domain, port, path, aid = didding.parseDIDWebs(self.did)
obr = basing.OobiRecord(date=helping.nowIso8601())
obr.cid = aid
self.hby.db.oobis.pin(keys=(self.oobi,), val=obr)

while self.hby.db.roobi.get(keys=(self.oobi,)) is None:
_ = yield tock

oobiHab = self.hby.habs[aid]
msgs = oobiHab.replyToOobi(aid=aid, role="controller", eids=None)
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())
obr.cid = aid
self.hby.db.oobis.pin(keys=(self.oobi,), val=obr)

while self.hby.db.roobi.get(keys=(self.oobi,)) is None:
_ = yield tock

oobiHab = self.hby.habs[aid]
msgs = oobiHab.replyToOobi(aid=aid, role="controller", eids=None)
else:
print(f"Generating CESR event stream from local hab")
#add KEL
self.genKelCesr(aid, msgs)
#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"{webbing.KC_DEFAULT_DIR}/{aid}"
Expand All @@ -78,7 +97,7 @@ def generate(self, tymth, tock=0.0, **opts):
kcf.write(msgs.decode("utf-8"))

#generate did doc
diddoc = didding.generateDIDDoc(self.hby, did=self.did, aid=aid, oobi=self.oobi)
diddoc = didding.generateDIDDoc(self.hby, did=self.did, aid=aid, oobi=self.oobi, reg_name=self.da_reg)

# Create the directory (and any intermediate directories in the given path) if it doesn't already exist
dd_dir_path = f"{webbing.DD_DEFAULT_DIR}/{aid}"
Expand Down Expand Up @@ -126,11 +145,42 @@ def generate(self, tymth, tock=0.0, **opts):
result = dict(
didDocument=diddoc,
pre=pre,
state=kever.state()._asdict(),
state=kever.state().ked,
kel=kel
)
didData = json.dumps(result, indent=2)

print(didData)
self.remove(self.toRemove)
return True

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: proving.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]]
for saider in saiders:

creder, *_ = rgy.reger.cloneCred(said=saider.qb64)

if creder.status is not None:
self.genTelCesr(rgy.reger, creder.status, msgs)
self.genTelCesr(rgy.reger, creder.said, msgs)
self.genAcdcCesr(aid, creder, msgs)
103 changes: 84 additions & 19 deletions src/dkr/core/didding.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@

from base64 import urlsafe_b64encode

from keri.help import helping

from keri import kering
from keri.app import oobiing, habbing
from keri.core import coring
from keri.app.cli.common import terming
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<aid>[^:]+)\Z', re.IGNORECASE)
DID_WEBS_RE = re.compile(r'\Adid:webs:(?P<domain>[^%:]+)(?:%3a(?P<port>\d+))?(?::(?P<path>.+?))?(?::(?P<aid>[^:]+))\Z', re.IGNORECASE)
DID_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
DID_TIME_PATTERN = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z")
DES_ALIASES_SCHEMA="EN6Oh5XSD5_q2Hgu-aqpdfbVepdpYpFlgz6zvJL5b_r5"

def parseDIDKeri(did):
match = DID_KERI_RE.match(did)
Expand Down Expand Up @@ -50,7 +53,9 @@ def parseDIDWebs(did):
return domain, port, path, aid


def generateDIDDoc(hby, did, aid, oobi=None, metadata=None):
def generateDIDDoc(hby: habbing.Habery, did, aid, oobi=None, metadata=None, reg_name=None):
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:
Expand Down Expand Up @@ -117,32 +122,39 @@ def generateDIDDoc(hby, did, aid, oobi=None, metadata=None):
))

sEnds=[]
if hasattr(hby, 'endsFor'):
ends = hby.endsFor(aid)
for role in ends:
eDict = ends[role]
for eid in eDict:
sDict = dict()
for proto in eDict[eid]:
sDict[proto]=f"{eDict[eid][proto]}"
sEnds.append(dict(
id=f"#{eid}/{role}",
type=role,
serviceEndpoint=sDict
))
# hab.fetchRoleUrls(hab.pre).get("controller").get("EGadHcyW9IfVIPrFUAa_I0z4dF8QzQAvUvfaUTJk8Jre").get("http") == "http://127.0.0.1:7777"
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 = []
da_ids = desAliases(hby, aid, reg_name=reg_name)
if da_ids:
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 if not s.startswith(dws_pre)]
print(f"Also Known As DIDs: {aka_ids}")

didResolutionMetadata = dict(
contentType="application/did+json",
retrieved=datetime.utcnow().strftime(DID_TIME_FORMAT)
)
didDocumentMetadata = dict(
witnesses=witnesses,
versionId=f"{kever.sner.num}"
versionId=f"{kever.sner.num}",
equivalentId=eq_ids,
)
diddoc = dict(
id=did,
verificationMethod=vms,
service=sEnds
service=sEnds,
alsoKnownAs=aka_ids
)

if metadata is True:
Expand All @@ -166,3 +178,56 @@ def fromDidWeb(diddoc):
for verificationMethod in diddoc['verificationMethod']:
verificationMethod['controller'] = verificationMethod['controller'].replace('did:web', 'did:webs')
return diddoc

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.
"""
if reg_name is 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
saiders = [saider for saider in saids if saider.qb64 in [saider.qb64 for saider in scads]]

da_ids = []
# for saider in saiders:
creds = rgy.reger.cloneCreds(saiders)

for idx, cred in enumerate(creds):
sad = cred['sad']
status = cred["status"]
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}")
else:
print(f" Status: Unknown")
print(f" Issued by {sad['i']}")
print(f" Issued on {status['dt']}")

return da_ids

def addEnds(ends):
sEnds=[]
for role in ends:
eDict = ends[role]
for eid in eDict:
sDict = dict()
for proto in eDict[eid]:
sDict[proto]=f"{eDict[eid][proto]}"
sEnds.append(dict(
id=f"#{eid}/{role}",
type=role,
serviceEndpoint=sDict
))
return sEnds
Loading

0 comments on commit e81f14a

Please sign in to comment.