diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5b48406..bbedc45 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -17,14 +17,14 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10.4 + - name: Set up Python 3.12.1 uses: actions/setup-python@v2 with: - python-version: 3.10.4 + python-version: 3.12.1 - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest mockito pytest-cov codecov + pip install pytest mockito==1.4.0 pytest-cov codecov pip install -r requirements.txt - name: Run tests run: | diff --git a/scripts/create_new_multisig_issuer.py b/scripts/create_new_multisig_issuer.py new file mode 100644 index 0000000..9f304cf --- /dev/null +++ b/scripts/create_new_multisig_issuer.py @@ -0,0 +1,150 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" +from time import sleep + +import requests +from keri import kering +from keri.core import coring, serdering +from keri.core.coring import Tiers + +from signify.app.clienting import SignifyClient + +URL = "http://localhost:3901" + + +def create_quadlet(): + bran1 = "0123456789abcdefghsec" + bran2 = "0123456789abcdefghsaw" + bran3 = "0123456789abcdefghsg4" + bran4 = "0123456789abcdefgh0z5" + + client1 = create_agent(bran1, + "EIX9c9DUvzXK5E7EnBybtIizdo9KBQISOrYb0JNQ7OFI", + "EHkbqFLxa5TrSjAiZsC5gtHmynGYkUhgOyNWDRKbfSPd") + + client2 = create_agent(bran2, + "EKzJM2IBFSkAIz-RpXUv7GhvTdPPvpNl9nf8emPUcXqi", + "EAiO7QUJcyDXJ5WfToUJqJV437N5p9NXbpMXb9XEjUti") + + client3 = create_agent(bran3, + "ECyAJ3zRVKO5vr8LbssPnNEKf10MmgF9BGqB06lvFVR0", + "EMY8KpPNknneXlrhGIFnN7UUOMO27g-M5SO5MRqXPzwe") + + client4 = create_agent(bran4, + "ENL1pd5iTRBe6XMMD-yi05W6_bVz1nQFvxWM52I6DTRk", + "EHLxs9z_5xwLuRBuS-xkQwIJvZMJ6d9dhxSo9fYn8lCs") + + create_aid(client1, "multisig1", bran1, "EBFg-5SGDCv5YfwpkArWRBdTxNRUXU8uVcDKNzizOQZc") + create_aid(client2, "multisig2", bran2, "EBmW2bXbgsP3HITwW3FmITzAb3wVmHlxCusZ46vgGgP5") + create_aid(client3, "multisig3", bran3, "EL4RpdS2Atb2Syu5xLdpz9CcNNYoFUUDlLHxHD09vcgh") + create_aid(client4, "multisig4", bran4, "EAiBVuuhCZrgckeHc9KzROVGJpmGbk2-e1B25GaeRrJs") + + oobi(client2, "multisig1", "http://127.0.0.1:3902/oobi/EBFg-5SGDCv5YfwpkArWRBdTxNRUXU8uVcDKNzizOQZc") + oobi(client3, "multisig1", "http://127.0.0.1:3902/oobi/EBFg-5SGDCv5YfwpkArWRBdTxNRUXU8uVcDKNzizOQZc") + oobi(client4, "multisig1", "http://127.0.0.1:3902/oobi/EBFg-5SGDCv5YfwpkArWRBdTxNRUXU8uVcDKNzizOQZc") + + oobi(client1, "multisig2", "http://127.0.0.1:3902/oobi/EBmW2bXbgsP3HITwW3FmITzAb3wVmHlxCusZ46vgGgP5") + oobi(client3, "multisig2", "http://127.0.0.1:3902/oobi/EBmW2bXbgsP3HITwW3FmITzAb3wVmHlxCusZ46vgGgP5") + oobi(client4, "multisig2", "http://127.0.0.1:3902/oobi/EBmW2bXbgsP3HITwW3FmITzAb3wVmHlxCusZ46vgGgP5") + + oobi(client1, "multisig3", "http://127.0.0.1:3902/oobi/EL4RpdS2Atb2Syu5xLdpz9CcNNYoFUUDlLHxHD09vcgh") + oobi(client2, "multisig3", "http://127.0.0.1:3902/oobi/EL4RpdS2Atb2Syu5xLdpz9CcNNYoFUUDlLHxHD09vcgh") + oobi(client4, "multisig3", "http://127.0.0.1:3902/oobi/EL4RpdS2Atb2Syu5xLdpz9CcNNYoFUUDlLHxHD09vcgh") + + oobi(client1, "multisig4", "http://127.0.0.1:3902/oobi/EAiBVuuhCZrgckeHc9KzROVGJpmGbk2-e1B25GaeRrJs") + oobi(client2, "multisig4", "http://127.0.0.1:3902/oobi/EAiBVuuhCZrgckeHc9KzROVGJpmGbk2-e1B25GaeRrJs") + oobi(client3, "multisig4", "http://127.0.0.1:3902/oobi/EAiBVuuhCZrgckeHc9KzROVGJpmGbk2-e1B25GaeRrJs") + + oobi(client1, "old-multisig1", "http://127.0.0.1:5642/oobi/EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4/witness") + oobi(client1, "old-multisig2", "http://127.0.0.1:5642/oobi/EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1/witness") + + oobi(client2, "old-multisig1", "http://127.0.0.1:5642/oobi/EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4/witness") + oobi(client2, "old-multisig2", "http://127.0.0.1:5642/oobi/EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1/witness") + + oobi(client3, "old-multisig1", "http://127.0.0.1:5642/oobi/EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4/witness") + oobi(client3, "old-multisig2", "http://127.0.0.1:5642/oobi/EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1/witness") + + oobi(client4, "old-multisig1", "http://127.0.0.1:5642/oobi/EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4/witness") + oobi(client4, "old-multisig2", "http://127.0.0.1:5642/oobi/EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1/witness") + + oobi(client1, "multisig", "http://127.0.0.1:5642/oobi/EC61gZ9lCKmHAS7U5ehUfEbGId5rcY0D7MirFZHDQcE2/witness") + oobi(client2, "multisig", "http://127.0.0.1:5642/oobi/EC61gZ9lCKmHAS7U5ehUfEbGId5rcY0D7MirFZHDQcE2/witness") + oobi(client3, "multisig", "http://127.0.0.1:5642/oobi/EC61gZ9lCKmHAS7U5ehUfEbGId5rcY0D7MirFZHDQcE2/witness") + oobi(client4, "multisig", "http://127.0.0.1:5642/oobi/EC61gZ9lCKmHAS7U5ehUfEbGId5rcY0D7MirFZHDQcE2/witness") + + +def create_agent(bran, ctrlAid, agentAid): + tier = Tiers.low + client = SignifyClient(passcode=bran, tier=tier) + assert client.controller == ctrlAid + + evt, siger = client.ctrl.event() + + res = requests.post(url="http://localhost:3903/boot", + json=dict( + icp=evt.ked, + sig=siger.qb64, + stem=client.ctrl.stem, + pidx=1, + tier=client.ctrl.tier)) + + if res.status_code != requests.codes.accepted: + raise kering.AuthNError(f"unable to initialize cloud agent connection, {res.status_code}, {res.text}") + + client.connect(url=URL, ) + assert client.agent is not None + + assert client.agent.pre == agentAid + assert client.agent.delpre == ctrlAid + print(f"Agent {client.agent.pre} created for controller {client.controller}") + + return client + + +def create_aid(client, name, bran, pre): + identifiers = client.identifiers() + operations = client.operations() + + wits = [ + "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + "BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM", + "BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX" + ] + + op = identifiers.create(name, bran=bran, wits=wits, toad="2") + op = op[2] + + while not op["done"]: + op = operations.get(op["name"]) + sleep(1) + + icp = serdering.SerderKERI(sad=op["response"]) + print(icp.pre) + assert icp.pre == pre + + identifiers.addEndRole(name, eid=client.agent.pre) + + print(f"Created AID {name}: {icp.pre}") + + +def oobi(client, alias, url): + oobis = client.oobis() + operations = client.operations() + + print(f"Resolving oobi to {alias}") + op = oobis.resolve( + oobi=url, + alias=alias) + while not op["done"]: + op = operations.get(op["name"]) + sleep(1) + print("... done") + + +if __name__ == "__main__": + create_quadlet() diff --git a/scripts/join_new_multisig_issuer.py b/scripts/join_new_multisig_issuer.py new file mode 100644 index 0000000..a3e5cd4 --- /dev/null +++ b/scripts/join_new_multisig_issuer.py @@ -0,0 +1,115 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +join new quadlet script + +""" + +from time import sleep + +from keri.core import eventing, coring, serdering +from keri.core.coring import Tiers +from signify.app.clienting import SignifyClient + + +def join_new_quadlet(): + group = "multisig" + client1 = get_client(bran=b'0123456789abcdefghsec') + client2 = get_client(bran=b'0123456789abcdefghsaw') + + resolve_oobi(client1, "vc", "http://127.0.0.1:7723/oobi/EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao") + resolve_oobi(client2, "vc", "http://127.0.0.1:7723/oobi/EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao") + + op2 = accept_join_request(client2, name="multisig2", group=group) + if not op2: + raise ValueError("No op created for multisig2") + op1 = accept_join_request(client1, name="multisig1", group=group) + if not op1: + raise ValueError("No op created for multisig1") + + while not op2['done']: + sleep(1) + op2 = client2.operations().get(op2['name']) + + while not op1['done']: + sleep(1) + op1 = client1.operations().get(op1['name']) + + +def get_client(bran): + url = "http://localhost:3901" + tier = Tiers.low + + return SignifyClient(passcode=bran, tier=tier, url=url) + + +def accept_join_request(client, name, group): + identifiers = client.identifiers() + notificatons = client.notifications() + exchanges = client.exchanges() + groups = client.groups() + + hab = identifiers.get(name) + + resp = notificatons.list() + + for note in resp['notes']: + payload = note['a'] + route = payload['r'] + if route == "/multisig/rot": + said = payload['d'] + + res = exchanges.get(said=said) + exn = res['exn'] + a = exn['a'] + + gid = a['gid'] + smids = a['smids'] + rmids = a['rmids'] + + recipients = list(set(smids + (rmids or []))) + recipients.remove(hab['prefix']) + + idx = smids.index(hab["prefix"]) + odx = rmids.index(hab['prefix']) + + embeds = exn['e'] + ked = embeds['rot'] + rot = serdering.SerderKERI(sad=ked) + + keeper = client.manager.get(aid=hab) + sigs = keeper.sign(ser=rot.raw, indexed=True, indices=[idx], ondices=[odx]) + + op = groups.join(group, rot, sigs, gid, smids, rmids) + + embeds = dict( + rot=eventing.messagize(serder=rot, sigers=[coring.Siger(qb64=sig) for sig in sigs]) + ) + + exchanges.send(name, "multisig", sender=hab, route="/multisig/rot", + payload=dict(gid=gid, smids=smids, rmids=smids), + embeds=embeds, recipients=recipients) + + return op + + return None + + +def resolve_oobi(client, alias, url): + oobis = client.oobis() + operations = client.operations() + + op = oobis.resolve(oobi=url, + alias=alias) + + print(f"resolving oobi for {alias}") + while not op["done"]: + op = operations.get(op["name"]) + sleep(1) + + print("... done") + return op["response"] + + +if __name__ == "__main__": + join_new_quadlet() diff --git a/scripts/list_multisig_credentials.py b/scripts/list_multisig_credentials.py new file mode 100644 index 0000000..500e449 --- /dev/null +++ b/scripts/list_multisig_credentials.py @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" +from keri.core import serdering +from keri.core.coring import Tiers + +from signify.app.clienting import SignifyClient + + +def list_credentials(): + url = "http://localhost:3901" + bran = b'0123456789abcdefghsec' + tier = Tiers.low + + client = SignifyClient(passcode=bran, tier=tier, url=url) + + identifiers = client.identifiers() + res = identifiers.list() + + aids = res['aids'] + + assert len(aids) == 2 + + res = identifiers.get("multisig") + + aid = res['prefix'] + print(aid) + credentials = client.credentials() + + creds = credentials.list(filtr={'-i': aid}) + for cred in creds: + creder = serdering.SerderACDC(sad=cred['sad']) + print(creder.pretty(size=5000)) + + +if __name__ == "__main__": + list_credentials() diff --git a/scripts/rename_registry.py b/scripts/rename_registry.py new file mode 100644 index 0000000..f1cc25c --- /dev/null +++ b/scripts/rename_registry.py @@ -0,0 +1,34 @@ +# -*- encoding: utf-8 -*- +""" +SIGNIFY +signify.app.clienting module + +Testing clienting with integration tests that require a running KERIA Cloud Agent +""" +import sys + +from keri.core import serdering +from keri.core.coring import Tiers + +from signify.app.clienting import SignifyClient + + +def rename_registry(name, registryName, newName): + url = "http://localhost:3901" + bran = b'0123456789abcdefghsec' + tier = Tiers.low + + client = SignifyClient(passcode=bran, tier=tier, url=url) + identifiers = client.identifiers() + registries = client.registries() + + hab = identifiers.get(name) + + res = registries.rename(hab, registryName, newName) + print(res) + + registry = registries.get(hab['name'], newName) + print(registry) + +if __name__ == "__main__": + rename_registry(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/setup.py b/setup.py index d30fd11..79ea0c3 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ from setuptools import find_packages, setup setup( name='signifypy', - version='0.1.0', # also change in src/signify/__init__.py + version='0.1.1', # also change in src/signify/__init__.py license='Apache Software License 2.0', description='Signify', long_description="KERI Signing at the Edge Infrastructure", @@ -63,9 +63,9 @@ keywords=[ # eg: 'keyword1', 'keyword2', 'keyword3', ], - python_requires='>=3.10.4', + python_requires='>=3.12.1', install_requires=[ - 'keri>=1.1.0', + 'keri>=1.1.6', 'multicommand>=1.0.0', 'requests>=2.28', 'http_sfv>=0.9.8', @@ -78,8 +78,8 @@ tests_require=[ 'responses>=0.22.0', 'coverage>=6.5.0', - 'pytest>=7.2.0', - 'mockito>=1.4.0' + 'pytest==7.2.0', + 'mockito==1.4.0' ], setup_requires=[ ], diff --git a/src/signify/__init__.py b/src/signify/__init__.py index e39210a..f609cc8 100644 --- a/src/signify/__init__.py +++ b/src/signify/__init__.py @@ -3,5 +3,5 @@ main package """ -__version__ = '0.1.0' # also change in setup.py +__version__ = '0.1.1' # also change in setup.py diff --git a/src/signify/app/credentialing.py b/src/signify/app/credentialing.py index 480b8c7..b025edf 100644 --- a/src/signify/app/credentialing.py +++ b/src/signify/app/credentialing.py @@ -103,6 +103,12 @@ def serialize(serder, anc): return msg + def rename(self, hab, registryName, newName): + name = hab["name"] + body = dict(name=newName) + resp = self.client.put(path=f"/identifiers/{name}/registries/{registryName}", json=body) + return resp.json() + class Credentials: """ Domain class for accessing, presenting, issuing and revoking credentials """ diff --git a/tests/app/test_credentialing.py b/tests/app/test_credentialing.py index 1c0218e..8400d7e 100644 --- a/tests/app/test_credentialing.py +++ b/tests/app/test_credentialing.py @@ -47,6 +47,10 @@ def test_registries(): expect(mock_client, times=1).get(f"/identifiers/{name}/registries/{regName}").thenReturn(mock_response) registries.get(name="aid1", registryName=regName) + (expect(mock_client, times=1).put(path=f"/identifiers/{name}/registries/{regName}", json={'name': 'test'}) + .thenReturn(mock_response)) + registries.rename(mock_hab, regName, "test") + pre = "ELI7pg979AdhmvrjDeam2eAO2SR5niCgnjAJXJHtJose" dig = "EOgQvKz8ziRn7FdR_ebwK9BkaVOnGeXQOJ87N6hMLrK0" nonce = "ACb_3pGwW3uIjtOg4zRQ66I-SggMcmoyju_uCzuSvgG4"