From 59c0059981882a0c9e8197ce3a6dead28fb778f6 Mon Sep 17 00:00:00 2001 From: "Colton Wolkins (Laptop)" Date: Tue, 10 Dec 2024 12:25:36 -0700 Subject: [PATCH] feat: Send ping message to did from admin route Signed-off-by: Colton Wolkins (Laptop) --- .../protocols_v2/trustping/v1_0/routes.py | 118 +++++++++++++++++- 1 file changed, 113 insertions(+), 5 deletions(-) diff --git a/acapy_agent/protocols_v2/trustping/v1_0/routes.py b/acapy_agent/protocols_v2/trustping/v1_0/routes.py index 1d0f0fcf0e..39369d8866 100644 --- a/acapy_agent/protocols_v2/trustping/v1_0/routes.py +++ b/acapy_agent/protocols_v2/trustping/v1_0/routes.py @@ -19,7 +19,7 @@ class PingRequestSchema(OpenAPISchema): """Request schema for performing a ping.""" - to = fields.Str( + to_did = fields.Str( required=True, allow_none=False, metadata={"description": "Comment for the ping message"}, @@ -47,6 +47,26 @@ class PingConnIdMatchInfoSchema(OpenAPISchema): metadata={"description": "Connection identifier", "example": UUID4_EXAMPLE}, ) +from ....wallet.base import BaseWallet +from ....wallet.did_info import DIDInfo +from ....wallet.did_method import KEY, PEER2, PEER4, SOV, DIDMethod, DIDMethods, HolderDefinedDid +from ....wallet.did_posture import DIDPosture +from ....wallet.error import WalletError, WalletNotFoundError +from ....messaging.v2_agent_message import V2AgentMessage +from ....connections.models.connection_target import ConnectionTarget +from didcomm_messaging import DIDCommMessaging, RoutingService +def format_did_info(info: DIDInfo): + """Serialize a DIDInfo object.""" + if info: + return { + "did": info.did, + "verkey": info.verkey, + "posture": DIDPosture.get(info.metadata).moniker, + "key_type": info.key_type.key_type, + "method": info.method.method_name, + "metadata": info.metadata, + } + @docs(tags=["trustping"], summary="Send a trust ping to a connection") @request_schema(PingRequestSchema()) @@ -60,16 +80,16 @@ async def connections_send_ping(request: web.BaseRequest): """ context: AdminRequestContext = request["context"] - connection_id = request.match_info["conn_id"] + #connection_id = request.match_info["conn_id"] outbound_handler = request["outbound_message_router"] body = await request.json() - to = body.get("to") + to_did = body.get("to_did") response_requested = body.get("response_requested") try: async with context.profile.session() as session: resolver = session.inject(DMPResolver) - did_doc = await resolver.resolve(to) + did_doc = await resolver.resolve(to_did) except Exception as err: raise web.HTTPNotFound(reason=str(err)) from err @@ -78,9 +98,97 @@ async def connections_send_ping(request: web.BaseRequest): #msg = Ping(did=did, response_requested=response_requested) #await outbound_handler(msg, connection_id=connection_id) + #filter_did = request.query.get("did") + #filter_verkey = request.query.get("verkey") + filter_posture = DIDPosture.get(request.query.get("posture")) + results = [] + async with context.session() as session: + did_methods: DIDMethods = session.inject(DIDMethods) + filter_method: DIDMethod | None = did_methods.from_method( + request.query.get("method") or "did:peer:2" + ) + #key_types = session.inject(KeyTypes) + #filter_key_type = key_types.from_key_type(request.query.get("key_type", "")) + wallet: BaseWallet | None = session.inject_or(BaseWallet) + if not wallet: + raise web.HTTPForbidden(reason="No wallet available") + else: + dids = await wallet.get_local_dids() + results = [ + format_did_info(info) + for info in dids + if ( + filter_posture is None + or DIDPosture.get(info.metadata) is DIDPosture.WALLET_ONLY + ) + and (not filter_method or info.method == filter_method) + #and (not filter_key_type or info.key_type == filter_key_type) + ] + + results.sort(key=lambda info: (DIDPosture.get(info["posture"]).ordinal, info["did"])) + + # return web.json_response({"results": results}) + + async with context.session() as session: + ctx = session + messaging = ctx.inject(DIDCommMessaging) + routing_service = ctx.inject(RoutingService) + frm = to_did + services = await routing_service._resolve_services(messaging.resolver, frm) + chain = [ + { + "did": frm, + "service": services, + } + ] + + # Loop through service DIDs until we run out of DIDs to forward to + to_target = services[0].service_endpoint.uri + found_forwardable_service = await routing_service.is_forwardable_service( + messaging.resolver, services[0] + ) + while found_forwardable_service: + services = await routing_service._resolve_services(messaging.resolver, to_target) + if services: + chain.append( + { + "did": to_target, + "service": services, + } + ) + to_target = services[0].service_endpoint.uri + found_forwardable_service = ( + await routing_service.is_forwardable_service(messaging.resolver, services[0]) + if services + else False + ) + reply_destination = [ + ConnectionTarget( + did=f"{to_did}#key-1", + endpoint=service.service_endpoint.uri, + recipient_keys=[f"{to_did}#key-1"], + sender_key=results[0]["did"] + "#key-1", + ) + for service in chain[-1]["service"] + ] + + their_did = to_did + our_did = results[0]["did"] + msg = V2AgentMessage( + message={ + "type": "https://didcomm.org/trust-ping/2.0/ping", + "body": {}, + "to": [their_did], + "from": our_did, + } + ) + ## await responder.send_reply(error_result) + await outbound_handler(msg, target_list=reply_destination) + + #return web.json_response({"thread_id": msg._thread_id}) - return web.json_response({"thread_id": "blah"}) + return web.json_response(msg.message) async def register(app: web.Application):