From d1f9f183caa03e26eb04848f60f38a69cdeb3b3a Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Tue, 20 Oct 2020 18:08:51 -0400 Subject: [PATCH 01/27] Override _type in msg models, prevent qualifying Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/util.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/acapy_plugin_toolbox/util.py b/acapy_plugin_toolbox/util.py index 66752092..850b2937 100644 --- a/acapy_plugin_toolbox/util.py +++ b/acapy_plugin_toolbox/util.py @@ -128,6 +128,14 @@ class Model(AgentMessage): __module__ = sys._getframe(2).f_globals['__name__'] __init__ = init if init else generic_init + @property + def _type(self): + """ + Override default _type method to ensure incorrect DIDComm Prefix + is not prepended to all our message types. + """ + return self.Meta.message_type + class Meta: """Generated Meta.""" __qualname__ = name + '.Meta' From 6ba1442e9438e16fb4feabd6d0a31dfd52661c6f Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Tue, 20 Oct 2020 22:00:58 -0400 Subject: [PATCH 02/27] Implement MediationRequestsGetHandler Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/mediator.py | 70 +++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index ae827af4..760d0047 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -1,23 +1,21 @@ -"""Define messages for credential issuer admin protocols.""" +"""Define messages and handlers for mediator admin protocol.""" # pylint: disable=invalid-name # pylint: disable=too-few-public-methods -import asyncio - -from uuid import uuid4 - from marshmallow import fields from aries_cloudagent.config.injection_context import InjectionContext from aries_cloudagent.core.protocol_registry import ProtocolRegistry -from aries_cloudagent.messaging.base_handler import BaseHandler, BaseResponder, RequestContext -from aries_cloudagent.messaging.decorators.attach_decorator import AttachDecorator -from aries_cloudagent.messaging.credential_definitions.util import CRED_DEF_TAGS +from aries_cloudagent.messaging.base_handler import ( + BaseHandler, BaseResponder, RequestContext +) from aries_cloudagent.protocols.routing.v1_0.manager import RoutingManager -from aries_cloudagent.protocols.routing.v1_0.models.route_record import RouteRecord, RouteRecordSchema - -from aries_cloudagent.connections.models.connection_record import ConnectionRecord -from aries_cloudagent.storage.error import StorageNotFoundError +from aries_cloudagent.protocols.routing.v1_0.models.route_record import ( + RouteRecord, RouteRecordSchema +) +from aries_cloudagent.protocols.coordinate_mediation.v1_0.models.mediation_record import ( + MediationRecord, MediationRecordSchema +) from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport from .util import generate_model_schema, admin_only @@ -26,6 +24,9 @@ ROUTES_LIST_GET = '{}/routes_list_get'.format(PROTOCOL) ROUTES_LIST = '{}/routes_list'.format(PROTOCOL) +MEDIATION_REQUESTS_GET = '{}/mediation-requests-get'.format(PROTOCOL) +MEDIATION_REQUESTS = '{}/mediation-requests'.format(PROTOCOL) + MESSAGE_TYPES = { ROUTES_LIST_GET: 'acapy_plugin_toolbox.mediator.RoutesListGet', @@ -43,6 +44,43 @@ async def setup( MESSAGE_TYPES ) +MediationRequestsGet, MediationRequestsGetSchema = generate_model_schema( + name='MediationRequestsGet', + handler='acapy_plugin_toolbox.mediator.MediationRequestsGetHandler', + msg_type=MEDIATION_REQUESTS_GET, + schema={ + 'state': fields.Str(required=True), + 'connection_id': fields.Str(required=False) + } +) + +MediationRequests, MediationRequestsSchema = generate_model_schema( + name='MediationRequests', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=MEDIATION_REQUESTS, + schema={ + 'requests': fields.List(fields.Nested(MediationRecordSchema)) + } +) + + +class MediationRequestsGetHandler(BaseHandler): + """Handler for received mediation requests get messages.""" + + @admin_only + async def handle(self, context: RequestContext, responder: BaseResponder): + """Handle mediation requests get message.""" + tag_filter = dict( + filter(lambda item: item[1] is not None, { + 'state': context.message.state, + 'connection_id': context.message.connection_id + }) + ) + records = MediationRecord.query(context, tag_filter=tag_filter) + response = MediationRequests(requests=records) + response.assign_thread_from(context.message) + await responder.send_reply(response) + RoutesListGet, RoutesListGetSchema = generate_model_schema( name='RoutesListGet', @@ -62,6 +100,11 @@ async def setup( ) +# TODO: Convert this to use coordinate-mediation models +# TODO: Change this to keylists-get as outlined in +# docs/admin-mediator/1.0/README +# TODO: Prefer using RouteRecord directly over using the RoutingManager (it's +# effectively the same thing) class RoutesListHandler(BaseHandler): """Handler for received get cred list request.""" @@ -85,8 +128,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): 'recipient_key': r.recipient_key, 'connection_id': r.connection_id, 'created_at': r.created_at, - - } for r in routes] #await V10PresentationExchange.query(context, {}, post_filter_positive) + } for r in routes] list = RoutesList(results=records) list.assign_thread_from(context.message) await responder.send_reply(list) From 7dbe3622bf1643666078a95b48ecd0b1cbecc72d Mon Sep 17 00:00:00 2001 From: Adam Burdett Date: Wed, 21 Oct 2020 11:25:32 -0600 Subject: [PATCH 03/27] changes needed to load mediation development code Signed-off-by: Adam Burdett --- docker-compose.yml | 1 + requirements.txt | 4 ++-- setup.py | 2 +- startup.sh | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 904afa5b..e5149dc8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,3 +9,4 @@ services: NGROK_NAME: ngrok AGENT_NAME: MyAgent PORT: 3000 + ADMIN_PORT: 3001 diff --git a/requirements.txt b/requirements.txt index 046adcdb..47b7df04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -aries-cloudagent[indy]@git+https://github.com/hyperledger/aries-cloudagent-python@0.5.3 -marshmallow==3.0.0 +aries-cloudagent[indy]@git+https://github.com/dbluhm/aries-cloudagent-python@feature/mediator-coordination +marshmallow==3.5.1 flake8 python-dateutil diff --git a/setup.py b/setup.py index 287f85a2..1945c95a 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def parse_requirements(filename): version='0.1.0', author='Daniel Bluhm , ' 'Sam Curren , ' - 'Adam Burdett ', description='Aries Cloud Agent - Python Plugin for Aries Toolbox', long_description=LONG_DESCRIPTION, diff --git a/startup.sh b/startup.sh index 40f6ee3c..4d18dba4 100644 --- a/startup.sh +++ b/startup.sh @@ -16,4 +16,5 @@ aca-py start \ --debug-credentials \ --debug-presentations \ --enable-undelivered-queue \ + --open-mediation \ "$@" From b179a43681c0d0708c16f18739a7fd04b904ea9a Mon Sep 17 00:00:00 2001 From: Adam Burdett Date: Wed, 21 Oct 2020 14:59:41 -0600 Subject: [PATCH 04/27] start of KeyListsGetHandler Signed-off-by: Adam Burdett --- acapy_plugin_toolbox/mediator.py | 74 ++++++++++++++------------------ 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index 760d0047..f48d5fa0 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -21,15 +21,21 @@ from .util import generate_model_schema, admin_only PROTOCOL = 'https://github.com/hyperledger/aries-toolbox/tree/master/docs/admin-mediator/0.1' -ROUTES_LIST_GET = '{}/routes_list_get'.format(PROTOCOL) -ROUTES_LIST = '{}/routes_list'.format(PROTOCOL) +KEYLISTS_GET = '{}/keylists-get'.format(PROTOCOL) +KEYLISTS = '{}/keylists'.format(PROTOCOL) MEDIATION_REQUESTS_GET = '{}/mediation-requests-get'.format(PROTOCOL) MEDIATION_REQUESTS = '{}/mediation-requests'.format(PROTOCOL) MESSAGE_TYPES = { - ROUTES_LIST_GET: - 'acapy_plugin_toolbox.mediator.RoutesListGet', + MEDIATION_REQUESTS_GET: + 'acapy_plugin_toolbox.mediator.MediationRequestsGet', + MEDIATION_REQUESTS: + 'acapy_plugin_toolbox.mediator.MediationRequests', + KEYLISTS: + 'acapy_plugin_toolbox.mediator.Keylists', + KEYLISTS_GET: + 'acapy_plugin_toolbox.mediator.KeylistsGet', } @@ -37,7 +43,7 @@ async def setup( context: InjectionContext, protocol_registry: ProblemReport = None ): - """Setup the issuer plugin.""" + """Setup the admin-mediator v1_0 plugin.""" if not protocol_registry: protocol_registry = await context.inject(ProtocolRegistry) protocol_registry.register_message_types( @@ -82,53 +88,37 @@ async def handle(self, context: RequestContext, responder: BaseResponder): await responder.send_reply(response) -RoutesListGet, RoutesListGetSchema = generate_model_schema( - name='RoutesListGet', - handler='acapy_plugin_toolbox.mediator.RoutesListHandler', - msg_type=ROUTES_LIST_GET, +KeylistsGet, KeylistsGetSchema = generate_model_schema( + name='KeylistsGet', + handler='acapy_plugin_toolbox.mediator.KeyListsGetHandler', + msg_type=KEYLISTS_GET, schema={ + 'connection_id': fields.Str(required=False) } ) -RoutesList, RoutesListSchema = generate_model_schema( - name='RoutesList', +KeyLists, KeyListsSchema = generate_model_schema( + name='KeyLists', handler='acapy_plugin_toolbox.util.PassHandler', - msg_type=ROUTES_LIST, + msg_type=KEYLISTS, schema={ - 'results': fields.List(fields.Dict()) + 'keylists': fields.List(fields.Nested(RouteRecordSchema)) } ) -# TODO: Convert this to use coordinate-mediation models -# TODO: Change this to keylists-get as outlined in -# docs/admin-mediator/1.0/README -# TODO: Prefer using RouteRecord directly over using the RoutingManager (it's -# effectively the same thing) -class RoutesListHandler(BaseHandler): - """Handler for received get cred list request.""" +class KeyListsGetHandler(BaseHandler): + """Handler for keylist get request.""" @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): - """Handle received get route list request.""" - - mgr = RoutingManager(context) - routes = await mgr.get_routes() # connectionid, recipient key - - # post_filter_positive = dict( - # filter(lambda item: item[1] is not None, { - # # 'state': V10PresentialExchange.STATE_CREDENTIAL_RECEIVED, - # 'role': V10PresentationExchange.ROLE_VERIFIER, - # 'connection_id': context.message.connection_id, - # 'verified': context.message.verified, - # }.items()) - # ) - records = [{ - 'id:': r.record_id, - 'recipient_key': r.recipient_key, - 'connection_id': r.connection_id, - 'created_at': r.created_at, - } for r in routes] - list = RoutesList(results=records) - list.assign_thread_from(context.message) - await responder.send_reply(list) + """Handle received get Keylist get request.""" + tag_filter = dict( + filter(lambda item: item[1] is not None, { + 'connection_id': context.message.connection_id + }) + ) + records = RouteRecord.query(context, tag_filter=tag_filter) + response = KeyLists(requests=records) + response.assign_thread_from(context.message) + await responder.send_reply(response) From 450fe03072cf21e9119a6c8860220562e7960e3d Mon Sep 17 00:00:00 2001 From: Adam Burdett Date: Wed, 21 Oct 2020 15:34:52 -0600 Subject: [PATCH 05/27] F'strin{gs}' instead of format Signed-off-by: Adam Burdett --- acapy_plugin_toolbox/mediator.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index f48d5fa0..4667408a 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -21,11 +21,10 @@ from .util import generate_model_schema, admin_only PROTOCOL = 'https://github.com/hyperledger/aries-toolbox/tree/master/docs/admin-mediator/0.1' -KEYLISTS_GET = '{}/keylists-get'.format(PROTOCOL) -KEYLISTS = '{}/keylists'.format(PROTOCOL) - -MEDIATION_REQUESTS_GET = '{}/mediation-requests-get'.format(PROTOCOL) -MEDIATION_REQUESTS = '{}/mediation-requests'.format(PROTOCOL) +KEYLISTS_GET = f'{PROTOCOL}/keylists-get' +KEYLISTS = f'{PROTOCOL}/keylists' +MEDIATION_REQUESTS_GET = f'{PROTOCOL}/mediation-requests-get' +MEDIATION_REQUESTS = f'{PROTOCOL}/mediation-requests' MESSAGE_TYPES = { MEDIATION_REQUESTS_GET: From b973ef9b8554f7e70826517b9bde314af4b6a669 Mon Sep 17 00:00:00 2001 From: Adam Burdett Date: Wed, 21 Oct 2020 15:56:35 -0600 Subject: [PATCH 06/27] typo fix Signed-off-by: Adam Burdett --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1945c95a..f47171a0 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def parse_requirements(filename): version='0.1.0', author='Daniel Bluhm , ' 'Sam Curren , ' - 'Adam Burdett , ' 'Mike Lodder ', description='Aries Cloud Agent - Python Plugin for Aries Toolbox', long_description=LONG_DESCRIPTION, From 7bd71103979adcd6410072a7b5dfe5d6628f009e Mon Sep 17 00:00:00 2001 From: Adam Burdett Date: Wed, 21 Oct 2020 16:50:09 -0600 Subject: [PATCH 07/27] sendMediationRequestHandler Signed-off-by: Adam Burdett --- acapy_plugin_toolbox/routing.py | 41 +++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index f62dee68..8d3d7b6d 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -8,9 +8,7 @@ from aries_cloudagent.config.injection_context import InjectionContext from aries_cloudagent.core.protocol_registry import ProtocolRegistry -from aries_cloudagent.connections.models.connection_record import ( - ConnectionRecord -) + from aries_cloudagent.messaging.base_handler import ( BaseHandler, BaseResponder, RequestContext ) @@ -21,7 +19,6 @@ BaseRecord, BaseRecordSchema ) from aries_cloudagent.messaging.valid import INDY_ISO8601_DATETIME -from aries_cloudagent.protocols.connections.v1_0.manager import ConnectionManager from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport from aries_cloudagent.storage.error import StorageNotFoundError @@ -29,16 +26,21 @@ from aries_cloudagent.protocols.routing.v1_0.models.route_update import RouteUpdate from aries_cloudagent.protocols.routing.v1_0.messages.route_query_request import RouteQueryRequest +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediation_request import MediationRequest + from .util import ( generate_model_schema, admin_only, timestamp_utc_iso, datetime_from_iso ) ADMIN_PROTOCOL_URI = "https://github.com/hyperledger/" \ "aries-toolbox/tree/master/docs/admin-routing/0.1" + SEND_UPDATE = f"{ADMIN_PROTOCOL_URI}/send_update" +SEND_MEDIATION_REQUEST = f"{ADMIN_PROTOCOL_URI/send_mediation_request}" MESSAGE_TYPES = { SEND_UPDATE: 'acapy_plugin_toolbox.routing.SendUpdate', + SEND_MEDIATION_REQUEST: 'acapy_plugin_toolbox.routing.SendMediationRequest', } @@ -46,7 +48,7 @@ async def setup( context: InjectionContext, protocol_registry: ProblemReport = None ): - """Setup the basicmessage plugin.""" + """Setup the routing plugin.""" if not protocol_registry: protocol_registry = await context.inject(ProtocolRegistry) protocol_registry.register_message_types( @@ -85,3 +87,32 @@ async def handle(self, context: RequestContext, responder: BaseResponder): update_msg, connection_id=context.message.connection_id, ) + + +SendMediationRequest, SendMediationRequestSchema = generate_model_schema( + name='SendMediationRequest', + handler='acapy_plugin_toolbox.routing.SendMediationRequestHandler', + msg_type=SEND_MEDIATION_REQUEST, + schema={ + 'connection_id': fields.Str(required=True), + 'mediator_terms': fields.List(fields.Str(), required=False), + 'recipient_terms': fields.List(fields.Str(), required=False), + } +) + + +class SendMediationRequestHandler(BaseHandler): + """Handler for sending mediation requests.""" + + @admin_only + async def handle(self, context: RequestContext, responder: BaseResponder): + mediation_requests = MediationRequest( + mediator_terms = context.message.mediator_terms, + recipient_terms = context.message.recipient_terms, + ) + + # TODO make sure connection_id is valid, fail gracefully + await responder.send( + mediation_requests, + connection_id=context.message.connection_id, + ) \ No newline at end of file From cc2e47b7f197c38e4d22b7c8c9fd8c724c17c829 Mon Sep 17 00:00:00 2001 From: Adam Burdett Date: Wed, 21 Oct 2020 17:19:49 -0600 Subject: [PATCH 08/27] mediation grant/deny handlers. Signed-off-by: Adam Burdett --- acapy_plugin_toolbox/mediator.py | 40 +++++++++++++++++++++++++------- acapy_plugin_toolbox/routing.py | 4 ++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index 4667408a..f19e779c 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -25,16 +25,22 @@ KEYLISTS = f'{PROTOCOL}/keylists' MEDIATION_REQUESTS_GET = f'{PROTOCOL}/mediation-requests-get' MEDIATION_REQUESTS = f'{PROTOCOL}/mediation-requests' +MEDIATION_GRANT = f'{PROTOCOL}/mediate-grant' +MEDIATION_DENY = f'{PROTOCOL}/mediate-deny' MESSAGE_TYPES = { - MEDIATION_REQUESTS_GET: + MEDIATION_REQUESTS_GET: # get all mediation records 'acapy_plugin_toolbox.mediator.MediationRequestsGet', - MEDIATION_REQUESTS: + MEDIATION_REQUESTS: # return type for get all mediation records for a connection 'acapy_plugin_toolbox.mediator.MediationRequests', - KEYLISTS: + KEYLISTS: # get all keylists used for mediation 'acapy_plugin_toolbox.mediator.Keylists', - KEYLISTS_GET: + KEYLISTS_GET: # return type for get all keylists 'acapy_plugin_toolbox.mediator.KeylistsGet', + MEDIATION_GRANT: # return type for request + 'acapy_plugin_toolbox.mediator.MediationGrant', + MEDIATION_DENY: # return type for request + 'acapy_plugin_toolbox.mediator.MediationDeny', } @@ -89,15 +95,15 @@ async def handle(self, context: RequestContext, responder: BaseResponder): KeylistsGet, KeylistsGetSchema = generate_model_schema( name='KeylistsGet', - handler='acapy_plugin_toolbox.mediator.KeyListsGetHandler', + handler='acapy_plugin_toolbox.mediator.KeylistsGetHandler', msg_type=KEYLISTS_GET, schema={ 'connection_id': fields.Str(required=False) } ) -KeyLists, KeyListsSchema = generate_model_schema( - name='KeyLists', +Keylists, KeylistsSchema = generate_model_schema( + name='Keylists', handler='acapy_plugin_toolbox.util.PassHandler', msg_type=KEYLISTS, schema={ @@ -106,7 +112,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): ) -class KeyListsGetHandler(BaseHandler): +class KeylistsGetHandler(BaseHandler): """Handler for keylist get request.""" @admin_only @@ -121,3 +127,21 @@ async def handle(self, context: RequestContext, responder: BaseResponder): response = KeyLists(requests=records) response.assign_thread_from(context.message) await responder.send_reply(response) + +MediationGrant, MediationGrantSchema = generate_model_schema( + name='MediationGrant', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=MEDIATION_GRANT, + schema={ + 'connection_id': fields.Str(required=False) + } +) + +MediationDeny, MediationDenySchema = generate_model_schema( + name='MediationDeny', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=MEDIATION_DENY, + schema={ + 'connection_id': fields.Str(required=False) + } +) \ No newline at end of file diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index 8d3d7b6d..3620f611 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -26,7 +26,7 @@ from aries_cloudagent.protocols.routing.v1_0.models.route_update import RouteUpdate from aries_cloudagent.protocols.routing.v1_0.messages.route_query_request import RouteQueryRequest -from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediation_request import MediationRequest +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediate_request import MediationRequest from .util import ( generate_model_schema, admin_only, timestamp_utc_iso, datetime_from_iso @@ -36,7 +36,7 @@ "aries-toolbox/tree/master/docs/admin-routing/0.1" SEND_UPDATE = f"{ADMIN_PROTOCOL_URI}/send_update" -SEND_MEDIATION_REQUEST = f"{ADMIN_PROTOCOL_URI/send_mediation_request}" +SEND_MEDIATION_REQUEST = f"{ADMIN_PROTOCOL_URI}/send_mediation_request" MESSAGE_TYPES = { SEND_UPDATE: 'acapy_plugin_toolbox.routing.SendUpdate', From fd0c97e63048d0e10b2ef95ca06595510b555ac9 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 21 Oct 2020 20:06:57 -0400 Subject: [PATCH 09/27] Complete send mediation request handler Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/routing.py | 89 +++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 33 deletions(-) diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index 3620f611..06ba9e92 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -1,46 +1,41 @@ """BasicMessage Plugin.""" # pylint: disable=invalid-name, too-few-public-methods -from typing import Union -from datetime import datetime - from marshmallow import fields +from .util import generate_model_schema, admin_only from aries_cloudagent.config.injection_context import InjectionContext +from aries_cloudagent.connections.models.connection_record import ConnectionRecord from aries_cloudagent.core.protocol_registry import ProtocolRegistry - from aries_cloudagent.messaging.base_handler import ( BaseHandler, BaseResponder, RequestContext ) -from aries_cloudagent.messaging.decorators.localization_decorator import ( - LocalizationDecorator -) -from aries_cloudagent.messaging.models.base_record import ( - BaseRecord, BaseRecordSchema -) -from aries_cloudagent.messaging.valid import INDY_ISO8601_DATETIME +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediate_request import MediationRequest from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport -from aries_cloudagent.storage.error import StorageNotFoundError - +from aries_cloudagent.protocols.routing.v1_0.messages.route_query_request import RouteQueryRequest from aries_cloudagent.protocols.routing.v1_0.messages.route_update_request import RouteUpdateRequest from aries_cloudagent.protocols.routing.v1_0.models.route_update import RouteUpdate -from aries_cloudagent.protocols.routing.v1_0.messages.route_query_request import RouteQueryRequest - -from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediate_request import MediationRequest - -from .util import ( - generate_model_schema, admin_only, timestamp_utc_iso, datetime_from_iso -) +from aries_cloudagent.storage.error import StorageNotFoundError ADMIN_PROTOCOL_URI = "https://github.com/hyperledger/" \ "aries-toolbox/tree/master/docs/admin-routing/0.1" SEND_UPDATE = f"{ADMIN_PROTOCOL_URI}/send_update" -SEND_MEDIATION_REQUEST = f"{ADMIN_PROTOCOL_URI}/send_mediation_request" +MEDIATION_REQUEST_SEND = f"{ADMIN_PROTOCOL_URI}/mediation-request-send" +MEDIATION_REQUEST_SENT = f"{ADMIN_PROTOCOL_URI}/mediation-request-sent" +KEYLIST_UPDATE_SEND = f"{ADMIN_PROTOCOL_URI}/keylist-update-send" +KEYLIST_UPDATE_SENT = f"{ADMIN_PROTOCOL_URI}/keylist-update-sent" +KEYLISTS_GET = f"{ADMIN_PROTOCOL_URI}/keylists-get" +KEYLISTS = f"{ADMIN_PROTOCOL_URI}/keylists" MESSAGE_TYPES = { SEND_UPDATE: 'acapy_plugin_toolbox.routing.SendUpdate', - SEND_MEDIATION_REQUEST: 'acapy_plugin_toolbox.routing.SendMediationRequest', + MEDIATION_REQUEST_SEND: 'acapy_plugin_toolbox.routing.MediationRequestSend', + MEDIATION_REQUEST_SENT: 'acapy_plugin_toolbox.routing.MediationRequestSent', + KEYLIST_UPDATE_SEND: 'acapy_plugin_toolbox.routing.KeylistUpdateSend', + KEYLIST_UPDATE_SENT: 'acapy_plugin_toolbox.routing.KeylistUpdateSent', + KEYLISTS_GET: 'acapy_plugin_toolbox.routing.KeylistsGet', + KEYLISTS: 'acapy_plugin_toolbox.routing.Keylists' } @@ -89,16 +84,24 @@ async def handle(self, context: RequestContext, responder: BaseResponder): ) -SendMediationRequest, SendMediationRequestSchema = generate_model_schema( - name='SendMediationRequest', +MediationRequestSend, MediationRequestSendSchema = generate_model_schema( + name='MediationRequestSend', handler='acapy_plugin_toolbox.routing.SendMediationRequestHandler', - msg_type=SEND_MEDIATION_REQUEST, + msg_type=MEDIATION_REQUEST_SEND, schema={ 'connection_id': fields.Str(required=True), 'mediator_terms': fields.List(fields.Str(), required=False), 'recipient_terms': fields.List(fields.Str(), required=False), } ) +MediationRequestSent, MediationRequestSentSchema = generate_model_schema( + name="MediationRequestSent", + handler="acapy_plugin_toolbox.util.PassHandler", + msg_type=MEDIATION_REQUEST_SENT, + schema={ + 'connection_id': fields.Str(required=True) + } +) class SendMediationRequestHandler(BaseHandler): @@ -106,13 +109,33 @@ class SendMediationRequestHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): - mediation_requests = MediationRequest( - mediator_terms = context.message.mediator_terms, - recipient_terms = context.message.recipient_terms, + # Construct message + mediation_request = MediationRequest( + mediator_terms=context.message.mediator_terms, + recipient_terms=context.message.recipient_terms, ) - - # TODO make sure connection_id is valid, fail gracefully + + # Verify connection exists + try: + connection = await ConnectionRecord.retrieve_by_id( + context, + context.message.connection_id + ) + except StorageNotFoundError: + report = ProblemReport( + explain_ltxt='Connection not found.', + who_retries='none' + ) + report.assign_thread_from(context.message) + await responder.send_reply(report) + + # Send mediation request await responder.send( - mediation_requests, - connection_id=context.message.connection_id, - ) \ No newline at end of file + mediation_request, + connection_id=connection.connection_id, + ) + + # Send notification of mediation request sent + sent = MediationRequestSent(connection_id=connection.connection_id) + sent.assign_thread_from(context.message) + await responder.send_reply(sent) From c3544b423fd12ec07b6715c475ead07f6bacdeb6 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 21 Oct 2020 20:50:57 -0400 Subject: [PATCH 10/27] Reword message types for clarity Change keylists to routes in most places Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/mediator.py | 64 ++++++++++++++++++-------------- acapy_plugin_toolbox/routing.py | 9 ++--- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index f19e779c..40c8eeb5 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -2,6 +2,8 @@ # pylint: disable=invalid-name # pylint: disable=too-few-public-methods +from functools import reduce + from marshmallow import fields from aries_cloudagent.config.injection_context import InjectionContext @@ -21,26 +23,33 @@ from .util import generate_model_schema, admin_only PROTOCOL = 'https://github.com/hyperledger/aries-toolbox/tree/master/docs/admin-mediator/0.1' -KEYLISTS_GET = f'{PROTOCOL}/keylists-get' -KEYLISTS = f'{PROTOCOL}/keylists' +ROUTES_GET = f'{PROTOCOL}/routes-get' +ROUTES = f'{PROTOCOL}/routes' MEDIATION_REQUESTS_GET = f'{PROTOCOL}/mediation-requests-get' MEDIATION_REQUESTS = f'{PROTOCOL}/mediation-requests' MEDIATION_GRANT = f'{PROTOCOL}/mediate-grant' +MEDIATION_GRANTED = f'{PROTOCOL}/mediate-granted' MEDIATION_DENY = f'{PROTOCOL}/mediate-deny' +MEDIATION_DENIED = f'{PROTOCOL}/mediate-denied' MESSAGE_TYPES = { - MEDIATION_REQUESTS_GET: # get all mediation records - 'acapy_plugin_toolbox.mediator.MediationRequestsGet', - MEDIATION_REQUESTS: # return type for get all mediation records for a connection - 'acapy_plugin_toolbox.mediator.MediationRequests', - KEYLISTS: # get all keylists used for mediation - 'acapy_plugin_toolbox.mediator.Keylists', - KEYLISTS_GET: # return type for get all keylists - 'acapy_plugin_toolbox.mediator.KeylistsGet', - MEDIATION_GRANT: # return type for request - 'acapy_plugin_toolbox.mediator.MediationGrant', - MEDIATION_DENY: # return type for request - 'acapy_plugin_toolbox.mediator.MediationDeny', + # get all mediation records + MEDIATION_REQUESTS_GET: 'acapy_plugin_toolbox.mediator.MediationRequestsGet', + + # return type for get all mediation records for a connection + MEDIATION_REQUESTS: 'acapy_plugin_toolbox.mediator.MediationRequests', + + # get all routes used for mediation + ROUTES: 'acapy_plugin_toolbox.mediator.Routes', + + # return type for get all routes + ROUTES_GET: 'acapy_plugin_toolbox.mediator.RoutesGet', + + MEDIATION_GRANT: 'acapy_plugin_toolbox.mediator.MediationGrant', + MEDIATION_GRANTED: 'acapy_plugin_toolbox.mediator.MediationGranted', + + MEDIATION_DENY: 'acapy_plugin_toolbox.mediator.MediationDeny', + MEDIATION_DENIED: 'acapy_plugin_toolbox.mediator.MediationDenied' } @@ -93,41 +102,42 @@ async def handle(self, context: RequestContext, responder: BaseResponder): await responder.send_reply(response) -KeylistsGet, KeylistsGetSchema = generate_model_schema( - name='KeylistsGet', - handler='acapy_plugin_toolbox.mediator.KeylistsGetHandler', - msg_type=KEYLISTS_GET, +RoutesGet, RoutesGetSchema = generate_model_schema( + name='RoutesGet', + handler='acapy_plugin_toolbox.mediator.RoutesGetHandler', + msg_type=ROUTES_GET, schema={ 'connection_id': fields.Str(required=False) } ) -Keylists, KeylistsSchema = generate_model_schema( - name='Keylists', +Routes, RoutesSchema = generate_model_schema( + name='Routes', handler='acapy_plugin_toolbox.util.PassHandler', - msg_type=KEYLISTS, + msg_type=ROUTES, schema={ - 'keylists': fields.List(fields.Nested(RouteRecordSchema)) + 'routes': fields.List(fields.Dict()) } ) -class KeylistsGetHandler(BaseHandler): - """Handler for keylist get request.""" +class RoutesGetHandler(BaseHandler): + """Handler for route get request.""" @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): - """Handle received get Keylist get request.""" + """Handle received get Route get request.""" tag_filter = dict( filter(lambda item: item[1] is not None, { 'connection_id': context.message.connection_id }) ) records = RouteRecord.query(context, tag_filter=tag_filter) - response = KeyLists(requests=records) + response = Routes(routes=records) response.assign_thread_from(context.message) await responder.send_reply(response) + MediationGrant, MediationGrantSchema = generate_model_schema( name='MediationGrant', handler='acapy_plugin_toolbox.util.PassHandler', @@ -144,4 +154,4 @@ async def handle(self, context: RequestContext, responder: BaseResponder): schema={ 'connection_id': fields.Str(required=False) } -) \ No newline at end of file +) diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index 06ba9e92..9274e309 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -12,7 +12,6 @@ ) from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediate_request import MediationRequest from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport -from aries_cloudagent.protocols.routing.v1_0.messages.route_query_request import RouteQueryRequest from aries_cloudagent.protocols.routing.v1_0.messages.route_update_request import RouteUpdateRequest from aries_cloudagent.protocols.routing.v1_0.models.route_update import RouteUpdate from aries_cloudagent.storage.error import StorageNotFoundError @@ -25,8 +24,8 @@ MEDIATION_REQUEST_SENT = f"{ADMIN_PROTOCOL_URI}/mediation-request-sent" KEYLIST_UPDATE_SEND = f"{ADMIN_PROTOCOL_URI}/keylist-update-send" KEYLIST_UPDATE_SENT = f"{ADMIN_PROTOCOL_URI}/keylist-update-sent" -KEYLISTS_GET = f"{ADMIN_PROTOCOL_URI}/keylists-get" -KEYLISTS = f"{ADMIN_PROTOCOL_URI}/keylists" +ROUTES_GET = f"{ADMIN_PROTOCOL_URI}/routes-get" +ROUTES = f"{ADMIN_PROTOCOL_URI}/routes" MESSAGE_TYPES = { SEND_UPDATE: 'acapy_plugin_toolbox.routing.SendUpdate', @@ -34,8 +33,8 @@ MEDIATION_REQUEST_SENT: 'acapy_plugin_toolbox.routing.MediationRequestSent', KEYLIST_UPDATE_SEND: 'acapy_plugin_toolbox.routing.KeylistUpdateSend', KEYLIST_UPDATE_SENT: 'acapy_plugin_toolbox.routing.KeylistUpdateSent', - KEYLISTS_GET: 'acapy_plugin_toolbox.routing.KeylistsGet', - KEYLISTS: 'acapy_plugin_toolbox.routing.Keylists' + ROUTES_GET: 'acapy_plugin_toolbox.routing.RoutesGet', + ROUTES: 'acapy_plugin_toolbox.routing.Routes' } From 14e3b8af254eba00af62eea894798ef1a42bac9a Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Tue, 10 Nov 2020 23:08:33 -0500 Subject: [PATCH 11/27] Mediation and Routing nearly completed Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/mediator.py | 114 ++++++++++++++---- acapy_plugin_toolbox/routing.py | 196 +++++++++++++++++++++++++------ 2 files changed, 248 insertions(+), 62 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index 40c8eeb5..d1f4da0a 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -12,6 +12,7 @@ BaseHandler, BaseResponder, RequestContext ) from aries_cloudagent.protocols.routing.v1_0.manager import RoutingManager +from aries_cloudagent.protocols.coordinate_mediation.v1_0.manager import MediationManager from aries_cloudagent.protocols.routing.v1_0.models.route_record import ( RouteRecord, RouteRecordSchema ) @@ -69,7 +70,7 @@ async def setup( handler='acapy_plugin_toolbox.mediator.MediationRequestsGetHandler', msg_type=MEDIATION_REQUESTS_GET, schema={ - 'state': fields.Str(required=True), + 'state': fields.Str(required=False), 'connection_id': fields.Str(required=False) } ) @@ -93,15 +94,97 @@ async def handle(self, context: RequestContext, responder: BaseResponder): tag_filter = dict( filter(lambda item: item[1] is not None, { 'state': context.message.state, + 'role': MediationRecord.ROLE_SERVER, 'connection_id': context.message.connection_id - }) + }.items()) ) - records = MediationRecord.query(context, tag_filter=tag_filter) + records = await MediationRecord.query(context, tag_filter=tag_filter) response = MediationRequests(requests=records) response.assign_thread_from(context.message) await responder.send_reply(response) +MediationGrant, MediationGrantSchema = generate_model_schema( + name='MediationGrant', + handler='acapy_plugin_toolbox.mediator.MediationGrantHandler', + msg_type=MEDIATION_GRANT, + schema={ + 'mediation_id': fields.Str(required=True) + } +) + + +MediationGranted, MediationGrantedSchema = generate_model_schema( + name='MediationGranted', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=MEDIATION_GRANTED, + schema={ + 'mediation_id': fields.Str(required=True) + } +) + + +class MediationGrantHandler(BaseHandler): + """ + Handler for MediationGrant messages (granting a received mediation + request). + """ + async def handle(self, context: RequestContext, responder: BaseResponder): + """Handle mediation grant request.""" + manager = MediationManager(context) + record = await MediationRecord.retrieve_by_id( + context, context.message.mediation_id + ) + + grant = await manager.grant_request(record) + await responder.send(grant, connection_id=record.connection_id) + + granted = MediationGranted(mediation_id=record.mediation_id) + granted.assign_thread_from(context.message) + await responder.send_reply(granted) + + +MediationDeny, MediationDenySchema = generate_model_schema( + name='MediationDeny', + handler='acapy_plugin_toolbox.mediator.MediationDenyHandler', + msg_type=MEDIATION_DENY, + schema={ + 'mediation_id': fields.Str(required=True) + } +) + + +MediationDenied, MediationDeniedSchema = generate_model_schema( + name='MediationDenied', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=MEDIATION_DENIED, + schema={ + 'mediation_id': fields.Str(required=True) + } +) + + +class MediationDenyHandler(BaseHandler): + """ + Handler for MediationDeny messages (denying a received mediation + request). + """ + + async def handle(self, context: RequestContext, responder: BaseResponder): + """Handle mediation deny request.""" + manager = MediationManager(context) + record = await MediationRecord.retrieve_by_id( + context, context.message.mediation_id + ) + + deny = await manager.deny_request(record) + await responder.send(deny, connection_id=record.connection_id) + + denied = MediationDenied(mediation_id=record.mediation_id) + denied.assign_thread_from(context.message) + await responder.send_reply(denied) + + RoutesGet, RoutesGetSchema = generate_model_schema( name='RoutesGet', handler='acapy_plugin_toolbox.mediator.RoutesGetHandler', @@ -116,7 +199,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): handler='acapy_plugin_toolbox.util.PassHandler', msg_type=ROUTES, schema={ - 'routes': fields.List(fields.Dict()) + 'routes': fields.List(fields.Nested(RouteRecordSchema)) } ) @@ -130,28 +213,9 @@ async def handle(self, context: RequestContext, responder: BaseResponder): tag_filter = dict( filter(lambda item: item[1] is not None, { 'connection_id': context.message.connection_id - }) + }.items()) ) - records = RouteRecord.query(context, tag_filter=tag_filter) + records = await RouteRecord.query(context, tag_filter=tag_filter) response = Routes(routes=records) response.assign_thread_from(context.message) await responder.send_reply(response) - - -MediationGrant, MediationGrantSchema = generate_model_schema( - name='MediationGrant', - handler='acapy_plugin_toolbox.util.PassHandler', - msg_type=MEDIATION_GRANT, - schema={ - 'connection_id': fields.Str(required=False) - } -) - -MediationDeny, MediationDenySchema = generate_model_schema( - name='MediationDeny', - handler='acapy_plugin_toolbox.util.PassHandler', - msg_type=MEDIATION_DENY, - schema={ - 'connection_id': fields.Str(required=False) - } -) diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index 9274e309..de4ed355 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -1,25 +1,38 @@ """BasicMessage Plugin.""" # pylint: disable=invalid-name, too-few-public-methods -from marshmallow import fields - -from .util import generate_model_schema, admin_only from aries_cloudagent.config.injection_context import InjectionContext -from aries_cloudagent.connections.models.connection_record import ConnectionRecord +from aries_cloudagent.connections.models.connection_record import \ + ConnectionRecord from aries_cloudagent.core.protocol_registry import ProtocolRegistry from aries_cloudagent.messaging.base_handler import ( BaseHandler, BaseResponder, RequestContext ) -from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediate_request import MediationRequest -from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport -from aries_cloudagent.protocols.routing.v1_0.messages.route_update_request import RouteUpdateRequest -from aries_cloudagent.protocols.routing.v1_0.models.route_update import RouteUpdate +from aries_cloudagent.protocols.coordinate_mediation.v1_0.manager import MediationManager +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.mediate_request import \ + MediationRequest +from aries_cloudagent.protocols.coordinate_mediation.v1_0.models.mediation_record import ( + MediationRecord, MediationRecordSchema +) +from aries_cloudagent.protocols.routing.v1_0.models.route_record import RouteRecordSchema +from aries_cloudagent.protocols.problem_report.v1_0.message import \ + ProblemReport +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.keylist_update import KeylistUpdate +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.inner.keylist_update_rule import KeylistUpdateRule from aries_cloudagent.storage.error import StorageNotFoundError +from aries_cloudagent.protocols.coordinate_mediation.v1_0.message_types import KEYLIST +from aries_cloudagent.protocols.coordinate_mediation.v1_0.messages.keylist import KeylistSchema +from marshmallow import fields +from marshmallow.validate import OneOf + +from .util import admin_only, generate_model_schema ADMIN_PROTOCOL_URI = "https://github.com/hyperledger/" \ "aries-toolbox/tree/master/docs/admin-routing/0.1" SEND_UPDATE = f"{ADMIN_PROTOCOL_URI}/send_update" +MEDIATION_REQUESTS_GET = f"{ADMIN_PROTOCOL_URI}/mediation-requests-get" +MEDIATION_REQUESTS = f"{ADMIN_PROTOCOL_URI}/mediation-requests" MEDIATION_REQUEST_SEND = f"{ADMIN_PROTOCOL_URI}/mediation-request-send" MEDIATION_REQUEST_SENT = f"{ADMIN_PROTOCOL_URI}/mediation-request-sent" KEYLIST_UPDATE_SEND = f"{ADMIN_PROTOCOL_URI}/keylist-update-send" @@ -28,7 +41,8 @@ ROUTES = f"{ADMIN_PROTOCOL_URI}/routes" MESSAGE_TYPES = { - SEND_UPDATE: 'acapy_plugin_toolbox.routing.SendUpdate', + MEDIATION_REQUESTS_GET: 'acapy_plugin_toolbox.routing.MediationRequestsGet', + MEDIATION_REQUESTS: 'acapy_plugin_toolbox.routing.MediationRequests', MEDIATION_REQUEST_SEND: 'acapy_plugin_toolbox.routing.MediationRequestSend', MEDIATION_REQUEST_SENT: 'acapy_plugin_toolbox.routing.MediationRequestSent', KEYLIST_UPDATE_SEND: 'acapy_plugin_toolbox.routing.KeylistUpdateSend', @@ -50,37 +64,43 @@ async def setup( ) -SendUpdate, SendUpdateSchema = generate_model_schema( - name='SendUpdate', - handler='acapy_plugin_toolbox.routing.SendUpdateHandler', - msg_type=SEND_UPDATE, +MediationRequestsGet, MediationRequestsGetSchema = generate_model_schema( + name='MediationRequestsGet', + handler='acapy_plugin_toolbox.routing.MediationRequestsGetHandler', + msg_type=MEDIATION_REQUESTS_GET, schema={ - 'connection_id': fields.Str(required=True), - 'verkey': fields.Str(required=True), - 'action': fields.Str(required=True), + 'state': fields.Str(required=False), + 'connection_id': fields.Str(required=False) + } +) + +MediationRequests, MediationRequestsSchema = generate_model_schema( + name='MediationRequests', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=MEDIATION_REQUESTS, + schema={ + 'requests': fields.List(fields.Nested(MediationRecordSchema)) } ) -class SendUpdateHandler(BaseHandler): - """Handler for received delete requests.""" +class MediationRequestsGetHandler(BaseHandler): + """Handler for received mediation requests get messages.""" @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): - """Handle received delete requests.""" - - update_msg = RouteUpdateRequest(updates=[ - RouteUpdate( - recipient_key=context.message.verkey, - action=context.message.action - ) - ]) - - # TODO make sure connection_id is valid, fail gracefully - await responder.send( - update_msg, - connection_id=context.message.connection_id, + """Handle mediation requests get message.""" + tag_filter = dict( + filter(lambda item: item[1] is not None, { + 'state': context.message.state, + 'role': MediationRecord.ROLE_CLIENT, + 'connection_id': context.message.connection_id + }.items()) ) + records = await MediationRecord.query(context, tag_filter=tag_filter) + response = MediationRequests(requests=records) + response.assign_thread_from(context.message) + await responder.send_reply(response) MediationRequestSend, MediationRequestSendSchema = generate_model_schema( @@ -108,12 +128,6 @@ class SendMediationRequestHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): - # Construct message - mediation_request = MediationRequest( - mediator_terms=context.message.mediator_terms, - recipient_terms=context.message.recipient_terms, - ) - # Verify connection exists try: connection = await ConnectionRecord.retrieve_by_id( @@ -127,6 +141,20 @@ async def handle(self, context: RequestContext, responder: BaseResponder): ) report.assign_thread_from(context.message) await responder.send_reply(report) + return + + # Create record + record = MediationRecord( + role=MediationRecord.ROLE_CLIENT, + connection_id=connection.connection_id + ) + await record.save(context, reason="Sending new mediation request") + + # Construct message + mediation_request = MediationRequest( + mediator_terms=context.message.mediator_terms, + recipient_terms=context.message.recipient_terms, + ) # Send mediation request await responder.send( @@ -138,3 +166,97 @@ async def handle(self, context: RequestContext, responder: BaseResponder): sent = MediationRequestSent(connection_id=connection.connection_id) sent.assign_thread_from(context.message) await responder.send_reply(sent) + + +KeylistUpdateSend, KeylistUpdateSendSchema = generate_model_schema( + name='KeylistUpdateSend', + handler='acapy_plugin_toolbox.routing.KeylistUpdateSendHandler', + msg_type=KEYLIST_UPDATE_SEND, + schema={ + 'connection_id': fields.Str(required=True), + 'verkey': fields.Str(required=True), + 'action': fields.Str( + required=True, + validate=OneOf({'add', 'remove'}) + ), + } +) + + +KeylistUpdateSent, KeylistUpdateSentSchema = generate_model_schema( + name='KeylistUpdateSent', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=KEYLIST_UPDATE_SENT, + schema={ + 'connection_id': fields.Str(required=True), + 'verkey': fields.Str(required=True), + 'action': fields.Str( + required=True, + validate=OneOf({'add', 'remove'}) + ), + } +) + + +class KeylistUpdateSendHandler(BaseHandler): + """Handler KeylistUpdateSend request.""" + + @admin_only + async def handle(self, context: RequestContext, responder: BaseResponder): + """Handle KeylistUpdateSend messages.""" + manager = MediationManager(context) + if context.message.action == KeylistUpdateRule.RULE_ADD: + update = await manager.add_key( + context.message.verkey, + context.message.connection_id + ) + elif context.message.action == KeylistUpdateRule.RULE_REMOVE: + update = await manager.remove_key( + context.message.verkey, + context.message.connection_id + ) + + await responder.send( + update, + connection_id=context.message.connection_id, + ) + + sent = KeylistUpdateSent( + connection_id=context.message.connection_id, + verkey=context.message.verkey, + action=context.message.action + ) + sent.assign_thread_from(context.message) + await responder.send_reply(sent) + + +RoutesGet, RoutesGetSchema = generate_model_schema( + name='RoutesGet', + handler='acapy_plugin_toolbox.routing.RoutesGetHandler', + msg_type=ROUTES_GET, + schema={ + 'connection_id': fields.Str(required=False) + } +) + + +Routes, RoutesSchema = generate_model_schema( + name='Routes', + handler='acapy_plugin_toolbox.util.PassHandler', + msg_type=ROUTES, + schema={ + 'routes': fields.List(fields.Nested(RouteRecordSchema)) + } +) + + +class RoutesGetHandler(BaseHandler): + """Handler for RoutesGet.""" + + @admin_only + async def handle(self, context: RequestContext, responder: BaseResponder): + """Handle RotuesGet.""" + manager = MediationManager(context) + routes = Routes(routes=await manager.get_my_keylist(context.message.connection_id)) + routes.assign_thread_from(context.message) + await responder.send_reply(routes) From 2838b13bb62503d706869b75192c2ca8e2024158 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Fri, 27 Nov 2020 15:44:46 -0500 Subject: [PATCH 12/27] Add ngrokless docker compose, move to subdir Signed-off-by: Daniel Bluhm --- README.md | 34 ++++++++++++------- Dockerfile => docker/Dockerfile | 11 +++--- .../docker-compose-a-b-ngrok.yml | 8 +++-- docker/docker-compose-a-b.yml | 23 +++++++++++++ .../docker-compose.yml | 4 ++- ngrok-wait.sh => docker/ngrok-wait.sh | 7 +++- startup.sh => docker/startup.sh | 5 ++- 7 files changed, 69 insertions(+), 23 deletions(-) rename Dockerfile => docker/Dockerfile (96%) rename docker-compose_alice_bob.yml => docker/docker-compose-a-b-ngrok.yml (79%) create mode 100644 docker/docker-compose-a-b.yml rename docker-compose.yml => docker/docker-compose.yml (76%) rename ngrok-wait.sh => docker/ngrok-wait.sh (69%) rename startup.sh => docker/startup.sh (92%) mode change 100644 => 100755 diff --git a/README.md b/README.md index 794f7819..8efe9c47 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,18 @@ Requirements: - Docker Compose ### Disclaimer regarding the use of ngrok -Both compose setups use the ngrok tunneling service to make your agent available -to the outside world. One caveat of this, however, is that connections made from -your docker agent will expire within 8 hours as a limitation of the ngrok -free-tier. Therefore, **these setups are intended for demonstration purposes -only** and should not be relied upon as is for production environments. - -### One Agent demo +Two of the docker compose setups use the ngrok tunneling service to make your +agent available to the outside world. One caveat of this, however, is that +connections made from your docker agent will expire within 8 hours as a +limitation of the ngrok free-tier. Therefore, **these setups are intended for +demonstration purposes only** and should not be relied upon as is for production +environments. + +### One Agent Demo To start the single agent demo: ```sh -$ docker-compose -f docker-compose.yml up --build +$ docker-compose -f docker/docker-compose.yml up --build ``` This will start two containers, one for the ngrok tunnel and one for the agent. @@ -35,15 +36,22 @@ starting up. The agent container will emit a fair amount of logs, including of starting up it will print an invitation to the screen that can then be pasted into the toolbox to connect to and remotely administer your docker agent. -### Two Agent demo -To start up an Alice and Bob demo: +### Two Agent Demos +To start up an Alice and Bob demo **with** ngrok: + +```sh +$ docker-compose -f docker/docker-compose-a-b-ngrok.yml up --build +``` +This will start four containers, two ngrok tunnels and two agent containers. + +To start up an Alice and Bob demo **without** ngrok: ```sh -$ docker-compose -f docker-compose_alice_bob.yml up --build +$ docker-compose -f docker/docker-compose-a-b.yml up --build ``` +This will start only the two agent containers. -This will start four containers, two ngrok tunnels and two agent containers. Two -invitations will be printed to the screen corresponding to Alice and Bob. +Two invitations will be printed to the screen corresponding to Alice and Bob. Pasting these invitations into the toolbox will result in "Alice (Admin)" and "Bob (Admin)" connections. Using the toolbox, you can then cause these two agents to interact with each other in various ways. diff --git a/Dockerfile b/docker/Dockerfile similarity index 96% rename from Dockerfile rename to docker/Dockerfile index 975c0390..8c708047 100644 --- a/Dockerfile +++ b/docker/Dockerfile @@ -37,15 +37,16 @@ RUN tar xzvf libsovtoken.tar.gz; \ cd libsovtoken-1.0.1/libsovtoken; \ cargo build ENV LIBSOVTOKEN=/home/indy/libsovtoken-1.0.1/libsovtoken/target/debug/libsovtoken.so -ADD . . - -RUN pip3 install --no-cache-dir -e . ADD https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 ./jq RUN chmod +x ./jq -COPY startup.sh startup.sh + +ADD . . +RUN pip3 install --no-cache-dir -e . + +COPY docker/startup.sh startup.sh RUN chmod +x ./startup.sh -COPY ngrok-wait.sh wait.sh +COPY docker/ngrok-wait.sh wait.sh RUN chmod +x ./wait.sh USER $user diff --git a/docker-compose_alice_bob.yml b/docker/docker-compose-a-b-ngrok.yml similarity index 79% rename from docker-compose_alice_bob.yml rename to docker/docker-compose-a-b-ngrok.yml index 8b7f9397..b1bf351c 100644 --- a/docker-compose_alice_bob.yml +++ b/docker/docker-compose-a-b-ngrok.yml @@ -4,7 +4,9 @@ services: image: wernight/ngrok command: ngrok http agent-alice:3000 --log stdout agent-alice: - build: . + build: + context: ../ + dockerfile: ./docker/Dockerfile environment: NGROK_NAME: ngrok-alice AGENT_NAME: Alice @@ -17,7 +19,9 @@ services: image: wernight/ngrok command: ngrok http agent-bob:3000 --log stdout agent-bob: - build: . + build: + context: ../ + dockerfile: ./docker/Dockerfile environment: NGROK_NAME: ngrok-bob AGENT_NAME: Bob diff --git a/docker/docker-compose-a-b.yml b/docker/docker-compose-a-b.yml new file mode 100644 index 00000000..774b1c1b --- /dev/null +++ b/docker/docker-compose-a-b.yml @@ -0,0 +1,23 @@ +version: "3" +services: + agent-alice: + build: + context: ../ + dockerfile: ./docker/Dockerfile + environment: + AGENT_NAME: Alice + PORT: 3000 + ADMIN_PORT: 3001 + NO_NGROK: 1 + network_mode: "host" + + agent-bob: + build: + context: ../ + dockerfile: ./docker/Dockerfile + environment: + AGENT_NAME: Bob + PORT: 3002 + ADMIN_PORT: 3003 + NO_NGROK: 1 + network_mode: "host" diff --git a/docker-compose.yml b/docker/docker-compose.yml similarity index 76% rename from docker-compose.yml rename to docker/docker-compose.yml index e5149dc8..22077e95 100644 --- a/docker-compose.yml +++ b/docker/docker-compose.yml @@ -4,7 +4,9 @@ services: image: wernight/ngrok command: ngrok http agent:3000 --log stdout agent: - build: . + build: + context: ../ + dockerfile: ./docker/Dockerfile environment: NGROK_NAME: ngrok AGENT_NAME: MyAgent diff --git a/ngrok-wait.sh b/docker/ngrok-wait.sh similarity index 69% rename from ngrok-wait.sh rename to docker/ngrok-wait.sh index 6b4d5950..6688ad64 100644 --- a/ngrok-wait.sh +++ b/docker/ngrok-wait.sh @@ -1,5 +1,10 @@ #!/bin/bash +if [ -n "$NO_NGROK" ]; then + export ENDPOINT="http://localhost:$PORT" + exec "$@" +fi + NGROK_NAME=${NGROK_NAME:-ngrok} echo "ngrok end point [$NGROK_NAME]" @@ -8,7 +13,7 @@ ENDPOINT=null while [ -z "$ENDPOINT" ] || [ "$ENDPOINT" = "null" ] do echo "Fetching end point from ngrok service" - ENDPOINT=$(curl --silent $NGROK_NAME:4040/api/tunnels | ./jq -r '.tunnels[0].public_url') + ENDPOINT=$(curl --silent "$NGROK_NAME:4040/api/tunnels" | ./jq -r '.tunnels[0].public_url') if [ -z "$ENDPOINT" ] || [ "$ENDPOINT" = "null" ]; then echo "ngrok not ready, sleeping 5 seconds...." diff --git a/startup.sh b/docker/startup.sh old mode 100644 new mode 100755 similarity index 92% rename from startup.sh rename to docker/startup.sh index 4d18dba4..b7c1f572 --- a/startup.sh +++ b/docker/startup.sh @@ -1,8 +1,11 @@ -aca-py start \ +#!/bin/bash +CMD=${CMD:-aca-py} +$CMD start \ -it acapy_plugin_toolbox.http_ws 0.0.0.0 "$PORT" \ -ot http \ -e "$ENDPOINT" "${ENDPOINT/http/ws}" \ --label "$AGENT_NAME" \ + --wallet-name "$AGENT_NAME" \ --auto-accept-requests --auto-ping-connection \ --auto-respond-credential-proposal --auto-respond-credential-offer --auto-respond-credential-request --auto-store-credential \ --auto-respond-presentation-proposal --auto-respond-presentation-request --auto-verify-presentation \ From 42545abea8d4b9a7a46e39d3d30f87c684c5f1e0 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Fri, 27 Nov 2020 15:45:31 -0500 Subject: [PATCH 13/27] fix: admin-mediator routes-get returning client Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/http_ws.py | 1 + acapy_plugin_toolbox/mediator.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/acapy_plugin_toolbox/http_ws.py b/acapy_plugin_toolbox/http_ws.py index 86aa6a4b..c195c16e 100644 --- a/acapy_plugin_toolbox/http_ws.py +++ b/acapy_plugin_toolbox/http_ws.py @@ -4,6 +4,7 @@ from aries_cloudagent.transport.inbound.base import BaseInboundTransport from aries_cloudagent.transport.inbound import http, ws + class HttpWsTransport(BaseInboundTransport): """Http+Ws Transport class.""" diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index d1f4da0a..eab99056 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -41,10 +41,10 @@ MEDIATION_REQUESTS: 'acapy_plugin_toolbox.mediator.MediationRequests', # get all routes used for mediation - ROUTES: 'acapy_plugin_toolbox.mediator.Routes', + ROUTES_GET: 'acapy_plugin_toolbox.mediator.RoutesGet', # return type for get all routes - ROUTES_GET: 'acapy_plugin_toolbox.mediator.RoutesGet', + ROUTES: 'acapy_plugin_toolbox.mediator.Routes', MEDIATION_GRANT: 'acapy_plugin_toolbox.mediator.MediationGrant', MEDIATION_GRANTED: 'acapy_plugin_toolbox.mediator.MediationGranted', @@ -212,7 +212,8 @@ async def handle(self, context: RequestContext, responder: BaseResponder): """Handle received get Route get request.""" tag_filter = dict( filter(lambda item: item[1] is not None, { - 'connection_id': context.message.connection_id + 'connection_id': context.message.connection_id, + 'role': MediationRecord.ROLE_SERVER }.items()) ) records = await RouteRecord.query(context, tag_filter=tag_filter) From fbcd90ac90a03f60867c61ea5463147a984796b3 Mon Sep 17 00:00:00 2001 From: Sam Curren Date: Mon, 30 Nov 2020 11:39:04 -0700 Subject: [PATCH 14/27] dockerfile ngrok partial changes. Signed-off-by: Sam Curren --- docker/Dockerfile | 3 ++- docker/docker-compose-a-b.yml | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 8c708047..4d392ae7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -51,4 +51,5 @@ RUN chmod +x ./wait.sh USER $user -CMD ./wait.sh ./startup.sh +# CMD ./wait.sh ./startup.sh +CMD ./startup.sh diff --git a/docker/docker-compose-a-b.yml b/docker/docker-compose-a-b.yml index 774b1c1b..f9973202 100644 --- a/docker/docker-compose-a-b.yml +++ b/docker/docker-compose-a-b.yml @@ -9,7 +9,10 @@ services: PORT: 3000 ADMIN_PORT: 3001 NO_NGROK: 1 - network_mode: "host" + ENDPOINT: http://host.docker.internal:3000/ + ports: + - "3000:3000" + - "3001:3001" agent-bob: build: @@ -20,4 +23,7 @@ services: PORT: 3002 ADMIN_PORT: 3003 NO_NGROK: 1 - network_mode: "host" + ENDPOINT: http://host.docker.internal:3002/ + ports: + - "3002:3002" + - "3003:3003" From d6257753270ca51c911a9a521f87f4abff18f22a Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Mon, 30 Nov 2020 19:02:26 -0500 Subject: [PATCH 15/27] fix(docker): prevent endpoint clobbering Add ngrokless linux docker compose to accommodate differences in networking on Linux VS Windows and Mac. Update REAMDE to reflect changes Signed-off-by: Daniel Bluhm --- README.md | 48 +++++++++++++++++------------ docker/docker-compose-a-b-linux.yml | 23 ++++++++++++++ docker/ngrok-wait.sh | 2 +- 3 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 docker/docker-compose-a-b-linux.yml diff --git a/README.md b/README.md index 8efe9c47..50e78f4b 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,19 @@ $ docker-compose -f docker/docker-compose-a-b-ngrok.yml up --build ``` This will start four containers, two ngrok tunnels and two agent containers. -To start up an Alice and Bob demo **without** ngrok: +To start up an Alice and Bob demo **without** ngrok (**Windows** and **Mac**): ```sh $ docker-compose -f docker/docker-compose-a-b.yml up --build ``` + +Due to differences in how networking is handled on Windows and Mac docker when +compared to Linux docker, use the following if you are on **Linux**: + +```sh +$ docker-compose -f docker/docker-compose-a-b-linux.yml up --build +``` + This will start only the two agent containers. Two invitations will be printed to the screen corresponding to Alice and Bob. @@ -108,10 +116,10 @@ $ pip install git+https://github.com/hyperledger/aries-acapy-plugin-toolbox.git@ Start up ACA-Py with the plugin parameter: ```sh $ aca-py start \ - -it http localhost 3000 -it ws localhost 3001 \ - -ot http \ - -e http://localhost:3000 ws://localhost:3001 \ - --plugin acapy_plugin_toolbox + -it http localhost 3000 -it ws localhost 3001 \ + -ot http \ + -e http://localhost:3000 ws://localhost:3001 \ + --plugin acapy_plugin_toolbox ``` Passing the whole package `acapy_plugin_toolbox` will load all protocol @@ -142,11 +150,11 @@ Available groups include: To load the "connections" group and the "basicmessage" module: ```sh $ aca-py start \ - -it http localhost 3000 -it ws localhost 3001 \ - -ot http \ - -e http://localhost:3000 ws://localhost:3001 \ - --plugin acapy_plugin_toolbox.group.connections - --plugin acapy_plugin_toolbox.basicmessage + -it http localhost 3000 -it ws localhost 3001 \ + -ot http \ + -e http://localhost:3000 ws://localhost:3001 \ + --plugin acapy_plugin_toolbox.group.connections + --plugin acapy_plugin_toolbox.basicmessage ``` ### Generating an invitation for use with the Toolbox @@ -158,11 +166,11 @@ can then be loaded into the Aries Toolbox: ```sh $ aca-py start \ - -it http localhost 3000 -it ws localhost 3001 \ - -ot http \ - -e http://localhost:3000 ws://localhost:3001 \ - --plugin acapy_plugin_toolbox \ - --invite --invite-label "My agent admin connection" --invite-role admin + -it http localhost 3000 -it ws localhost 3001 \ + -ot http \ + -e http://localhost:3000 ws://localhost:3001 \ + --plugin acapy_plugin_toolbox \ + --invite --invite-label "My agent admin connection" --invite-role admin ``` The invitation will be printed to the screen after the agent has started up and @@ -186,8 +194,8 @@ and a start up command similar to the following (with environment variables replaced with your appropriate values or available in the environment): ```sh $ aca-py start \ - -it http localhost 3000 -it ws localhost 3001 \ - -ot http \ + -it http localhost 3000 -it ws localhost 3001 \ + -ot http \ -e $ENDPOINT ${ENDPOINT/http/ws} \ --label $AGENT_NAME \ --auto-accept-requests --auto-ping-connection \ @@ -208,9 +216,9 @@ that generally provides only one port-to-port tunnel at a time. To use the HTTP+WS transport: ```sh $ aca-py start \ - -it acapy_plugin_toolbox.http_ws localhost 3000 \ - -ot http \ - -e http://localhost:3000 ws://localhost:3000 + -it acapy_plugin_toolbox.http_ws localhost 3000 \ + -ot http \ + -e http://localhost:3000 ws://localhost:3000 ``` Note that you do not need to load any other plugins for this transport but you diff --git a/docker/docker-compose-a-b-linux.yml b/docker/docker-compose-a-b-linux.yml new file mode 100644 index 00000000..8f93b461 --- /dev/null +++ b/docker/docker-compose-a-b-linux.yml @@ -0,0 +1,23 @@ +version: "3" +services: + agent-alice: + build: + context: ../ + dockerfile: ./docker/Dockerfile + network_mode: host + environment: + AGENT_NAME: Alice + PORT: 3000 + ADMIN_PORT: 3001 + NO_NGROK: 1 + + agent-bob: + build: + context: ../ + dockerfile: ./docker/Dockerfile + network_mode: host + environment: + AGENT_NAME: Bob + PORT: 3002 + ADMIN_PORT: 3003 + NO_NGROK: 1 diff --git a/docker/ngrok-wait.sh b/docker/ngrok-wait.sh index 6688ad64..a328d58b 100644 --- a/docker/ngrok-wait.sh +++ b/docker/ngrok-wait.sh @@ -1,7 +1,7 @@ #!/bin/bash if [ -n "$NO_NGROK" ]; then - export ENDPOINT="http://localhost:$PORT" + export ENDPOINT=${ENDPOINT:-"http://localhost:$PORT"} exec "$@" fi From 234ae34ac2199be138c99cf8eff90b84d2d32bd3 Mon Sep 17 00:00:00 2001 From: Sam Curren Date: Tue, 1 Dec 2020 11:44:34 -0700 Subject: [PATCH 16/27] correct temp endpoint fix Signed-off-by: Sam Curren --- docker/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4d392ae7..8c708047 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -51,5 +51,4 @@ RUN chmod +x ./wait.sh USER $user -# CMD ./wait.sh ./startup.sh -CMD ./startup.sh +CMD ./wait.sh ./startup.sh From 8a1ad8c43a05aba6ee572558e01143f69e5d43c4 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 15:35:42 -0500 Subject: [PATCH 17/27] fix: mediator context -> session Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/mediator.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/acapy_plugin_toolbox/mediator.py b/acapy_plugin_toolbox/mediator.py index 026261e0..aedf1e2f 100644 --- a/acapy_plugin_toolbox/mediator.py +++ b/acapy_plugin_toolbox/mediator.py @@ -98,7 +98,8 @@ async def handle(self, context: RequestContext, responder: BaseResponder): 'connection_id': context.message.connection_id }.items()) ) - records = await MediationRecord.query(context, tag_filter=tag_filter) + session = await context.session() + records = await MediationRecord.query(session, tag_filter=tag_filter) response = MediationRequests(requests=records) response.assign_thread_from(context.message) await responder.send_reply(response) @@ -131,9 +132,10 @@ class MediationGrantHandler(BaseHandler): """ async def handle(self, context: RequestContext, responder: BaseResponder): """Handle mediation grant request.""" - manager = MediationManager(context) + session = await context.session() + manager = MediationManager(session) record = await MediationRecord.retrieve_by_id( - context, context.message.mediation_id + session, context.message.mediation_id ) grant = await manager.grant_request(record) @@ -172,9 +174,10 @@ class MediationDenyHandler(BaseHandler): async def handle(self, context: RequestContext, responder: BaseResponder): """Handle mediation deny request.""" - manager = MediationManager(context) + session = await context.session() + manager = MediationManager(session) record = await MediationRecord.retrieve_by_id( - context, context.message.mediation_id + session, context.message.mediation_id ) deny = await manager.deny_request(record) @@ -210,13 +213,14 @@ class RoutesGetHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle received get Route get request.""" + session = await context.session() tag_filter = dict( filter(lambda item: item[1] is not None, { 'connection_id': context.message.connection_id, 'role': MediationRecord.ROLE_SERVER }.items()) ) - records = await RouteRecord.query(context, tag_filter=tag_filter) + records = await RouteRecord.query(session, tag_filter=tag_filter) response = Routes(routes=records) response.assign_thread_from(context.message) await responder.send_reply(response) From 04b7068eaade0753a2e05139748c60304e5d8c80 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 15:41:50 -0500 Subject: [PATCH 18/27] fix: routing context -> session Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/routing.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index bc741cb7..abe07dbd 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -96,6 +96,7 @@ class MediationRequestsGetHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle mediation requests get message.""" + session = await context.session() tag_filter = dict( filter(lambda item: item[1] is not None, { 'state': context.message.state, @@ -103,7 +104,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): 'connection_id': context.message.connection_id }.items()) ) - records = await MediationRecord.query(context, tag_filter=tag_filter) + records = await MediationRecord.query(session, tag_filter=tag_filter) response = MediationRequests(requests=records) response.assign_thread_from(context.message) await responder.send_reply(response) @@ -210,7 +211,8 @@ class KeylistUpdateSendHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle KeylistUpdateSend messages.""" - manager = MediationManager(context) + session = await context.session() + manager = MediationManager(session) if context.message.action == KeylistUpdateRule.RULE_ADD: update = await manager.add_key( context.message.verkey, @@ -262,7 +264,8 @@ class RoutesGetHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle RotuesGet.""" - manager = MediationManager(context) + session = await context.session() + manager = MediationManager(session) routes = Routes(routes=await manager.get_my_keylist(context.message.connection_id)) routes.assign_thread_from(context.message) await responder.send_reply(routes) From 452ba1a2a9ab3089472eeef189a842d5c7a36ce9 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 16:11:59 -0500 Subject: [PATCH 19/27] fix: admin connection lookup in basicmessage Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/basicmessage.py | 40 +++++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/acapy_plugin_toolbox/basicmessage.py b/acapy_plugin_toolbox/basicmessage.py index 5bc87df8..1394959c 100644 --- a/acapy_plugin_toolbox/basicmessage.py +++ b/acapy_plugin_toolbox/basicmessage.py @@ -1,16 +1,12 @@ """BasicMessage Plugin.""" # pylint: disable=invalid-name, too-few-public-methods -from typing import Union from datetime import datetime +from typing import Union -from marshmallow import fields - +from aries_cloudagent.connections.models.conn_record import ConnRecord from aries_cloudagent.core.profile import ProfileSession from aries_cloudagent.core.protocol_registry import ProtocolRegistry -from aries_cloudagent.connections.models.conn_record import ( - ConnRecord -) from aries_cloudagent.messaging.base_handler import ( BaseHandler, BaseResponder, RequestContext ) @@ -21,12 +17,18 @@ BaseRecord, BaseRecordSchema ) from aries_cloudagent.messaging.valid import INDY_ISO8601_DATETIME -from aries_cloudagent.protocols.connections.v1_0.manager import ConnectionManager -from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport +from aries_cloudagent.protocols.connections.v1_0.manager import ( + ConnectionManager +) +from aries_cloudagent.protocols.problem_report.v1_0.message import ( + ProblemReport +) +from aries_cloudagent.storage.base import BaseStorage from aries_cloudagent.storage.error import StorageNotFoundError +from marshmallow import fields from .util import ( - generate_model_schema, admin_only, timestamp_utc_iso, datetime_from_iso + admin_only, datetime_from_iso, generate_model_schema, timestamp_utc_iso ) PROTOCOL_URI = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0" @@ -236,21 +238,27 @@ async def handle(self, context: RequestContext, responder: BaseResponder): }, ) - connection_mgr = ConnectionManager(context) session = await context.session() - admins = await ConnRecord.query( - session, post_filter_positive={'their_role': 'admin'} + connection_mgr = ConnectionManager(session) + storage = session.inject(BaseStorage) + admin_ids = map( + lambda record: record.tags['connection_id'], + filter( + lambda record: record.value == 'admin', + await storage.find_all_records( + ConnRecord.RECORD_TYPE_METADATA, {'key': 'group'} + ) + ) ) - if not admins: + if not admin_ids: return - admins = filter(lambda admin: admin.state == 'active', admins) admin_verkeys = [ target.recipient_keys[0] - for admin in admins + for admin_id in admin_ids for target in await connection_mgr.get_connection_targets( - connection=admin + connection_id=admin_id ) ] From 55105d7554358bb0ccf5de10b064b8aaa8ba7d40 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 16:12:49 -0500 Subject: [PATCH 20/27] fix: connection manager context -> session Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/connections.py | 3 ++- acapy_plugin_toolbox/invitations.py | 3 ++- acapy_plugin_toolbox/static_connections.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/acapy_plugin_toolbox/connections.py b/acapy_plugin_toolbox/connections.py index dd4cba02..2563680f 100644 --- a/acapy_plugin_toolbox/connections.py +++ b/acapy_plugin_toolbox/connections.py @@ -293,7 +293,8 @@ class ReceiveInvitationHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle recieve invitation request.""" - connection_mgr = ConnectionManager(context) + session = await context.session() + connection_mgr = ConnectionManager(session) invitation = ConnectionInvitation.from_url(context.message.invitation) connection = await connection_mgr.receive_invitation( invitation, diff --git a/acapy_plugin_toolbox/invitations.py b/acapy_plugin_toolbox/invitations.py index 42ac5a34..cefa7b4f 100644 --- a/acapy_plugin_toolbox/invitations.py +++ b/acapy_plugin_toolbox/invitations.py @@ -119,7 +119,8 @@ class CreateInvitationHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle create invitation request.""" - connection_mgr = ConnectionManager(context) + session = await context.session() + connection_mgr = ConnectionManager(session) connection, invitation = await connection_mgr.create_invitation( my_label=context.message.label, their_role=context.message.role, diff --git a/acapy_plugin_toolbox/static_connections.py b/acapy_plugin_toolbox/static_connections.py index 87ef36c2..dc6006ac 100644 --- a/acapy_plugin_toolbox/static_connections.py +++ b/acapy_plugin_toolbox/static_connections.py @@ -90,8 +90,8 @@ class CreateStaticConnectionHandler(BaseHandler): async def handle(self, context: RequestContext, responder: BaseResponder): """Handle static connection creation request.""" - connection_mgr = ConnectionManager(context) session = await context.session() + connection_mgr = ConnectionManager(session) wallet: BaseWallet = session.inject(BaseWallet) # Make our info for the connection @@ -193,8 +193,8 @@ class StaticConnectionGetListHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): """Handle static connection get list request.""" - connection_mgr = ConnectionManager(context) session = await context.session() + connection_mgr = ConnectionManager(session) wallet: BaseWallet = session.inject(BaseWallet) try: tag_filter = dict( From 49eeb39d2e3f7ad9de04dc68767e4eefd57a557d Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 16:15:06 -0500 Subject: [PATCH 21/27] fix: invitations role -> group Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/invitations.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/acapy_plugin_toolbox/invitations.py b/acapy_plugin_toolbox/invitations.py index cefa7b4f..627740b4 100644 --- a/acapy_plugin_toolbox/invitations.py +++ b/acapy_plugin_toolbox/invitations.py @@ -75,7 +75,7 @@ async def setup( schema={ 'label': fields.Str(required=False), 'alias': fields.Str(required=False), # default? - 'role': fields.Str(required=False), + 'group': fields.Str(required=False), 'auto_accept': fields.Boolean(missing=False), 'multi_use': fields.Boolean(missing=False), } @@ -85,7 +85,7 @@ async def setup( 'id': fields.Str(required=True), 'label': fields.Str(required=False), 'alias': fields.Str(required=False), # default? - 'role': fields.Str(required=False), + 'group': fields.Str(required=False), 'auto_accept': fields.Boolean(missing=False), 'multi_use': fields.Boolean(missing=False), 'invitation_url': fields.Str(required=True), @@ -123,17 +123,20 @@ async def handle(self, context: RequestContext, responder: BaseResponder): connection_mgr = ConnectionManager(session) connection, invitation = await connection_mgr.create_invitation( my_label=context.message.label, - their_role=context.message.role, auto_accept=context.message.auto_accept, multi_use=bool(context.message.multi_use), public=False, alias=context.message.alias, ) + if context.message.group: + await connection.metadata_set( + session, "group", context.message.group + ) invite_response = Invitation( id=connection.connection_id, label=invitation.label, alias=connection.alias, - role=connection.their_role, + group=context.message.group, auto_accept=connection.accept == ConnRecord.ACCEPT_AUTO, multi_use=( connection.invitation_mode == @@ -180,12 +183,13 @@ async def handle(self, context: RequestContext, responder: BaseResponder): invitation = await connection.retrieve_invitation(session) except StorageNotFoundError: continue + group = await connection.metadata_get(session, 'group') invite = { 'id': connection.connection_id, 'label': invitation.label, 'alias': connection.alias, - 'role': connection.their_role, + 'group': group, 'auto_accept': ( connection.accept == ConnRecord.ACCEPT_AUTO ), From dc93823c0752ba960a55019b95f0881d58b0dca7 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 16:24:57 -0500 Subject: [PATCH 22/27] fix: context -> session in saves Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/basicmessage.py | 8 ++++--- acapy_plugin_toolbox/connections.py | 2 +- .../credential_definitions.py | 4 ++-- acapy_plugin_toolbox/routing.py | 22 +++++-------------- acapy_plugin_toolbox/schemas.py | 4 ++-- 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/acapy_plugin_toolbox/basicmessage.py b/acapy_plugin_toolbox/basicmessage.py index 1394959c..42aafe69 100644 --- a/acapy_plugin_toolbox/basicmessage.py +++ b/acapy_plugin_toolbox/basicmessage.py @@ -219,6 +219,7 @@ class BasicMessageHandler(BaseHandler): async def handle(self, context: RequestContext, responder: BaseResponder): """Handle received basic message.""" + session = await context.session() msg = BasicMessageRecord( connection_id=context.connection_record.connection_id, message_id=context.message._id, @@ -226,7 +227,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): content=context.message.content, state=BasicMessageRecord.STATE_RECV ) - await msg.save(context, reason='New message received.') + await msg.save(session, reason='New message received.') await responder.send_webhook( "basicmessages", @@ -385,9 +386,10 @@ class SendHandler(BaseHandler): async def handle(self, context: RequestContext, responder: BaseResponder): """Handle received send requests.""" # pylint: disable=protected-access + session = await context.session() try: connection = await ConnRecord.retrieve_by_id( - context, context.message.connection_id + session, context.message.connection_id ) except StorageNotFoundError: report = ProblemReport( @@ -412,7 +414,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): content=msg.content, state=BasicMessageRecord.STATE_SENT ) - await record.save(context, reason='Message sent.') + await record.save(session, reason='Message sent.') sent_msg = Sent(connection_id=connection.connection_id, message=record) sent_msg.assign_thread_from(context.message) await responder.send_reply(sent_msg) diff --git a/acapy_plugin_toolbox/connections.py b/acapy_plugin_toolbox/connections.py index 2563680f..a1f1b358 100644 --- a/acapy_plugin_toolbox/connections.py +++ b/acapy_plugin_toolbox/connections.py @@ -209,7 +209,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): connection.their_label = new_label new_role = context.message.role or connection.their_role connection.their_role = new_role - await connection.save(context, reason="Update request received.") + await connection.save(session, reason="Update request received.") conn_response = Connection( **conn_record_to_message_repr(connection) ) diff --git a/acapy_plugin_toolbox/credential_definitions.py b/acapy_plugin_toolbox/credential_definitions.py index f0ef97eb..edb4994d 100644 --- a/acapy_plugin_toolbox/credential_definitions.py +++ b/acapy_plugin_toolbox/credential_definitions.py @@ -192,7 +192,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): state=SchemaRecord.STATE_WRITTEN, author=SchemaRecord.AUTHOR_OTHER ) - await schema_record.save(context, reason='Retrieved from ledger') + await schema_record.save(session, reason='Retrieved from ledger') try: async with ledger: @@ -296,7 +296,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): state=SchemaRecord.STATE_WRITTEN, author=SchemaRecord.AUTHOR_OTHER ) - await schema_record.save(context, reason='Retrieved from ledger') + await schema_record.save(session, reason='Retrieved from ledger') cred_def_record = CredDefRecord( cred_def_id=credential_definition['id'], diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index abe07dbd..f9bf6b67 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -136,9 +136,11 @@ class SendMediationRequestHandler(BaseHandler): @admin_only async def handle(self, context: RequestContext, responder: BaseResponder): # Verify connection exists + session = await context.session() + manager = MediationManager(session) try: - connection = await ConnectionRecord.retrieve_by_id( - context, + connection = await ConnRecord.retrieve_by_id( + session, context.message.connection_id ) except StorageNotFoundError: @@ -150,22 +152,10 @@ async def handle(self, context: RequestContext, responder: BaseResponder): await responder.send_reply(report) return - # Create record - record = MediationRecord( - role=MediationRecord.ROLE_CLIENT, - connection_id=connection.connection_id - ) - await record.save(context, reason="Sending new mediation request") - - # Construct message - mediation_request = MediationRequest( - mediator_terms=context.message.mediator_terms, - recipient_terms=context.message.recipient_terms, - ) - + request = await manager.prepare_request(connection.connection_id) # Send mediation request await responder.send( - mediation_request, + request, connection_id=connection.connection_id, ) diff --git a/acapy_plugin_toolbox/schemas.py b/acapy_plugin_toolbox/schemas.py index 04025f41..24aceb78 100644 --- a/acapy_plugin_toolbox/schemas.py +++ b/acapy_plugin_toolbox/schemas.py @@ -200,7 +200,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): state=SchemaRecord.STATE_WRITTEN, author=SchemaRecord.AUTHOR_SELF, ) - await schema.save(context, reason="Committed to ledger") + await schema.save(session, reason="Committed to ledger") result = SchemaID(schema_id=schema_id) result.assign_thread_from(context.message) @@ -254,7 +254,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): state=SchemaRecord.STATE_WRITTEN, author=SchemaRecord.AUTHOR_OTHER ) - await schema_record.save(context, reason='Retrieved from ledger') + await schema_record.save(session, reason='Retrieved from ledger') schema_msg = Schema(**schema_record.serialize()) schema_msg.assign_thread_from(context.message) From bdea239e0cc0e521d8a0879fb1aba4d39e674626 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 16:26:47 -0500 Subject: [PATCH 23/27] fix: retrieve_by_id context -> session Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/holder.py | 6 ++++-- acapy_plugin_toolbox/issuer.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/acapy_plugin_toolbox/holder.py b/acapy_plugin_toolbox/holder.py index a9d687a2..b690722c 100644 --- a/acapy_plugin_toolbox/holder.py +++ b/acapy_plugin_toolbox/holder.py @@ -107,9 +107,10 @@ async def handle(self, context: RequestContext, responder: BaseResponder): credential_manager = CredentialManager(context) + session = await context.session() try: conn_record = await ConnRecord.retrieve_by_id( - context, + session, connection_id ) except StorageNotFoundError: @@ -173,9 +174,10 @@ async def handle(self, context: RequestContext, responder: BaseResponder): """Handle received send presentation proposal request.""" connection_id = str(context.message.connection_id) + session = await context.session() try: conn_record = await ConnRecord.retrieve_by_id( - context, + session, connection_id ) except StorageNotFoundError: diff --git a/acapy_plugin_toolbox/issuer.py b/acapy_plugin_toolbox/issuer.py index 5872f775..d2977eb5 100644 --- a/acapy_plugin_toolbox/issuer.py +++ b/acapy_plugin_toolbox/issuer.py @@ -107,9 +107,10 @@ async def handle(self, context: RequestContext, responder: BaseResponder): connection_id = str(context.message.connection_id) preview_spec = context.message.credential_proposal + session = await context.session() try: conn_record = await ConnRecord.retrieve_by_id( - context, + session, connection_id ) except StorageNotFoundError: @@ -179,9 +180,10 @@ async def handle(self, context: RequestContext, responder: BaseResponder): """Handle received presentation request request.""" connection_id = str(context.message.connection_id) + session = await context.session() try: conn_record = await ConnRecord.retrieve_by_id( - context, + session, connection_id ) except StorageNotFoundError: From c211d77267ab5caf6e52578a377e01c5388ab9d1 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 17:42:14 -0500 Subject: [PATCH 24/27] fix: basicmessage notifications Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/basicmessage.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/acapy_plugin_toolbox/basicmessage.py b/acapy_plugin_toolbox/basicmessage.py index 42aafe69..17451a4a 100644 --- a/acapy_plugin_toolbox/basicmessage.py +++ b/acapy_plugin_toolbox/basicmessage.py @@ -1,6 +1,7 @@ """BasicMessage Plugin.""" # pylint: disable=invalid-name, too-few-public-methods +import json from datetime import datetime from typing import Union @@ -245,21 +246,26 @@ async def handle(self, context: RequestContext, responder: BaseResponder): admin_ids = map( lambda record: record.tags['connection_id'], filter( - lambda record: record.value == 'admin', + lambda record: json.loads(record.value) == 'admin', await storage.find_all_records( ConnRecord.RECORD_TYPE_METADATA, {'key': 'group'} ) ) ) + admins = [ + await ConnRecord.retrieve_by_id(session, id) + for id in admin_ids + ] - if not admin_ids: + if not admins: return + admins = filter(lambda admin: admin.state == 'active', admins) admin_verkeys = [ target.recipient_keys[0] - for admin_id in admin_ids + for admin in admins for target in await connection_mgr.get_connection_targets( - connection_id=admin_id + connection=admin ) ] From 76f14861e0dbd8b99c5ac9b89b3be36ddfa781a5 Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 19:13:25 -0500 Subject: [PATCH 25/27] fix: prepare_requests returns tuple Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/routing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acapy_plugin_toolbox/routing.py b/acapy_plugin_toolbox/routing.py index f9bf6b67..9401c258 100644 --- a/acapy_plugin_toolbox/routing.py +++ b/acapy_plugin_toolbox/routing.py @@ -152,7 +152,9 @@ async def handle(self, context: RequestContext, responder: BaseResponder): await responder.send_reply(report) return - request = await manager.prepare_request(connection.connection_id) + _record, request = await manager.prepare_request( + connection.connection_id + ) # Send mediation request await responder.send( request, From 80cbb2a0edb0cabc1820e92a355460420932c0ce Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Wed, 16 Dec 2020 22:41:20 -0500 Subject: [PATCH 26/27] feat: support specifying mediator in create and receive invite Signed-off-by: Daniel Bluhm --- acapy_plugin_toolbox/connections.py | 6 ++++-- acapy_plugin_toolbox/invitations.py | 4 ++++ docker/startup.sh | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/acapy_plugin_toolbox/connections.py b/acapy_plugin_toolbox/connections.py index a1f1b358..ae8ac708 100644 --- a/acapy_plugin_toolbox/connections.py +++ b/acapy_plugin_toolbox/connections.py @@ -282,7 +282,8 @@ async def handle(self, context: RequestContext, responder: BaseResponder): 'invitation': fields.Str(required=True), 'auto_accept': fields.Bool( missing=False - ) + ), + 'mediation_id': fields.Str(required=False), } ) @@ -298,7 +299,8 @@ async def handle(self, context: RequestContext, responder: BaseResponder): invitation = ConnectionInvitation.from_url(context.message.invitation) connection = await connection_mgr.receive_invitation( invitation, - auto_accept=context.message.auto_accept + auto_accept=context.message.auto_accept, + mediation_id=context.message.mediation_id, ) connection_resp = Connection(**conn_record_to_message_repr(connection)) await responder.send_reply(connection_resp) diff --git a/acapy_plugin_toolbox/invitations.py b/acapy_plugin_toolbox/invitations.py index 627740b4..b3e9ba2b 100644 --- a/acapy_plugin_toolbox/invitations.py +++ b/acapy_plugin_toolbox/invitations.py @@ -78,6 +78,7 @@ async def setup( 'group': fields.Str(required=False), 'auto_accept': fields.Boolean(missing=False), 'multi_use': fields.Boolean(missing=False), + 'mediation_id': fields.Str(required=False) } ) @@ -93,6 +94,7 @@ async def setup( required=False, description="Time of record creation", **INDY_ISO8601_DATETIME ), + 'mediation_id': fields.Str(required=False), 'raw_repr': fields.Dict(required=False), }) @@ -127,6 +129,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): multi_use=bool(context.message.multi_use), public=False, alias=context.message.alias, + mediation_id=context.message.mediation_id, ) if context.message.group: await connection.metadata_set( @@ -142,6 +145,7 @@ async def handle(self, context: RequestContext, responder: BaseResponder): connection.invitation_mode == ConnRecord.INVITATION_MODE_MULTI ), + mediation_id=context.message.mediation_id, invitation_url=invitation.to_url(), created_date=connection.created_at, raw_repr={ diff --git a/docker/startup.sh b/docker/startup.sh index 4a0119b1..19ad8ad0 100755 --- a/docker/startup.sh +++ b/docker/startup.sh @@ -7,6 +7,8 @@ $CMD start \ --label "$AGENT_NAME" \ --wallet-name "$AGENT_NAME" \ --auto-accept-requests --auto-ping-connection \ + --auto-send-keylist-update-in-create-invitation \ + --auto-send-keylist-update-in-requests \ --auto-respond-credential-proposal --auto-respond-credential-offer --auto-respond-credential-request --auto-store-credential \ --auto-respond-presentation-proposal --auto-respond-presentation-request --auto-verify-presentation \ --preserve-exchange-records \ From 4e844ecf07f2f45b90453c9a004683fcad59ea8b Mon Sep 17 00:00:00 2001 From: Daniel Bluhm Date: Fri, 18 Dec 2020 16:41:22 -0500 Subject: [PATCH 27/27] fix: use hyperledger for aca-py Signed-off-by: Daniel Bluhm --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f34bb7a9..d1abe2b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -aries-cloudagent[indy]@git+https://github.com/dbluhm/aries-cloudagent-python@toolbox-updating +aries-cloudagent[indy]@git+https://github.com/hyperledger/aries-cloudagent-python@b9c59da5a6d0482d63ab60e6b3c184b864b8a6f0 marshmallow==3.5.1 flake8 python-dateutil