Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many additions and fixes to kli commands, new ESSR payload attachment support #803

Merged
merged 5 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions images/keripy.base.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Builder layer
FROM python:3.12-alpine as builder

# Install compilation dependencies
RUN apk --no-cache add \
bash \
alpine-sdk \
libffi-dev \
libsodium \
libsodium-dev

SHELL ["/bin/bash", "-c"]

# Setup Rust for blake3 dependency build
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
13 changes: 6 additions & 7 deletions src/keri/app/agenting.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ def witDo(self, tymth=None, tock=0.0):
msg = self.msgs.popleft()
pre = msg["pre"]
sn = msg["sn"] if "sn" in msg else None
auths = msg["auths"] if "auths" in msg else None

yield from self.receipt(pre, sn)
yield from self.receipt(pre, sn, auths)
self.cues.push(msg)

yield self.tock
Expand Down Expand Up @@ -616,12 +617,10 @@ def sendDo(self, tymth=None, tock=0.0, **opts):

_ = (yield self.tock)

total = len(witers)
count = 0
while count < total:
for witer in witers:
count += len(witer.sent)
_ = (yield self.tock)
while witers:
witer = witers.pop()
while not witer.idle:
_ = (yield self.tock)

self.remove(witers)
self.cues.push(evt)
Expand Down
58 changes: 58 additions & 0 deletions src/keri/app/cli/commands/aid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# -*- encoding: utf-8 -*-
"""
KERI
keri.kli.commands module

"""
import argparse

from hio import help
from hio.base import doing

from keri.app.cli.common import existing
from keri.kering import ConfigurationError

logger = help.ogler.getLogger()

parser = argparse.ArgumentParser(description='Print the AID for a given alias')
parser.set_defaults(handler=lambda args: handler(args),
transferable=True)
parser.add_argument('--name', '-n', help='keystore name and file location of KERI keystore', required=True)
parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore',
required=False, default="")
parser.add_argument('--alias', '-a', help='human readable alias for the new identifier prefix', default=None,
required=True)
parser.add_argument('--passcode', '-p', help='21 character encryption passcode for keystore (is not saved)',
dest="bran", default=None) # passcode => bran


def handler(args):
kwa = dict(args=args)
return [doing.doify(status, **kwa)]


def status(tymth, tock=0.0, **opts):
""" Command line status handler

"""
_ = (yield tock)
args = opts["args"]
name = args.name
alias = args.alias
base = args.base
bran = args.bran

try:
with existing.existingHby(name=name, base=base, bran=bran) as hby:
if alias is None:
alias = existing.aliasInput(hby)

hab = hby.habByName(alias)
if hab is None:
print(f"{alias} is not a valid alias for an identifier")

print(hab.pre)

except ConfigurationError as e:
print(f"identifier prefix for {name} does not exist, incept must be run first", )
return -1
28 changes: 25 additions & 3 deletions src/keri/app/cli/commands/delegate/confirm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from keri import core
from keri.core import coring, serdering
from keri.db import dbing
from keri.help import helping
from keri.peer import exchanging

logger = help.ogler.getLogger()
Expand All @@ -32,6 +33,10 @@
parser.add_argument("--interact", "-i", help="anchor the delegation approval in an interaction event. "
"Default is to use a rotation event.", action="store_true")
parser.add_argument("--auto", "-Y", help="auto approve any delegation request non-interactively", action="store_true")
parser.add_argument("--authenticate", '-z', help="Prompt the controller for authentication codes for each witness",
action='store_true')
parser.add_argument('--code', help='<Witness AID>:<code> formatted witness auth codes. Can appear multiple times',
default=[], action="append", required=False)


def confirm(args):
Expand All @@ -47,22 +52,27 @@ def confirm(args):
alias = args.alias
interact = args.interact
auto = args.auto
authenticate = args.authenticate
codes = args.code

confirmDoer = ConfirmDoer(name=name, base=base, alias=alias, bran=bran, interact=interact, auto=auto)
confirmDoer = ConfirmDoer(name=name, base=base, alias=alias, bran=bran, interact=interact, auto=auto,
authenticate=authenticate, codes=codes)

doers = [confirmDoer]
return doers


class ConfirmDoer(doing.DoDoer):
def __init__(self, name, base, alias, bran, interact=False, auto=False):
def __init__(self, name, base, alias, bran, interact=False, auto=False, authenticate=False, codes=None):
hby = existing.setupHby(name=name, base=base, bran=bran)
self.hbyDoer = habbing.HaberyDoer(habery=hby) # setup doer
self.witq = agenting.WitnessInquisitor(hby=hby)
self.postman = forwarding.Poster(hby=hby)
self.counselor = grouping.Counselor(hby=hby)
self.notifier = notifying.Notifier(hby=hby)
self.mux = grouping.Multiplexor(hby=hby, notifier=self.notifier)
self.authenticate = authenticate
self.codes = codes if codes is not None else []

exc = exchanging.Exchanger(hby=hby, handlers=[])
delegating.loadHandlers(hby=hby, exc=exc, notifier=self.notifier)
Expand Down Expand Up @@ -173,7 +183,19 @@ def confirmDo(self, tymth, tock=0.0):
else:
hab.rotate(data=[anchor])

witDoer = agenting.WitnessReceiptor(hby=self.hby)
auths = {}
if self.authenticate:
for arg in self.codes:
(wit, code) = arg.split(":")
auths[wit] = f"{code}#{helping.nowIso8601()}"

for wit in hab.kever.wits:
if wit in auths:
continue
code = input(f"Entire code for {wit}: ")
auths[wit] = f"{code}#{helping.nowIso8601()}"

witDoer = agenting.WitnessReceiptor(hby=self.hby, auths=auths)
self.extend(doers=[witDoer])
self.toRemove.append(witDoer)
yield self.tock
Expand Down
2 changes: 2 additions & 0 deletions src/keri/app/cli/commands/incept.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ def mergeArgsWithFile(args):
incept_opts.estOnly = args.est_only
if args.data is not None:
incept_opts.data = config.parseData(args.data)
if args.delpre is not None:
incept_opts.delpre = args.delpre

return incept_opts

Expand Down
135 changes: 135 additions & 0 deletions src/keri/app/cli/commands/mailbox/add.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# -*- encoding: utf-8 -*-
"""
KERI
keri.kli.commands module

"""
import argparse

from hio import help
from hio.base import doing
from hio.help import Hict

from keri import kering
from keri.app import connecting, habbing, forwarding
from keri.app.agenting import httpClient, WitnessPublisher
from keri.app.cli.common import existing
from keri.core import serdering

logger = help.ogler.getLogger()

parser = argparse.ArgumentParser(description='Add mailbox role')
parser.set_defaults(handler=lambda args: add(args),
transferable=True)
parser.add_argument('--name', '-n', help='keystore name and file location of KERI keystore', required=True)
parser.add_argument('--alias', '-a', help='human readable alias for the identifier to whom the credential was issued',
required=True)
parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore',
required=False, default="")
parser.add_argument('--passcode', '-p', help='22 character encryption passcode for keystore (is not saved)',
dest="bran", default=None) # passcode => bran
parser.add_argument("--mailbox", '-w', help="the mailbox AID or alias to add", required=True)


def add(args):
""" Command line handler for adding an aid to a watcher's list of AIds to watch

Parameters:
args(Namespace): parsed command line arguments

"""

ed = AddDoer(name=args.name,
alias=args.alias,
base=args.base,
bran=args.bran,
mailbox=args.mailbox)
return [ed]


class AddDoer(doing.DoDoer):

def __init__(self, name, alias, base, bran, mailbox):
self.hby = existing.setupHby(name=name, base=base, bran=bran)
self.hab = self.hby.habByName(alias)
self.org = connecting.Organizer(hby=self.hby)
self.witpub = WitnessPublisher(hby=self.hby)

if mailbox in self.hby.kevers:
mbx = mailbox
else:
mbx = self.org.find("alias", mailbox)
if len(mbx) != 1:
raise ValueError(f"invalid mailbox {mailbox}")
mbx = mbx[0]['id']

if not mbx:
raise ValueError(f"unknown mailbox {mailbox}")

self.mailbox = mbx

doers = [doing.doify(self.addDo), self.witpub]

super(AddDoer, self).__init__(doers=doers)

def addDo(self, tymth, tock=0.0):
""" Grant credential by creating /ipex/grant exn message

Parameters:
tymth (function): injected function wrapper closure returned by .tymen() of
Tymist instance. Calling tymth() returns associated Tymist .tyme.
tock (float): injected initial tock value

Returns: doifiable Doist compatible generator method

"""
# enter context
self.wind(tymth)
self.tock = tock
_ = (yield self.tock)

if isinstance(self.hab, habbing.GroupHab):
raise ValueError("watchers for multisig AIDs not currently supported")

kel = self.hab.replay()
data = dict(cid=self.hab.pre,
role=kering.Roles.mailbox,
eid=self.mailbox)

route = "/end/role/add"
msg = self.hab.reply(route=route, data=data)
self.hab.psr.parseOne(ims=(bytes(msg))) # make copy to preserve

fargs = dict([("kel", kel.decode("utf-8")),
("rpy", msg.decode("utf-8"))])

headers = (Hict([
("Content-Type", "multipart/form-data"),
]))

client, clientDoer = httpClient(self.hab, self.mailbox)
self.extend([clientDoer])

client.request(
method="POST",
path=f"{client.requester.path}/mailboxes",
headers=headers,
fargs=fargs
)
while not client.responses:
yield self.tock

rep = client.respond()
if rep.status == 200:
msg = self.hab.replyEndRole(cid=self.hab.pre, role=kering.Roles.mailbox)
self.witpub.msgs.append(dict(pre=self.hab.pre, msg=bytes(msg)))

while not self.witpub.cues:
yield self.tock

print(f"Mailbox {self.mailbox} added for {self.hab.name}")

else:
print(rep.status, rep.data)

self.remove([clientDoer, self.witpub])
13 changes: 13 additions & 0 deletions src/keri/app/cli/commands/oobi/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,16 @@ def generate(tymth, tock=0.0, **opts):
url = urls[kering.Schemes.http] if kering.Schemes.http in urls else urls[kering.Schemes.https]
up = urlparse(url)
print(f"{up.scheme}://{up.hostname}:{up.port}/oobi/{hab.pre}/controller")
elif role in (kering.Roles.mailbox,):
for (_, _, eid), end in hab.db.ends.getItemIter(keys=(hab.pre, kering.Roles.mailbox, )):
if not (end.allowed and end.enabled is not False):
continue

urls = hab.fetchUrls(eid=eid, scheme=kering.Schemes.http) or hab.fetchUrls(eid=hab.pre,
scheme=kering.Schemes.https)
if not urls:
print(f"{alias} identifier {hab.pre} does not have any mailbox endpoints")
return
url = urls[kering.Schemes.http] if kering.Schemes.http in urls else urls[kering.Schemes.https]
up = urlparse(url)
print(f"{up.scheme}://{up.hostname}:{up.port}/oobi/{hab.pre}/mailbox/{eid}")
17 changes: 14 additions & 3 deletions src/keri/app/cli/commands/rotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
dest="endpoint", action='store_true')
parser.add_argument("--authenticate", '-z', help="Prompt the controller for authentication codes for each witness",
action='store_true')
parser.add_argument('--code', help='<Witness AID>:<code> formatted witness auth codes. Can appear multiple times',
default=[], action="append", required=False)

parser.add_argument("--proxy", help="alias for delegation communication proxy", default="")

rotating.addRotationArgs(parser)
Expand Down Expand Up @@ -63,7 +66,7 @@ def rotate(args):
cuts=opts.witsCut, adds=opts.witsAdd,
isith=opts.isith, nsith=opts.nsith,
count=opts.ncount, toad=opts.toad,
data=opts.data, proxy=args.proxy, authenticate=args.authenticate)
data=opts.data, proxy=args.proxy, authenticate=args.authenticate, codes=args.code)

doers = [rotDoer]

Expand Down Expand Up @@ -118,7 +121,8 @@ class RotateDoer(doing.DoDoer):
"""

def __init__(self, name, base, bran, alias, endpoint=False, isith=None, nsith=None, count=None,
toad=None, wits=None, cuts=None, adds=None, data: list = None, proxy=None, authenticate=False):
toad=None, wits=None, cuts=None, adds=None, data: list = None, proxy=None, authenticate=False,
codes=None):
"""
Returns DoDoer with all registered Doers needed to perform rotation.

Expand All @@ -144,6 +148,7 @@ def __init__(self, name, base, bran, alias, endpoint=False, isith=None, nsith=No
self.endpoint = endpoint
self.proxy = proxy
self.authenticate = authenticate
self.codes = codes if codes is not None else []

self.wits = wits if wits is not None else []
self.cuts = cuts if cuts is not None else []
Expand Down Expand Up @@ -193,12 +198,18 @@ def rotateDo(self, tymth, tock=0.0):

auths = {}
if self.authenticate:
for arg in self.codes:
(wit, code) = arg.split(":")
auths[wit] = f"{code}#{helping.nowIso8601()}"

for wit in hab.kever.wits:
if wit in auths:
continue
code = input(f"Entire code for {wit}: ")
auths[wit] = f"{code}#{helping.nowIso8601()}"

if hab.kever.delpre:
self.swain.delegation(pre=hab.pre, sn=hab.kever.sn)
self.swain.delegation(pre=hab.pre, sn=hab.kever.sn, auths=auths)
print("Waiting for delegation approval...")
while not self.swain.complete(hab.kever.prefixer, coring.Seqner(sn=hab.kever.sn)):
yield self.tock
Expand Down
Loading
Loading