From c9d35f901e293f166d5abbd58cda249248555253 Mon Sep 17 00:00:00 2001 From: Fergal Date: Fri, 11 Oct 2024 13:51:23 +0100 Subject: [PATCH] feat: endpoint to get credential registry end (#304) --- src/keria/app/credentialing.py | 57 ++++++++++++++++++++++++++++++++- tests/app/test_credentialing.py | 26 +++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/keria/app/credentialing.py b/src/keria/app/credentialing.py index 08641d3..54c981b 100644 --- a/src/keria/app/credentialing.py +++ b/src/keria/app/credentialing.py @@ -34,7 +34,10 @@ def loadEnds(app, identifierResource): credentialCollectionEnd = CredentialCollectionEnd(identifierResource) app.add_route("/identifiers/{name}/credentials", credentialCollectionEnd) - + + credentialRegistryResEnd = CredentialRegistryResourceEnd() + app.add_route("/registries/{ri}/{vci}", credentialRegistryResEnd) + credentialResourceEnd = CredentialResourceEnd() app.add_route("/credentials/{said}", credentialResourceEnd) credentialResourceDelEnd = CredentialResourceDeleteEnd(identifierResource) @@ -892,6 +895,58 @@ def on_delete(self, req, rep, name, said): rep.data = op.to_json().encode("utf-8") +class CredentialRegistryResourceEnd: + @staticmethod + def on_get(req, rep, ri, vci): + """ Get credential registry state + + Parameters: + req: falcon.Request HTTP request + rep: falcon.Response HTTP response + + --- + summary: Get credential registry state + description: Get credential registry state from any known Tever (does not need be controlled by us) + tags: + - Credentials + parameters: + - in: path + name: ri + schema: + type: string + required: true + description: SAID of management TEL + - in: path + name: vci + schema: + type: string + required: true + description: SAID of credential + responses: + 200: + description: Credential registry state + content: + application/json: + schema: + description: Credential registry state + type: object + 404: + description: Unknown management registry or credential + """ + agent = req.context.agent + if ri not in agent.tvy.tevers: + raise falcon.HTTPNotFound(description=f"registry {ri} not found") + tever = agent.tvy.tevers[ri] + + state = tever.vcState(vci) + if not state: + raise falcon.HTTPNotFound(description=f"credential {vci} not found in registry {ri}") + + rep.status = falcon.HTTP_200 + rep.content_type = "application/json" + rep.data = json.dumps(asdict(state)).encode("utf-8") + + def signPaths(hab, pather, sigers): """ Sign the SAD or SAIDs with the keys from the Habitat. diff --git a/tests/app/test_credentialing.py b/tests/app/test_credentialing.py index 0ef649e..562f666 100644 --- a/tests/app/test_credentialing.py +++ b/tests/app/test_credentialing.py @@ -350,6 +350,8 @@ def test_credentialing_ends(helpers, seeder): app.add_route("/credentials/query", credResEnd) credResEnd = credentialing.CredentialResourceEnd() app.add_route("/credentials/{said}", credResEnd) + credentialRegistryResEnd = credentialing.CredentialRegistryResourceEnd() + app.add_route("/registries/{ri}/{vci}", credentialRegistryResEnd) assert hab.pre == "EIqTaQiZw73plMOq8pqHTi9BDgDrrE7iE9v2XfN2Izze" @@ -468,6 +470,23 @@ def test_credentialing_ends(helpers, seeder): assert res.status_code == 200 assert res.headers['content-type'] == "application/json+cesr" + res = client.simulate_get(f"/registries/{registry.regk}/{saids[0]}") + assert res.status_code == 200 + assert res.json == {'vn': [1, 0], 'i': 'EIO9uC3K6MvyjFD-RB3RYW3dfL49kCyz3OPqv3gi1dek', 's': '0', + 'd': 'EBVaw6pCqfMIiZGkA6qevzRUGsxTRuZXxl6YG1neeCGF', 'ri': 'EACehJRd0wfteUAJgaTTJjMSaQqWvzeeHqAMMqxuqxU4', + 'ra': {}, 'a': {'s': 3, 'd': 'EO_rknKiU14E0I-rN6yttRE0OSDKaQpVSozAcghjS4dj'}, + 'dt': '2021-06-27T21:26:21.233257+00:00', 'et': 'iss'} + + res = client.simulate_get(f"/registries/{registry.regk}/EDqDrGuzned0HOKFTLqd7m7O7WGE5zYIOHrlCq4EnWxy") + assert res.status_code == 404 + assert res.json == {'description': f"credential EDqDrGuzned0HOKFTLqd7m7O7WGE5zYIOHrlCq4EnWxy not found in registry EACehJRd0wfteUAJgaTTJjMSaQqWvzeeHqAMMqxuqxU4", + 'title': '404 Not Found'} + + res = client.simulate_get(f"/registries/EBVaw6pCqfMIiZGkA6qevzRUGsxTRuZXxl6YG1neeCGF/{saids[0]}") + assert res.status_code == 404 + assert res.json == {'description': f"registry EBVaw6pCqfMIiZGkA6qevzRUGsxTRuZXxl6YG1neeCGF not found", + 'title': '404 Not Found'} + def test_revoke_credential(helpers, seeder): with helpers.openKeria() as (agency, agent, app, client): @@ -489,6 +508,8 @@ def test_revoke_credential(helpers, seeder): app.add_route("/identifiers/{name}/credentials/{said}", credResDelEnd) credResEnd = credentialing.CredentialQueryCollectionEnd() app.add_route("/credentials/query", credResEnd) + credentialRegistryResEnd = credentialing.CredentialRegistryResourceEnd() + app.add_route("/registries/{ri}/{vci}", credentialRegistryResEnd) seeder.seedSchema(agent.hby.db) @@ -635,3 +656,8 @@ def test_revoke_credential(helpers, seeder): assert len(res.json) == 1 assert res.json[0]['sad']['d'] == creder.said assert res.json[0]['status']['s'] == "1" + + res = client.simulate_get(f"/registries/{registry["regk"]}/{creder.said}") + assert res.status_code == 200 + assert res.json["s"] == "1" + assert res.json["et"] == "rev"