diff --git a/examples/scripts/client.ts b/examples/scripts/client.ts index f778720f..0230571f 100644 --- a/examples/scripts/client.ts +++ b/examples/scripts/client.ts @@ -1,3 +1,4 @@ +// @ts-ignore let signify: any; // @ts-ignore @@ -50,6 +51,8 @@ async function connect() { let op = await identifiers.create("multisig-ts", {bran: salt}) let aid = op["response"] + await identifiers.addEndRole("multisig-ts", "agent", d.agent.i) + console.log("Created AID: ", aid) console.log("Resolving delegator...") @@ -66,8 +69,7 @@ async function connect() { console.log("Resolving multisig-kli...") op = await oobis.resolve( - "http://127.0.0.1:5642/oobi/EFBmwh8vdPTofoautCiEjjuA17gSlEnE3xc-xy-fGzWZ/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv" + - "_VmF_dJNN6vkf2Ha", + "http://127.0.0.1:5642/oobi/EFBmwh8vdPTofoautCiEjjuA17gSlEnE3xc-xy-fGzWZ", "multisig-kli"); while (!op["done"]) { op = await operations.get(op["name"]); diff --git a/examples/scripts/create_multisig_aid.py b/examples/scripts/create_multisig_aid.py index 2ab70915..4760509d 100644 --- a/examples/scripts/create_multisig_aid.py +++ b/examples/scripts/create_multisig_aid.py @@ -9,9 +9,7 @@ from time import sleep from keri.app.keeping import Algos -from keri.core import coring from keri.core.coring import Tiers - from signify.app.clienting import SignifyClient diff --git a/examples/scripts/create_person_aid.py b/examples/scripts/create_person_aid.py index 47a3310e..6ed77a0f 100644 --- a/examples/scripts/create_person_aid.py +++ b/examples/scripts/create_person_aid.py @@ -24,8 +24,8 @@ def create_aid(): operations = client.operations() oobis = client.oobis() - aids = identifiers.list() - assert aids == [] + res = identifiers.list() + assert res["aids"] == [] wits = [ "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", @@ -57,8 +57,7 @@ def create_aid(): print("multisig-sigpy resolving multisig-kli...") op = oobis.resolve( - oobi="http://127.0.0.1:5642/oobi/EFBmwh8vdPTofoautCiEjjuA17gSlEnE3xc-xy-fGzWZ/witness/BBilc4" - "-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + oobi="http://127.0.0.1:5642/oobi/EFBmwh8vdPTofoautCiEjjuA17gSlEnE3xc-xy-fGzWZ", alias="multisig-kli") while not op["done"]: op = operations.get(op["name"]) diff --git a/examples/scripts/create_rpys.py b/examples/scripts/create_rpys.py new file mode 100644 index 00000000..4760509d --- /dev/null +++ b/examples/scripts/create_rpys.py @@ -0,0 +1,61 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" +import json +from time import sleep + +from keri.app.keeping import Algos +from keri.core.coring import Tiers +from signify.app.clienting import SignifyClient + + +def create_multisig_aid(): + url = "http://localhost:3901" + bran = b'9876543210abcdefghijk' + tier = Tiers.low + + client = SignifyClient(passcode=bran, tier=tier, url=url) + + identifiers = client.identifiers() + operations = client.operations() + states = client.keyStates() + + aid = identifiers.get("multisig-sigpy") + sigPy = aid["state"] + + kli = states.get("EFBmwh8vdPTofoautCiEjjuA17gSlEnE3xc-xy-fGzWZ") + sigTs = states.get("ELViLL4JCh-oktYca-pmPLwkmUaeYjyPmCLxELAKZW8V") + + assert len(kli) == 1 + assert len(sigTs) == 1 + + states = rstates = [sigPy, kli[0], sigTs[0]] + for state in states: + print(json.dumps(state, indent=2)) + + op = identifiers.create("multisig", algo=Algos.group, mhab=aid, + delpre="EHpD0-CDWOdu5RJ8jHBSUkOqBZ3cXeDVHWNb_Ul89VI7", + toad=2, + wits=[ + "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + "BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM", + "BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX" + ], + isith=["1/3", "1/3", "1/3"], nsith=["1/3", "1/3", "1/3"], + states=states, + rstates=rstates) + print("waiting on multisig creation...") + while not op["done"]: + op = operations.get(op["name"]) + sleep(1) + gAid = op["response"] + print(f"group multisig created:") + print(json.dumps(gAid, indent=2)) + + +if __name__ == "__main__": + create_multisig_aid() diff --git a/examples/scripts/delegator.sh b/examples/scripts/delegator.sh index 460a4333..451e1c8b 100755 --- a/examples/scripts/delegator.sh +++ b/examples/scripts/delegator.sh @@ -3,5 +3,5 @@ kli init --name delegator --nopasscode --config-dir ${KERI_SCRIPT_DIR} --config-file demo-witness-oobis-schema --salt 0ACDEyMzQ1Njc4OWdoaWpsaw kli incept --name delegator --alias delegator --file ${KERI_DEMO_SCRIPT_DIR}/data/delegator.json - -# kli delegate confirm --name delegator --alias delegator -Y & +echo "Waiting for delegation request..." +kli delegate confirm --name delegator --alias delegator \ No newline at end of file diff --git a/examples/scripts/list_aids.py b/examples/scripts/list_aids.py new file mode 100644 index 00000000..bae4694e --- /dev/null +++ b/examples/scripts/list_aids.py @@ -0,0 +1,27 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" + +from keri.core.coring import Tiers + +from signify.app.clienting import SignifyClient + + +def list_aids(): + url = "http://localhost:3901" + bran = b'9876543210abcdefghijk' + tier = Tiers.low + client = SignifyClient(passcode=bran, tier=tier, url=url) + + identifiers = client.identifiers() + res = identifiers.list() + for aid in res["aids"]: + print(f"{aid['name']}: {aid['prefix']}") + + +if __name__ == "__main__": + list_aids() diff --git a/examples/scripts/make_endroles.ts b/examples/scripts/make_endroles.ts new file mode 100644 index 00000000..6e70204f --- /dev/null +++ b/examples/scripts/make_endroles.ts @@ -0,0 +1,67 @@ + +// @ts-ignore +let signify: any; + +// @ts-ignore +import('signify-ts').then( + (module) => { + signify = module + signify.ready().then(() => { + console.log("Signify client ready!"); + makeends().then(() => { + console.log("Done") + }); + }); + } +) + +async function makeends() { + let url = "http://127.0.0.1:3901" + let bran = '0123456789abcdefghijk' + + const client = new signify.SignifyClient(url, bran); + await client.connect() + let d = await client.state() + console.log("Connected: ") + console.log(" Agent: ", d.agent.i, " Controller: ", d.controller.state.i) + + let identifiers = client.identifiers() + let escrows = client.escrows() + + let members = await identifiers.members("multisig") + let hab = await identifiers.get("multisig") + let aid = hab["prefix"] + let signing = members['signing'] + + let auths = new Map() + let stamp = new Date() + + signing.forEach((end: any) => { + let ends = end["ends"] + let roles = ["agent", "mailbox"] + roles.forEach((role) => { + if (role in ends) { + Object.keys(ends[role]).forEach((k:any) => { + let key = [aid, role, k].join(".") + auths.set(key, stamp) + }) + } + }) + }) + + let rpys = await escrows.listReply("/end/role") + + rpys.forEach((rpy:object) => { + let serder = new signify.Serder(rpy) + let payload = serder.ked['a'] + + let key = Object.values(payload).join(".") + let then = new Date(Date.parse(serder.ked["dt"])) + if (auths.has(key) && then < stamp) { + identifiers.addEndRole("multisig", payload["role"], payload["eid"], serder.ked["dt"]) + auths.set(key, then) // track signed role auths by timestamp signed + } + }) + +} + diff --git a/examples/scripts/multisig-kli.sh b/examples/scripts/multisig-kli.sh index 3481adc3..b4c81be2 100755 --- a/examples/scripts/multisig-kli.sh +++ b/examples/scripts/multisig-kli.sh @@ -9,6 +9,7 @@ # EFBmwh8vdPTofoautCiEjjuA17gSlEnE3xc-xy-fGzWZ kli init --name multisig-kli --salt 0ACDEyMzQ1Njc4OWxtbm9GhI --nopasscode --config-dir "${KERI_SCRIPT_DIR}" --config-file demo-witness-oobis-schema kli incept --name multisig-kli --alias multisig-kli --file "${KERI_DEMO_SCRIPT_DIR}"/data/gleif-sample.json +kli ends add --name multisig-kli --alias multisig-kli --role mailbox --eid BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX read -n 1 -r -p "Press any key after multisig-sigpy and multisig-sigts have been created:" @@ -16,4 +17,8 @@ kli oobi resolve --name multisig-kli --oobi-alias delegator --oobi http://127.0. kli oobi resolve --name multisig-kli --oobi-alias multisig-sigpy --oobi http://127.0.0.1:3902/oobi/EBcIURLpxmVwahksgrsGW6_dUw0zBhyEHYFk17eWrZfk/agent/EERMVxqeHfFo_eIvyzBXaKdT1EyobZdSs1QXuFyYLjmz kli oobi resolve --name multisig-kli --oobi-alias multisig-sigts --oobi http://127.0.0.1:3902/oobi/ELViLL4JCh-oktYca-pmPLwkmUaeYjyPmCLxELAKZW8V/agent/EEXekkGu9IAzav6pZVJhkLnjtjM5v3AcyA-pdKUcaGei -kli multisig incept --name multisig-kli --alias multisig-kli --group multisig --file ${KERI_DEMO_SCRIPT_DIR}/data/multisig-triple.json \ No newline at end of file +kli multisig incept --name multisig-kli --alias multisig-kli --group multisig --file ${KERI_DEMO_SCRIPT_DIR}/data/multisig-triple.json + +read -n 1 -r -p "Press any key to create endpoints for multisig AID..." + +kli multisig ends add --name multisig-kli --alias multisig --role agent --role mailbox \ No newline at end of file diff --git a/examples/scripts/multisig-sigpy.sh b/examples/scripts/multisig-sigpy.sh index f4cb337c..bb7f667d 100755 --- a/examples/scripts/multisig-sigpy.sh +++ b/examples/scripts/multisig-sigpy.sh @@ -3,3 +3,8 @@ python "${KERI_SCRIPT_DIR}"/create_agent.py python "${KERI_SCRIPT_DIR}"/create_person_aid.py +python "${KERI_SCRIPT_DIR}"/create_multisig_aid.py + +read -n 1 -r -p "Press any key to create endpoints for multisig AID..." + +python "${KERI_SCRIPT_DIR}"/multisig_endrole.py diff --git a/examples/scripts/multisig-sigty.sh b/examples/scripts/multisig-sigty.sh new file mode 100755 index 00000000..857b68ce --- /dev/null +++ b/examples/scripts/multisig-sigty.sh @@ -0,0 +1,8 @@ +#!/bin/bash + + +npx --package=signify-ts ts-node client.ts + +read -n 1 -r -p "Press any key to create endpoints for multisig AID..." + +npx --package=signify-ts ts-node make_endroles.ts \ No newline at end of file diff --git a/examples/scripts/multisig_endrole.py b/examples/scripts/multisig_endrole.py new file mode 100644 index 00000000..07045db1 --- /dev/null +++ b/examples/scripts/multisig_endrole.py @@ -0,0 +1,93 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" + +import json +from time import sleep + +from keri.app.keeping import Algos +from keri.core import coring +from keri.core.coring import Tiers +from keri.help import helping +from signify.app.clienting import SignifyClient + +url = "http://localhost:3901" +bran = b'9876543210abcdefghijk' +tier = Tiers.low + +def authorize_endroles(): + client = SignifyClient(passcode=bran, tier=tier, url=url) + identifiers = client.identifiers() + escrows = client.escrows() + endroles = client.endroles() + + members = identifiers.members("multisig") + hab = identifiers.get("multisig") + aid = hab["prefix"] + + auths = {} + stamp = helping.nowUTC() + + for member in members['signing']: + ends = member["ends"] + if not ends: + print("\tNone") + + for role in ("agent", "mailbox"): + if role in ends: + for k, v in ends[role].items(): + auths[(aid, role, k)] = stamp + + rpys = escrows.getEscrowReply(route="/end/role") + for rpy in rpys: + serder = coring.Serder(ked=rpy) + payload = serder.ked['a'] + keys = tuple(payload.values()) + then = helping.fromIso8601(serder.ked["dt"]) + if keys in auths and then < stamp: + identifiers.addEndRole("multisig", role=payload["role"], eid=payload['eid'], stamp=helping.toIso8601(then)) + auths[keys] = then # track signed role auths by timestamp signed + + print("Waiting for approvals from other members...") + authKeys = set(auths.keys()) + while authKeys - endrole_set(endroles, "multisig"): + rpys = escrows.getEscrowReply(route="/end/role") + for rpy in rpys: + serder = coring.Serder(ked=rpy) + payload = serder.ked['a'] + keys = tuple(payload.values()) + if keys in auths: + then = helping.fromIso8601(serder.ked["dt"]) + stamp = auths[keys] + + if stamp == then: + continue + + if then < stamp: + print(f"authing {payload} - {then}") + identifiers.addEndRole("multisig", role=payload["role"], eid=payload['eid'], + stamp=serder.ked["dt"]) + auths[keys] = then # track signed role auths by timestamp signed + + print("All endpoint role authorizations approved") + + +def endrole_set(er, name): + ends = er.list(name=name) + return {(end['cid'], end['role'], end['eid']) for end in ends} + + +def list_endroles(): + client = SignifyClient(passcode=bran, tier=tier, url=url) + + endroles = client.endroles() + print(endrole_set(endroles, "multisig")) + + +if __name__ == "__main__": + authorize_endroles() + # list_endroles() diff --git a/examples/scripts/stream_escrows.py b/examples/scripts/stream_escrows.py new file mode 100644 index 00000000..c5a5058c --- /dev/null +++ b/examples/scripts/stream_escrows.py @@ -0,0 +1,35 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" +import json +from time import sleep + +from keri.app.keeping import Algos +from keri.core.coring import Tiers +from signify.app.clienting import SignifyClient + + +def stream_escrows(): + url = "http://localhost:3901" + bran = b'9876543210abcdefghijk' + tier = Tiers.low + + client = SignifyClient(passcode=bran, tier=tier, url=url) + + endroles = client.endroles() + + + + + escrows = client.escrows() + + for rpy in escrows.getEscrowReplyIter(route="/end/role"): + print(rpy) + + +if __name__ == "__main__": + stream_escrows() diff --git a/src/keri/app/signify.ts b/src/keri/app/signify.ts index 13f406ed..9220481c 100644 --- a/src/keri/app/signify.ts +++ b/src/keri/app/signify.ts @@ -246,7 +246,7 @@ export class SignifyClient { } }) } - + async rotate(nbran: string, aids: [string] ){ let data = this.controller.rotate(nbran, aids) await fetch(this.url + "/agent/" + this.controller.pre, { @@ -256,7 +256,7 @@ export class SignifyClient { "Content-Type": "application/json" } }) - + } identifiers() { @@ -302,6 +302,10 @@ export class SignifyClient { notifications() { return new Notifications(this) } + + escrows(): Escrows { + return new Escrows(this) + } } class Identifier { @@ -565,11 +569,11 @@ class Identifier { let res = await this.client.fetch("/identifiers/" + name, "PUT", jsondata) return res.json() } - async addEndRole(name: string, role: string, eid?: string) { + async addEndRole(name: string, role: string, eid?: string, stamp?: string) { const hab = await this.get(name) const pre = hab.prefix - const rpy = this.makeEndRole(pre, role, eid) + const rpy = this.makeEndRole(pre, role, eid, stamp) const keeper = this.client.manager!.get(hab) const sigs = keeper.sign(b(rpy.raw)) @@ -582,7 +586,7 @@ class Identifier { return res.json() } - makeEndRole(pre: string, role: string, eid?: string) { + makeEndRole(pre: string, role: string, eid?: string, stamp?: string) { const data: any = { cid: pre, role: role @@ -591,7 +595,12 @@ class Identifier { data.eid = eid } const route = "/end/role/add" - return reply(route, data, undefined, undefined, Serials.JSON) + return reply(route, data, stamp, undefined, Serials.JSON) + } + + async members(name: string) { + let res = await this.client.fetch("/identifiers/" + name + "/members", "GET", undefined) + return res.json() } } @@ -1292,3 +1301,21 @@ class Notifications { } +class Escrows { + client: SignifyClient + + constructor(client: SignifyClient) { + this.client = client + } + + async listReply(route?:string) { + let params = new URLSearchParams() + if (route !== undefined) {params.append('route', route)} + + let path = `/escrows/rpy` + '?' + params.toString() + let method = 'GET' + let res = await this.client.fetch(path, method, null) + return await res.json() + } +} +