From 4ad8a932bf9b9165edfa660b02ed59df5efbae24 Mon Sep 17 00:00:00 2001 From: Rodolfo Miranda Date: Fri, 29 Mar 2024 15:29:46 -0300 Subject: [PATCH 1/4] IdentifierResourceEnd changes --- src/keria/app/aiding.py | 61 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/src/keria/app/aiding.py b/src/keria/app/aiding.py index c2e8625b..6495d5c1 100644 --- a/src/keria/app/aiding.py +++ b/src/keria/app/aiding.py @@ -31,6 +31,7 @@ def loadEnds(app, agency, authn): app.add_route("/identifiers", aidsEnd) aidEnd = IdentifierResourceEnd() app.add_route("/identifiers/{name}", aidEnd) + app.add_route("/identifiers/{name}/events", aidEnd) aidOOBIsEnd = IdentifierOOBICollectionEnd() app.add_route("/identifiers/{name}/oobis", aidOOBIsEnd) @@ -456,7 +457,54 @@ def on_get(req, rep, name): rep.data = json.dumps(data).encode("utf-8") def on_put(self, req, rep, name): - """ Identifier UPDATE endpoint + """ Identifier rename endpoint + + Parameters: + req (Request): falcon.Request HTTP request object + rep (Response): falcon.Response HTTP response object + name (str): human readable name for Hab to rename + + """ + if not name: + raise falcon.HTTPBadRequest(description="name is required") + agent = req.context.agent + hab = agent.hby.habByName(name) + + if hab is None: + raise falcon.HTTPNotFound(title=f"No AID with name {name} found") + body = req.get_media() + newName = body.get("name") + habord = hab.db.habs.get(keys=name) + hab.db.habs.put(keys=newName, + val=habord) + hab.db.habs.rem(keys=name) + hab.name = newName + hab = agent.hby.habByName(newName) + data = info(hab, agent.mgr, full=True) + rep.status = falcon.HTTP_200 + rep.content_type = "application/json" + rep.data = json.dumps(data).encode("utf-8") + + def on_delete(self, req, rep, name): + """ Identifier delete endpoint + + Parameters: + req (Request): falcon.Request HTTP request object + rep (Response): falcon.Response HTTP response object + name (str): human readable name for Hab to delete + + """ + if not name: + raise falcon.HTTPBadRequest(description="name is required") + agent = req.context.agent + hab = agent.hby.habByName(name) + if hab is None: + raise falcon.HTTPNotFound(title=f"No AID with name {name} found") + hab.db.habs.rem(keys=name) + rep.status = falcon.HTTP_200 + + def on_post(self, req, rep, name): + """ Identifier events endpoint Parameters: req (Request): falcon.Request HTTP request object @@ -464,15 +512,18 @@ def on_put(self, req, rep, name): name (str): human readable name for Hab to rotate or interact """ + if not name: + raise falcon.HTTPBadRequest(description="name is required") agent = req.context.agent try: body = req.get_media() - typ = Ilks.ixn if req.params.get("type") == "ixn" else Ilks.rot - - if typ in (Ilks.rot,): + if body.get("rot") is not None: op = self.rotate(agent, name, body) - else: + elif body.get("ixn") is not None: op = self.interact(agent, name, body) + else: + raise falcon.HTTPBadRequest(title="invalid request", + description=f"required field 'rot' or 'ixn' missing from request") rep.status = falcon.HTTP_200 rep.content_type = "application/json" From b42309fbd9be0c0e4b191dc45fb4b9401a51eb09 Mon Sep 17 00:00:00 2001 From: Rodolfo Miranda Date: Fri, 29 Mar 2024 16:39:54 -0300 Subject: [PATCH 2/4] fix tests --- tests/app/test_aiding.py | 27 +++++++++++++++------------ tests/app/test_specing.py | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/app/test_aiding.py b/tests/app/test_aiding.py index 15f84477..7920248b 100644 --- a/tests/app/test_aiding.py +++ b/tests/app/test_aiding.py @@ -252,6 +252,7 @@ def test_identifier_collection_end(helpers): resend = aiding.IdentifierResourceEnd() app.add_route("/identifiers", end) app.add_route("/identifiers/{name}", resend) + app.add_route("/identifiers/{name}/events", resend) groupEnd = aiding.GroupMemberCollectionEnd() app.add_route("/identifiers/{name}/members", groupEnd) @@ -365,7 +366,7 @@ def test_identifier_collection_end(helpers): 'salty': {'stem': 'signify:aid', 'pidx': 0, 'tier': 'low', 'sxlt': sxlt, 'transferable': True, 'kidx': 1, 'icodes': [MtrDex.Ed25519_Seed], 'ncodes': [MtrDex.Ed25519_Seed]} } - res = client.simulate_put(path="/identifiers/aid1", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/aid1/events", body=json.dumps(body)) assert res.status_code == 200 # Try with missing arguments @@ -470,7 +471,7 @@ def test_identifier_collection_end(helpers): 'salty': {'stem': 'signify:aid', 'pidx': 0, 'tier': 'low', 'sxlt': sxlt, 'transferable': True, 'kidx': 3, 'icodes': [MtrDex.Ed25519_Seed], 'ncodes': [MtrDex.Ed25519_Seed]} } - res = client.simulate_put(path="/identifiers/aid3", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/aid3/events", body=json.dumps(body)) assert res.status_code == 200 # create member habs for group AID @@ -654,6 +655,7 @@ def test_identifier_collection_end(helpers): resend = aiding.IdentifierResourceEnd() app.add_route("/identifiers", end) app.add_route("/identifiers/{name}", resend) + app.add_route("/identifiers/{name}/events", resend) eventsEnd = agenting.KeyEventCollectionEnd() app.add_route("/events", eventsEnd) @@ -722,7 +724,7 @@ def test_identifier_collection_end(helpers): "transferable": True, } } - res = client.simulate_put(path="/identifiers/randy1", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randy1/events", body=json.dumps(body)) assert res.status_code == 200 assert res.json["response"] == serder.ked res = client.simulate_get(path="/identifiers") @@ -740,7 +742,7 @@ def test_identifier_collection_end(helpers): body = {'ixn': serder.ked, 'sigs': sigers } - res = client.simulate_put(path="/identifiers/randy1?type=ixn", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randy1/events", body=json.dumps(body)) assert res.status_code == 200 assert res.json["response"] == serder.ked @@ -751,17 +753,17 @@ def test_identifier_collection_end(helpers): assert events[2] == serder.ked # Bad interactions - res = client.simulate_put(path="/identifiers/badrandy?type=ixn", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/badrandy/events", body=json.dumps(body)) assert res.status_code == 404 assert res.json == {'title': 'No AID badrandy found'} body = {'sigs': sigers} - res = client.simulate_put(path="/identifiers/randy1?type=ixn", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randy1/events", body=json.dumps(body)) assert res.status_code == 400 - assert res.json == {'description': "required field 'ixn' missing from request", 'title': 'invalid interaction'} + assert res.json == {'description': "required field 'rot' or 'ixn' missing from request", 'title': 'invalid request'} body = {'ixn': serder.ked} - res = client.simulate_put(path="/identifiers/randy1?type=ixn", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randy1/events", body=json.dumps(body)) assert res.status_code == 400 assert res.json == {'description': "required field 'sigs' missing from request", 'title': 'invalid interaction'} @@ -774,7 +776,7 @@ def test_identifier_collection_end(helpers): "transferable": True, } } - res = client.simulate_put(path="/identifiers/randybad?type=rot", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randybad/events", body=json.dumps(body)) assert res.status_code == 404 assert res.json == {'title': 'No AID with name randybad found'} @@ -786,9 +788,9 @@ def test_identifier_collection_end(helpers): "transferable": True, } } - res = client.simulate_put(path="/identifiers/randy1", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randy1/events", body=json.dumps(body)) assert res.status_code == 400 - assert res.json == {'description': "required field 'rot' missing from request", 'title': 'invalid rotation'} + assert res.json == {'description': "required field 'rot' or 'ixn' missing from request", 'title': 'invalid request'} # rotate to unknown witness serder = eventing.rotate(keys=keys, @@ -812,7 +814,7 @@ def test_identifier_collection_end(helpers): "transferable": True, } } - res = client.simulate_put(path="/identifiers/randy1", body=json.dumps(body)) + res = client.simulate_post(path="/identifiers/randy1/events", body=json.dumps(body)) assert res.status_code == 400 assert res.json == {'description': "unknown witness EJJR2nmwyYAZAoTNZH3ULvaU6Z-i0d8fSVPzhzS6b5CM", 'title': '400 Bad Request'} @@ -823,6 +825,7 @@ def test_identifier_collection_end(helpers): resend = aiding.IdentifierResourceEnd() app.add_route("/identifiers", end) app.add_route("/identifiers/{name}", resend) + app.add_route("/identifiers/{name}/events", resend) eventsEnd = agenting.KeyEventCollectionEnd() app.add_route("/events", eventsEnd) diff --git a/tests/app/test_specing.py b/tests/app/test_specing.py index 134cb337..77115bd1 100644 --- a/tests/app/test_specing.py +++ b/tests/app/test_specing.py @@ -46,7 +46,7 @@ def test_spec_resource(helpers): js = json.dumps(sd) print(js) # Assert on the entire JSON to ensure we are getting all the docs - assert js == """{"paths": {"/operations": {"get": {"summary": "Get list of long running operations", "parameters": [{"in": "query", "name": "type", "schema": {"type": "string"}, "required": false, "description": "filter list of long running operations by type"}], "responses": {"200": {"content": {"application/json": {"schema": {"type": "array"}}}}}}}, "/oobis": {"post": {"summary": "Resolve OOBI and assign an alias for the remote identifier", "description": "Resolve OOBI URL or `rpy` message by process results of request and assign 'alias' in contact data for resolved identifier", "tags": ["OOBIs"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "OOBI", "properties": {"oobialias": {"type": "string", "description": "alias to assign to the identifier resolved from this OOBI", "required": false}, "url": {"type": "string", "description": "URL OOBI"}, "rpy": {"type": "object", "description": "unsigned KERI `rpy` event message with endpoints"}}}}}}, "responses": {"202": {"description": "OOBI resolution to key state successful"}}}}, "/states": {"get": {"summary": "Display key event log (KEL) for given identifier prefix", "description": "If provided qb64 identifier prefix is in Kevers, return the current state of the identifier along with the KEL and all associated signatures and receipts", "tags": ["Key Event Log"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of KEL to load"}], "responses": {"200": {"description": "Key event log and key state of identifier"}, "404": {"description": "Identifier not found in Key event database"}}}}, "/events": {"get": {"summary": "Display key event log (KEL) for given identifier prefix", "description": "If provided qb64 identifier prefix is in Kevers, return the current state of the identifier along with the KEL and all associated signatures and receipts", "tags": ["Key Event Log"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of KEL to load"}], "responses": {"200": {"description": "Key event log and key state of identifier"}, "404": {"description": "Identifier not found in Key event database"}}}}, "/queries": {"post": {"summary": "Display key event log (KEL) for given identifier prefix", "description": "If provided qb64 identifier prefix is in Kevers, return the current state of the identifier along with the KEL and all associated signatures and receipts", "tags": ["Query"], "parameters": [{"in": "body", "name": "pre", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of KEL to load"}], "responses": {"200": {"description": "Key event log and key state of identifier"}, "404": {"description": "Identifier not found in Key event database"}}}}, "/identifiers": {"get": {}, "options": {}, "post": {}}, "/challenges": {"get": {"summary": "Get random list of words for a 2 factor auth challenge", "description": "Get the list of identifiers associated with this agent", "tags": ["Challenge/Response"], "parameters": [{"in": "query", "name": "strength", "schema": {"type": "int"}, "description": "cryptographic strength of word list", "required": false}], "responses": {"200": {"description": "An array of random words", "content": {"application/json": {"schema": {"description": "Random word list", "type": "object", "properties": {"words": {"type": "array", "description": "random challenge word list", "items": {"type": "string"}}}}}}}}}}, "/contacts": {"get": {"summary": "Get list of contact information associated with remote identifiers", "description": "Get list of contact information associated with remote identifiers. All information is metadata and kept in local storage only", "tags": ["Contacts"], "parameters": [{"in": "query", "name": "group", "schema": {"type": "string"}, "required": false, "description": "field name to group results by"}, {"in": "query", "name": "filter_field", "schema": {"type": "string"}, "description": "field name to search", "required": false}, {"in": "query", "name": "filter_value", "schema": {"type": "string"}, "description": "value to search for", "required": false}], "responses": {"200": {"description": "List of contact information for remote identifiers"}}}}, "/notifications": {"get": {"summary": "Get list of notifications for the controller of the agent", "description": "Get list of notifications for the controller of the agent. Notifications will be sorted by creation date/time", "parameters": [{"in": "header", "name": "Range", "schema": {"type": "string"}, "required": false, "description": "size of the result list. Defaults to 25"}], "tags": ["Notifications"], "responses": {"200": {"description": "List of contact information for remote identifiers"}}}}, "/oobi": {"get": {}}, "/": {"post": {"summary": "Accept KERI events with attachment headers and parse", "description": "Accept KERI events with attachment headers and parse.", "tags": ["Events"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "description": "KERI event message"}}}}, "responses": {"204": {"description": "KEL EXN, QRY, RPY event accepted."}}}, "put": {"summary": "Accept KERI events with attachment headers and parse", "description": "Accept KERI events with attachment headers and parse.", "tags": ["Events"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "description": "KERI event message"}}}}, "responses": {"200": {"description": "Mailbox query response for server sent events"}, "204": {"description": "KEL or EXN event accepted."}}}}, "/operations/{name}": {"delete": {}, "get": {}}, "/oobis/{alias}": {"get": {"summary": "Get OOBI for specific identifier", "description": "Generate OOBI for the identifier of the specified alias and role", "tags": ["OOBIs"], "parameters": [{"in": "path", "name": "alias", "schema": {"type": "string"}, "required": true, "description": "human readable alias for the identifier generate OOBI for"}, {"in": "query", "name": "role", "schema": {"type": "string"}, "required": true, "description": "role for which to generate OOBI"}], "responses": {"200": {"description": "An array of Identifier key state information", "content": {"application/json": {"schema": {"description": "Key state information for current identifiers", "type": "object"}}}}}}}, "/agent/{caid}": {"get": {}, "put": {}}, "/identifiers/{name}": {"get": {}, "put": {}}, "/endroles/{aid}": {"get": {}, "post": {}}, "/escrows/rpy": {"get": {}}, "/challenges/{name}": {"post": {"summary": "Sign challenge message and forward to peer identifier", "description": "Sign a challenge word list received out of bands and send `exn` peer to peer message to recipient", "tags": ["Challenge/Response"], "parameters": [{"in": "path", "name": "name", "schema": {"type": "string"}, "required": true, "description": "Human readable alias for the identifier to create"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Challenge response", "properties": {"recipient": {"type": "string", "description": "human readable alias recipient identifier to send signed challenge to"}, "words": {"type": "array", "description": "challenge in form of word list", "items": {"type": "string"}}}}}}}, "responses": {"202": {"description": "Success submission of signed challenge/response"}}}}, "/challenges_verify/{source}": {"post": {"summary": "Sign challenge message and forward to peer identifier", "description": "Sign a challenge word list received out of bands and send `exn` peer to peer message to recipient", "tags": ["Challenge/Response"], "parameters": [{"in": "path", "name": "name", "schema": {"type": "string"}, "required": true, "description": "Human readable alias for the identifier to create"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Challenge response", "properties": {"recipient": {"type": "string", "description": "human readable alias recipient identifier to send signed challenge to"}, "words": {"type": "array", "description": "challenge in form of word list", "items": {"type": "string"}}}}}}}, "responses": {"202": {"description": "Success submission of signed challenge/response"}}}, "put": {"summary": "Mark challenge response exn message as signed", "description": "Mark challenge response exn message as signed", "tags": ["Challenge/Response"], "parameters": [{"in": "path", "name": "name", "schema": {"type": "string"}, "required": true, "description": "Human readable alias for the identifier to create"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Challenge response", "properties": {"aid": {"type": "string", "description": "aid of signer of accepted challenge response"}, "said": {"type": "array", "description": "SAID of challenge message signed", "items": {"type": "string"}}}}}}}, "responses": {"202": {"description": "Success submission of signed challenge/response"}}}}, "/contacts/{prefix}": {"delete": {"summary": "Delete contact information associated with remote identifier", "description": "Delete contact information associated with remote identifier", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of contact to delete"}], "responses": {"202": {"description": "Contact information successfully deleted for prefix"}, "404": {"description": "No contact information found for prefix"}}}, "get": {"summary": "Get contact information associated with single remote identifier", "description": "Get contact information associated with single remote identifier. All information is meta-data and kept in local storage only", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of contact to get"}], "responses": {"200": {"description": "Contact information successfully retrieved for prefix"}, "404": {"description": "No contact information found for prefix"}}}, "post": {"summary": "Create new contact information for an identifier", "description": "Creates new information for an identifier, overwriting all existing information for that identifier", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix to add contact metadata to"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Contact information", "type": "object"}}}}, "responses": {"200": {"description": "Updated contact information for remote identifier"}, "400": {"description": "Invalid identifier used to update contact information"}, "404": {"description": "Prefix not found in identifier contact information"}}}, "put": {"summary": "Update provided fields in contact information associated with remote identifier prefix", "description": "Update provided fields in contact information associated with remote identifier prefix. All information is metadata and kept in local storage only", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix to add contact metadata to"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Contact information", "type": "object"}}}}, "responses": {"200": {"description": "Updated contact information for remote identifier"}, "400": {"description": "Invalid identifier used to update contact information"}, "404": {"description": "Prefix not found in identifier contact information"}}}}, "/notifications/{said}": {"delete": {"summary": "Delete notification", "description": "Delete notification", "tags": ["Notifications"], "parameters": [{"in": "path", "name": "said", "schema": {"type": "string"}, "required": true, "description": "qb64 said of note to delete"}], "responses": {"202": {"description": "Notification successfully deleted for prefix"}, "404": {"description": "No notification information found for prefix"}}}, "put": {"summary": "Mark notification as read", "description": "Mark notification as read", "tags": ["Notifications"], "parameters": [{"in": "path", "name": "said", "schema": {"type": "string"}, "required": true, "description": "qb64 said of note to mark as read"}], "responses": {"202": {"description": "Notification successfully marked as read for prefix"}, "404": {"description": "No notification information found for SAID"}}}}, "/oobi/{aid}": {"get": {}}, "/identifiers/{name}/oobis": {"get": {}}, "/identifiers/{name}/endroles": {"get": {}, "post": {}}, "/identifiers/{name}/members": {"get": {}}, "/endroles/{aid}/{role}": {"get": {}, "post": {}}, "/contacts/{prefix}/img": {"get": {"summary": "Get contact image for identifer prefix", "description": "Get contact image for identifer prefix", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of contact image to get"}], "responses": {"200": {"description": "Contact information successfully retrieved for prefix", "content": {"image/jpg": {"schema": {"description": "Image", "type": "binary"}}}}, "404": {"description": "No contact information found for prefix"}}}, "post": {"summary": "Uploads an image to associate with identifier.", "description": "Uploads an image to associate with identifier.", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "description": "identifier prefix to associate image to", "required": true}], "requestBody": {"required": true, "content": {"image/jpg": {"schema": {"type": "string", "format": "binary"}}, "image/png": {"schema": {"type": "string", "format": "binary"}}}}, "responses": {"200": {"description": "Image successfully uploaded"}}}}, "/oobi/{aid}/{role}": {"get": {}}, "/identifiers/{name}/endroles/{role}": {"get": {}, "post": {}}, "/oobi/{aid}/{role}/{eid}": {"get": {}}, "/identifiers/{name}/endroles/{role}/{eid}": {"delete": {}}}, "info": {"title": "KERIA Interactive Web Interface API", "version": "1.0.1"}, "openapi": "3.1.0"}""" + assert js == """{"paths": {"/operations": {"get": {"summary": "Get list of long running operations", "parameters": [{"in": "query", "name": "type", "schema": {"type": "string"}, "required": false, "description": "filter list of long running operations by type"}], "responses": {"200": {"content": {"application/json": {"schema": {"type": "array"}}}}}}}, "/oobis": {"post": {"summary": "Resolve OOBI and assign an alias for the remote identifier", "description": "Resolve OOBI URL or `rpy` message by process results of request and assign 'alias' in contact data for resolved identifier", "tags": ["OOBIs"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "OOBI", "properties": {"oobialias": {"type": "string", "description": "alias to assign to the identifier resolved from this OOBI", "required": false}, "url": {"type": "string", "description": "URL OOBI"}, "rpy": {"type": "object", "description": "unsigned KERI `rpy` event message with endpoints"}}}}}}, "responses": {"202": {"description": "OOBI resolution to key state successful"}}}}, "/states": {"get": {"summary": "Display key event log (KEL) for given identifier prefix", "description": "If provided qb64 identifier prefix is in Kevers, return the current state of the identifier along with the KEL and all associated signatures and receipts", "tags": ["Key Event Log"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of KEL to load"}], "responses": {"200": {"description": "Key event log and key state of identifier"}, "404": {"description": "Identifier not found in Key event database"}}}}, "/events": {"get": {"summary": "Display key event log (KEL) for given identifier prefix", "description": "If provided qb64 identifier prefix is in Kevers, return the current state of the identifier along with the KEL and all associated signatures and receipts", "tags": ["Key Event Log"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of KEL to load"}], "responses": {"200": {"description": "Key event log and key state of identifier"}, "404": {"description": "Identifier not found in Key event database"}}}}, "/queries": {"post": {"summary": "Display key event log (KEL) for given identifier prefix", "description": "If provided qb64 identifier prefix is in Kevers, return the current state of the identifier along with the KEL and all associated signatures and receipts", "tags": ["Query"], "parameters": [{"in": "body", "name": "pre", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of KEL to load"}], "responses": {"200": {"description": "Key event log and key state of identifier"}, "404": {"description": "Identifier not found in Key event database"}}}}, "/identifiers": {"get": {}, "options": {}, "post": {}}, "/challenges": {"get": {"summary": "Get random list of words for a 2 factor auth challenge", "description": "Get the list of identifiers associated with this agent", "tags": ["Challenge/Response"], "parameters": [{"in": "query", "name": "strength", "schema": {"type": "int"}, "description": "cryptographic strength of word list", "required": false}], "responses": {"200": {"description": "An array of random words", "content": {"application/json": {"schema": {"description": "Random word list", "type": "object", "properties": {"words": {"type": "array", "description": "random challenge word list", "items": {"type": "string"}}}}}}}}}}, "/contacts": {"get": {"summary": "Get list of contact information associated with remote identifiers", "description": "Get list of contact information associated with remote identifiers. All information is metadata and kept in local storage only", "tags": ["Contacts"], "parameters": [{"in": "query", "name": "group", "schema": {"type": "string"}, "required": false, "description": "field name to group results by"}, {"in": "query", "name": "filter_field", "schema": {"type": "string"}, "description": "field name to search", "required": false}, {"in": "query", "name": "filter_value", "schema": {"type": "string"}, "description": "value to search for", "required": false}], "responses": {"200": {"description": "List of contact information for remote identifiers"}}}}, "/notifications": {"get": {"summary": "Get list of notifications for the controller of the agent", "description": "Get list of notifications for the controller of the agent. Notifications will be sorted by creation date/time", "parameters": [{"in": "header", "name": "Range", "schema": {"type": "string"}, "required": false, "description": "size of the result list. Defaults to 25"}], "tags": ["Notifications"], "responses": {"200": {"description": "List of contact information for remote identifiers"}}}}, "/oobi": {"get": {}}, "/": {"post": {"summary": "Accept KERI events with attachment headers and parse", "description": "Accept KERI events with attachment headers and parse.", "tags": ["Events"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "description": "KERI event message"}}}}, "responses": {"204": {"description": "KEL EXN, QRY, RPY event accepted."}}}, "put": {"summary": "Accept KERI events with attachment headers and parse", "description": "Accept KERI events with attachment headers and parse.", "tags": ["Events"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "description": "KERI event message"}}}}, "responses": {"200": {"description": "Mailbox query response for server sent events"}, "204": {"description": "KEL or EXN event accepted."}}}}, "/operations/{name}": {"delete": {}, "get": {}}, "/oobis/{alias}": {"get": {"summary": "Get OOBI for specific identifier", "description": "Generate OOBI for the identifier of the specified alias and role", "tags": ["OOBIs"], "parameters": [{"in": "path", "name": "alias", "schema": {"type": "string"}, "required": true, "description": "human readable alias for the identifier generate OOBI for"}, {"in": "query", "name": "role", "schema": {"type": "string"}, "required": true, "description": "role for which to generate OOBI"}], "responses": {"200": {"description": "An array of Identifier key state information", "content": {"application/json": {"schema": {"description": "Key state information for current identifiers", "type": "object"}}}}}}}, "/agent/{caid}": {"get": {}, "put": {}}, "/identifiers/{name}": {"delete": {}, "get": {}, "post": {}, "put": {}}, "/endroles/{aid}": {"get": {}, "post": {}}, "/escrows/rpy": {"get": {}}, "/challenges/{name}": {"post": {"summary": "Sign challenge message and forward to peer identifier", "description": "Sign a challenge word list received out of bands and send `exn` peer to peer message to recipient", "tags": ["Challenge/Response"], "parameters": [{"in": "path", "name": "name", "schema": {"type": "string"}, "required": true, "description": "Human readable alias for the identifier to create"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Challenge response", "properties": {"recipient": {"type": "string", "description": "human readable alias recipient identifier to send signed challenge to"}, "words": {"type": "array", "description": "challenge in form of word list", "items": {"type": "string"}}}}}}}, "responses": {"202": {"description": "Success submission of signed challenge/response"}}}}, "/challenges_verify/{source}": {"post": {"summary": "Sign challenge message and forward to peer identifier", "description": "Sign a challenge word list received out of bands and send `exn` peer to peer message to recipient", "tags": ["Challenge/Response"], "parameters": [{"in": "path", "name": "name", "schema": {"type": "string"}, "required": true, "description": "Human readable alias for the identifier to create"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Challenge response", "properties": {"recipient": {"type": "string", "description": "human readable alias recipient identifier to send signed challenge to"}, "words": {"type": "array", "description": "challenge in form of word list", "items": {"type": "string"}}}}}}}, "responses": {"202": {"description": "Success submission of signed challenge/response"}}}, "put": {"summary": "Mark challenge response exn message as signed", "description": "Mark challenge response exn message as signed", "tags": ["Challenge/Response"], "parameters": [{"in": "path", "name": "name", "schema": {"type": "string"}, "required": true, "description": "Human readable alias for the identifier to create"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Challenge response", "properties": {"aid": {"type": "string", "description": "aid of signer of accepted challenge response"}, "said": {"type": "array", "description": "SAID of challenge message signed", "items": {"type": "string"}}}}}}}, "responses": {"202": {"description": "Success submission of signed challenge/response"}}}}, "/contacts/{prefix}": {"delete": {"summary": "Delete contact information associated with remote identifier", "description": "Delete contact information associated with remote identifier", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of contact to delete"}], "responses": {"202": {"description": "Contact information successfully deleted for prefix"}, "404": {"description": "No contact information found for prefix"}}}, "get": {"summary": "Get contact information associated with single remote identifier", "description": "Get contact information associated with single remote identifier. All information is meta-data and kept in local storage only", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of contact to get"}], "responses": {"200": {"description": "Contact information successfully retrieved for prefix"}, "404": {"description": "No contact information found for prefix"}}}, "post": {"summary": "Create new contact information for an identifier", "description": "Creates new information for an identifier, overwriting all existing information for that identifier", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix to add contact metadata to"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Contact information", "type": "object"}}}}, "responses": {"200": {"description": "Updated contact information for remote identifier"}, "400": {"description": "Invalid identifier used to update contact information"}, "404": {"description": "Prefix not found in identifier contact information"}}}, "put": {"summary": "Update provided fields in contact information associated with remote identifier prefix", "description": "Update provided fields in contact information associated with remote identifier prefix. All information is metadata and kept in local storage only", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix to add contact metadata to"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"description": "Contact information", "type": "object"}}}}, "responses": {"200": {"description": "Updated contact information for remote identifier"}, "400": {"description": "Invalid identifier used to update contact information"}, "404": {"description": "Prefix not found in identifier contact information"}}}}, "/notifications/{said}": {"delete": {"summary": "Delete notification", "description": "Delete notification", "tags": ["Notifications"], "parameters": [{"in": "path", "name": "said", "schema": {"type": "string"}, "required": true, "description": "qb64 said of note to delete"}], "responses": {"202": {"description": "Notification successfully deleted for prefix"}, "404": {"description": "No notification information found for prefix"}}}, "put": {"summary": "Mark notification as read", "description": "Mark notification as read", "tags": ["Notifications"], "parameters": [{"in": "path", "name": "said", "schema": {"type": "string"}, "required": true, "description": "qb64 said of note to mark as read"}], "responses": {"202": {"description": "Notification successfully marked as read for prefix"}, "404": {"description": "No notification information found for SAID"}}}}, "/oobi/{aid}": {"get": {}}, "/identifiers/{name}/events": {"delete": {}, "get": {}, "post": {}, "put": {}}, "/identifiers/{name}/oobis": {"get": {}}, "/identifiers/{name}/endroles": {"get": {}, "post": {}}, "/identifiers/{name}/members": {"get": {}}, "/endroles/{aid}/{role}": {"get": {}, "post": {}}, "/contacts/{prefix}/img": {"get": {"summary": "Get contact image for identifer prefix", "description": "Get contact image for identifer prefix", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "required": true, "description": "qb64 identifier prefix of contact image to get"}], "responses": {"200": {"description": "Contact information successfully retrieved for prefix", "content": {"image/jpg": {"schema": {"description": "Image", "type": "binary"}}}}, "404": {"description": "No contact information found for prefix"}}}, "post": {"summary": "Uploads an image to associate with identifier.", "description": "Uploads an image to associate with identifier.", "tags": ["Contacts"], "parameters": [{"in": "path", "name": "prefix", "schema": {"type": "string"}, "description": "identifier prefix to associate image to", "required": true}], "requestBody": {"required": true, "content": {"image/jpg": {"schema": {"type": "string", "format": "binary"}}, "image/png": {"schema": {"type": "string", "format": "binary"}}}}, "responses": {"200": {"description": "Image successfully uploaded"}}}}, "/oobi/{aid}/{role}": {"get": {}}, "/identifiers/{name}/endroles/{role}": {"get": {}, "post": {}}, "/oobi/{aid}/{role}/{eid}": {"get": {}}, "/identifiers/{name}/endroles/{role}/{eid}": {"delete": {}}}, "info": {"title": "KERIA Interactive Web Interface API", "version": "1.0.1"}, "openapi": "3.1.0"}""" "" \ No newline at end of file From 74f9dea8f42749b15815a6a8db5ef3e47545cac3 Mon Sep 17 00:00:00 2001 From: Rodolfo Miranda Date: Fri, 29 Mar 2024 17:02:05 -0300 Subject: [PATCH 3/4] add rename and delete tests --- tests/app/test_aiding.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/app/test_aiding.py b/tests/app/test_aiding.py index 7920248b..24451ac2 100644 --- a/tests/app/test_aiding.py +++ b/tests/app/test_aiding.py @@ -474,6 +474,19 @@ def test_identifier_collection_end(helpers): res = client.simulate_post(path="/identifiers/aid3/events", body=json.dumps(body)) assert res.status_code == 200 + # rename aid3 + res = client.simulate_put(path="/identifiers/aid3", body=json.dumps({"name": "aid3renamed"})) + assert res.status_code == 200 + aid = res.json + assert aid["name"] == "aid3renamed" + + # delete aid3renamed + res = client.simulate_delete(path="/identifiers/aid3renamed") + assert res.status_code == 200 + res = client.simulate_get(path="/identifiers") + assert res.status_code == 200 + assert len(res.json) == 2 + # create member habs for group AID p1 = p1hby.makeHab(name="p1") assert p1.pre == "EBPtjiAY9ITdvScWFGeeCu3Pf6_CFFr57siQqffVt9Of" @@ -600,8 +613,8 @@ def test_identifier_collection_end(helpers): res = client.simulate_get(path="/identifiers") assert res.status_code == 200 - assert len(res.json) == 4 - aid = res.json[3] + assert len(res.json) == 3 + aid = res.json[2] assert aid["name"] == "multisig" assert aid["prefix"] == serder.pre group = aid["group"] From 0cdcc49182404087bde6700c0aa3b10081372426 Mon Sep 17 00:00:00 2001 From: Rodolfo Miranda Date: Fri, 29 Mar 2024 19:28:00 -0300 Subject: [PATCH 4/4] rebase --- tests/app/test_aiding.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/app/test_aiding.py b/tests/app/test_aiding.py index 24451ac2..63bfdf01 100644 --- a/tests/app/test_aiding.py +++ b/tests/app/test_aiding.py @@ -475,13 +475,13 @@ def test_identifier_collection_end(helpers): assert res.status_code == 200 # rename aid3 - res = client.simulate_put(path="/identifiers/aid3", body=json.dumps({"name": "aid3renamed"})) + res = client.simulate_put(path="/identifiers/aid3", body=json.dumps({"name": "aid3Renamed"})) assert res.status_code == 200 aid = res.json - assert aid["name"] == "aid3renamed" + assert aid["name"] == "aid3Renamed" # delete aid3renamed - res = client.simulate_delete(path="/identifiers/aid3renamed") + res = client.simulate_delete(path="/identifiers/aid3Renamed") assert res.status_code == 200 res = client.simulate_get(path="/identifiers") assert res.status_code == 200