From be2412a7f50368f9279b5bbca75caf375fb1549d Mon Sep 17 00:00:00 2001 From: Matthias Binzer Date: Wed, 30 Mar 2022 13:14:11 +0200 Subject: [PATCH 1/8] Allow deleting a pres exchange item without reading it first Related to #1687 this allows deleting a presentation exchange record without reading it from storage. Signed-off-by: Matthias Binzer --- aries_cloudagent/protocols/present_proof/v2_0/routes.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aries_cloudagent/protocols/present_proof/v2_0/routes.py b/aries_cloudagent/protocols/present_proof/v2_0/routes.py index 8d24d1afe4..211fca5488 100644 --- a/aries_cloudagent/protocols/present_proof/v2_0/routes.py +++ b/aries_cloudagent/protocols/present_proof/v2_0/routes.py @@ -34,6 +34,8 @@ from ....storage.error import StorageError, StorageNotFoundError from ....storage.vc_holder.base import VCHolder from ....storage.vc_holder.vc_record import VCRecord +from ....storage.record import StorageRecord +from ....storage.base import BaseStorage from ....utils.tracing import trace_event, get_timer, AdminAPIMessageTracingSchema from ....vc.ld_proofs import BbsBlsSignature2020, Ed25519Signature2018 from ....wallet.error import WalletNotFoundError @@ -1234,8 +1236,10 @@ async def present_proof_remove(request: web.BaseRequest): pres_ex_record = None try: async with context.profile.session() as session: - pres_ex_record = await V20PresExRecord.retrieve_by_id(session, pres_ex_id) - await pres_ex_record.delete_record(session) + storage = session.inject(BaseStorage) + storage_record = StorageRecord(type=V20PresExRecord.RECORD_TYPE, value=None, id=pres_ex_id) + await storage.delete_record(storage_record) + except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err except StorageError as err: From 17c499024df7817bc2f908c2b60a2c7121b68923 Mon Sep 17 00:00:00 2001 From: Shaanjot Gill Date: Thu, 31 Mar 2022 15:53:14 -0700 Subject: [PATCH 2/8] minor updates Signed-off-by: Shaanjot Gill --- .../messaging/models/base_record.py | 7 +++++-- .../models/tests/test_base_record.py | 21 +++++++++++++++++++ .../protocols/present_proof/v2_0/routes.py | 14 +++++++++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/aries_cloudagent/messaging/models/base_record.py b/aries_cloudagent/messaging/models/base_record.py index 44ed51e4fe..35f77baf8e 100644 --- a/aries_cloudagent/messaging/models/base_record.py +++ b/aries_cloudagent/messaging/models/base_record.py @@ -19,7 +19,7 @@ from ..util import datetime_to_str, time_now from ..valid import INDY_ISO8601_DATETIME -from .base import BaseModel, BaseModelSchema +from .base import BaseModel, BaseModelSchema, BaseModelError LOGGER = logging.getLogger(__name__) @@ -329,7 +329,10 @@ async def query( positive=False, alt=alt, ): - result.append(cls.from_storage(record.id, vals)) + try: + result.append(cls.from_storage(record.id, vals)) + except BaseModelError as err: + raise BaseModelError(f"{err}, for record id {record.id}") return result async def save( diff --git a/aries_cloudagent/messaging/models/tests/test_base_record.py b/aries_cloudagent/messaging/models/tests/test_base_record.py index 4caf5dc3d6..87749e2df8 100644 --- a/aries_cloudagent/messaging/models/tests/test_base_record.py +++ b/aries_cloudagent/messaging/models/tests/test_base_record.py @@ -12,6 +12,7 @@ StorageError, StorageRecord, ) +from ....messaging.models.base import BaseModelError from ...util import time_now @@ -181,6 +182,26 @@ async def test_query(self): assert result[0]._id == record_id assert result[0].value == record_value + async def test_query_x(self): + session = InMemoryProfile.test_session() + mock_storage = async_mock.MagicMock(BaseStorage, autospec=True) + session.context.injector.bind_instance(BaseStorage, mock_storage) + record_id = "record_id" + record_value = {"created_at": time_now(), "updated_at": time_now()} + tag_filter = {"tag": "filter"} + stored = StorageRecord( + BaseRecordImpl.RECORD_TYPE, json.dumps(record_value), {}, record_id + ) + + mock_storage.find_all_records.return_value = [stored] + with async_mock.patch.object( + BaseRecordImpl, + "from_storage", + async_mock.MagicMock(side_effect=BaseModelError), + ): + with self.assertRaises(BaseModelError): + await BaseRecordImpl.query(session, tag_filter) + async def test_query_post_filter(self): session = InMemoryProfile.test_session() mock_storage = async_mock.MagicMock(BaseStorage, autospec=True) diff --git a/aries_cloudagent/protocols/present_proof/v2_0/routes.py b/aries_cloudagent/protocols/present_proof/v2_0/routes.py index a74b9203d4..115bf09d08 100644 --- a/aries_cloudagent/protocols/present_proof/v2_0/routes.py +++ b/aries_cloudagent/protocols/present_proof/v2_0/routes.py @@ -32,6 +32,7 @@ UUID4, ) from ....storage.error import StorageError, StorageNotFoundError +from ....storage.base import BaseStorage from ....storage.vc_holder.base import VCHolder from ....storage.vc_holder.vc_record import VCRecord from ....utils.tracing import trace_event, get_timer, AdminAPIMessageTracingSchema @@ -1265,8 +1266,17 @@ async def present_proof_remove(request: web.BaseRequest): pres_ex_record = None try: async with context.profile.session() as session: - pres_ex_record = await V20PresExRecord.retrieve_by_id(session, pres_ex_id) - await pres_ex_record.delete_record(session) + try: + pres_ex_record = await V20PresExRecord.retrieve_by_id( + session, pres_ex_id + ) + await pres_ex_record.delete_record(session) + except (BaseModelError, ValidationError): + storage = session.inject(BaseStorage) + storage_record = await storage.get_record( + record_type=V20PresExRecord.RECORD_TYPE, record_id=pres_ex_id + ) + await storage.delete_record(storage_record) except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err except StorageError as err: From 6f905093fb28b20568887596e82627d6f4fec543 Mon Sep 17 00:00:00 2001 From: Shaanjot Gill Date: Thu, 31 Mar 2022 16:27:21 -0700 Subject: [PATCH 3/8] cleanup from conflict resolve Signed-off-by: Shaanjot Gill --- aries_cloudagent/protocols/present_proof/v2_0/routes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/aries_cloudagent/protocols/present_proof/v2_0/routes.py b/aries_cloudagent/protocols/present_proof/v2_0/routes.py index 20aa183a47..115bf09d08 100644 --- a/aries_cloudagent/protocols/present_proof/v2_0/routes.py +++ b/aries_cloudagent/protocols/present_proof/v2_0/routes.py @@ -35,8 +35,6 @@ from ....storage.base import BaseStorage from ....storage.vc_holder.base import VCHolder from ....storage.vc_holder.vc_record import VCRecord -from ....storage.record import StorageRecord -from ....storage.base import BaseStorage from ....utils.tracing import trace_event, get_timer, AdminAPIMessageTracingSchema from ....vc.ld_proofs import BbsBlsSignature2020, Ed25519Signature2018 from ....wallet.error import WalletNotFoundError From 34d0913c236d912a3b7a287f317750579ba4330d Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Thu, 7 Apr 2022 07:28:03 -0700 Subject: [PATCH 4/8] Adds support to faber demo for returning json response in connectionless proof request Signed-off-by: Akiff Manji --- demo/runners/faber.py | 10 +++------- demo/runners/support/agent.py | 4 +++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/demo/runners/faber.py b/demo/runners/faber.py index d7e7ce6ab5..99af10a9f6 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -608,14 +608,10 @@ async def main(args): ) pres_req_id = proof_request["presentation_exchange_id"] url = ( - "http://" - + os.getenv("DOCKERHOST").replace( - "{PORT}", str(faber_agent.agent.admin_port + 1) - ) - + "/webhooks/pres_req/" - + pres_req_id - + "/" + os.getenv("WEBHOOK_TARGET") + or ("http://" + os.getenv("DOCKERHOST").replace("{PORT}", str(faber_agent.agent.admin_port + 1)) + "/webhooks") ) + + f"/pres_req/{pres_req_id}/" log_msg(f"Proof request url: {url}") qr = QRCode(border=1) qr.add_data(url) diff --git a/demo/runners/support/agent.py b/demo/runners/support/agent.py index 2a8cf1ddb5..5300cc9ffd 100644 --- a/demo/runners/support/agent.py +++ b/demo/runners/support/agent.py @@ -715,7 +715,7 @@ async def listen_webhooks(self, webhook_port): if RUN_MODE == "pwd": self.webhook_url = f"http://localhost:{str(webhook_port)}/webhooks" else: - self.webhook_url = ( + self.webhook_url = self.external_webhook_target or ( f"http://{self.external_host}:{str(webhook_port)}/webhooks" ) app = web.Application() @@ -764,6 +764,8 @@ async def _send_connectionless_proof_req(self, request: ClientRequest): return web.Response(status=404) proof_reg_txn = proof_exch["presentation_request_dict"] proof_reg_txn["~service"] = await self.service_decorator() + if request.headers['Accept'] == 'application/json': + return web.json_response(proof_reg_txn) objJsonStr = json.dumps(proof_reg_txn) objJsonB64 = base64.b64encode(objJsonStr.encode("ascii")) service_url = self.webhook_url From 24bfbab095d52d420c7f32a872829a713867785a Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Thu, 7 Apr 2022 07:47:15 -0700 Subject: [PATCH 5/8] Format code Signed-off-by: Akiff Manji --- demo/runners/faber.py | 11 +++++++---- demo/runners/support/agent.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/demo/runners/faber.py b/demo/runners/faber.py index 99af10a9f6..ba46d9eec0 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -607,11 +607,14 @@ async def main(args): "/present-proof/create-request", proof_request_web_request ) pres_req_id = proof_request["presentation_exchange_id"] - url = ( - os.getenv("WEBHOOK_TARGET") - or ("http://" + os.getenv("DOCKERHOST").replace("{PORT}", str(faber_agent.agent.admin_port + 1)) + "/webhooks") + url = os.getenv("WEBHOOK_TARGET") or ( + "http://" + + os.getenv("DOCKERHOST").replace( + "{PORT}", str(faber_agent.agent.admin_port + 1) + ) + + "/webhooks" ) - + f"/pres_req/{pres_req_id}/" + +f"/pres_req/{pres_req_id}/" log_msg(f"Proof request url: {url}") qr = QRCode(border=1) qr.add_data(url) diff --git a/demo/runners/support/agent.py b/demo/runners/support/agent.py index cd2af724c8..abf3e7fd6e 100644 --- a/demo/runners/support/agent.py +++ b/demo/runners/support/agent.py @@ -769,7 +769,7 @@ async def _send_connectionless_proof_req(self, request: ClientRequest): return web.Response(status=404) proof_reg_txn = proof_exch["presentation_request_dict"] proof_reg_txn["~service"] = await self.service_decorator() - if request.headers['Accept'] == 'application/json': + if request.headers["Accept"] == "application/json": return web.json_response(proof_reg_txn) objJsonStr = json.dumps(proof_reg_txn) objJsonB64 = base64.b64encode(objJsonStr.encode("ascii")) From b69587a69f2c9852bc378c71a56f5b2f04a03aad Mon Sep 17 00:00:00 2001 From: Akiff Manji Date: Mon, 11 Apr 2022 11:28:06 -0700 Subject: [PATCH 6/8] Fix formatting issue on webhook url Signed-off-by: Akiff Manji --- demo/runners/faber.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/demo/runners/faber.py b/demo/runners/faber.py index ba46d9eec0..1d127cefcb 100644 --- a/demo/runners/faber.py +++ b/demo/runners/faber.py @@ -607,14 +607,17 @@ async def main(args): "/present-proof/create-request", proof_request_web_request ) pres_req_id = proof_request["presentation_exchange_id"] - url = os.getenv("WEBHOOK_TARGET") or ( - "http://" - + os.getenv("DOCKERHOST").replace( - "{PORT}", str(faber_agent.agent.admin_port + 1) + url = ( + os.getenv("WEBHOOK_TARGET") + or ( + "http://" + + os.getenv("DOCKERHOST").replace( + "{PORT}", str(faber_agent.agent.admin_port + 1) + ) + + "/webhooks" ) - + "/webhooks" + + f"/pres_req/{pres_req_id}/" ) - +f"/pres_req/{pres_req_id}/" log_msg(f"Proof request url: {url}") qr = QRCode(border=1) qr.add_data(url) From 9e43317ba96a4e12a336849975e472a0dec6f5d6 Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Mon, 11 Apr 2022 14:39:17 -0700 Subject: [PATCH 7/8] Use provided connection_id if provided Signed-off-by: Ian Costanzo --- aries_cloudagent/wallet/routes.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/aries_cloudagent/wallet/routes.py b/aries_cloudagent/wallet/routes.py index a7772be595..1c23f01fbd 100644 --- a/aries_cloudagent/wallet/routes.py +++ b/aries_cloudagent/wallet/routes.py @@ -441,7 +441,12 @@ async def wallet_set_public_did(request: web.BaseRequest): info: DIDInfo = None try: info, attrib_def = await promote_wallet_public_did( - context.profile, context, context.session, did, write_ledger=write_ledger + context.profile, + context, + context.session, + did, + write_ledger=write_ledger, + connection_id=connection_id, ) except LookupError as err: raise web.HTTPNotFound(reason=str(err)) from err @@ -487,6 +492,7 @@ async def promote_wallet_public_did( session_fn, did: str, write_ledger: bool = False, + connection_id: str = None, ) -> DIDInfo: """Promote supplied DID to the wallet public DID.""" @@ -512,7 +518,8 @@ async def promote_wallet_public_did( write_ledger = False # author has not provided a connection id, so determine which to use - connection_id = await get_endorser_connection_id(context.profile) + if not connection_id: + connection_id = await get_endorser_connection_id(context.profile) if not connection_id: raise web.HTTPBadRequest(reason="No endorser connection found") @@ -785,10 +792,12 @@ async def on_register_nym_event(profile: Profile, event: Event): if is_author_role(profile) and profile.context.settings.get_value( "endorser.auto_promote_author_did" ): + print(">>> payload =", event.payload) did = event.payload["did"] + connection_id = event.payload.get("connection_id") try: await promote_wallet_public_did( - profile, profile.context, profile.session, did + profile, profile.context, profile.session, did, connection_id ) except Exception: # log the error, but continue From 9296ff35a78a14c9f643d1d0cfa991f0b98115b1 Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Tue, 12 Apr 2022 09:56:14 -0700 Subject: [PATCH 8/8] Remove debugging Signed-off-by: Ian Costanzo --- aries_cloudagent/wallet/routes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aries_cloudagent/wallet/routes.py b/aries_cloudagent/wallet/routes.py index 1c23f01fbd..0acff9d4cc 100644 --- a/aries_cloudagent/wallet/routes.py +++ b/aries_cloudagent/wallet/routes.py @@ -792,7 +792,6 @@ async def on_register_nym_event(profile: Profile, event: Event): if is_author_role(profile) and profile.context.settings.get_value( "endorser.auto_promote_author_did" ): - print(">>> payload =", event.payload) did = event.payload["did"] connection_id = event.payload.get("connection_id") try: