async def create_response(self, connection: ConnectionRecord, my_endpoint: str = None) -> ConnectionResponse: """ Create a connection response for a received connection request. Args: connection: The `ConnectionRecord` with a pending connection request my_endpoint: The endpoint I can be reached at Returns: A tuple of the updated `ConnectionRecord` new `ConnectionResponse` message """ ConnectionRecord.log_state( self.context, "Creating connection response", {"connection_id": connection.connection_id}, ) if connection.state not in ( ConnectionRecord.STATE_REQUEST, ConnectionRecord.STATE_RESPONSE, ): raise ConnectionManagerError( "Connection is not in the request or response state") request = await connection.retrieve_request(self.context) wallet: BaseWallet = await self.context.inject(BaseWallet) if connection.my_did: my_info = await wallet.get_local_did(connection.my_did) else: my_info = await wallet.create_local_did() connection.my_did = my_info.did # Create connection response message if not my_endpoint: my_endpoints = [] default_endpoint = self.context.settings.get("default_endpoint") if default_endpoint: my_endpoints.append(default_endpoint) my_endpoints.extend( self.context.settings.get("additional_endpoints", [])) did_doc = await self.create_did_document( my_info, connection.inbound_connection_id, my_endpoints) response = ConnectionResponse( connection=ConnectionDetail(did=my_info.did, did_doc=did_doc)) # Assign thread information response.assign_thread_from(request) response.assign_trace_from(request) # Sign connection field using the invitation key wallet: BaseWallet = await self.context.inject(BaseWallet) await response.sign_field("connection", connection.invitation_key, wallet) # Update connection state connection.state = ConnectionRecord.STATE_RESPONSE await connection.save( self.context, reason="Created connection response", log_params={"response": response}, ) return response
async def receive_request(self, request: ConnectionRequest, receipt: MessageReceipt) -> ConnectionRecord: """ Receive and store a connection request. Args: request: The `ConnectionRequest` to accept receipt: The message receipt Returns: The new or updated `ConnectionRecord` instance """ ConnectionRecord.log_state(self.context, "Receiving connection request", {"request": request}) connection = None connection_key = None # Determine what key will need to sign the response if receipt.recipient_did_public: wallet: BaseWallet = await self.context.inject(BaseWallet) my_info = await wallet.get_local_did(receipt.recipient_did) connection_key = my_info.verkey else: connection_key = receipt.recipient_verkey try: connection = await ConnectionRecord.retrieve_by_invitation_key( self.context, connection_key, ConnectionRecord.INITIATOR_SELF) except StorageNotFoundError: raise ConnectionManagerError( "No invitation found for pairwise connection") invitation = None if connection: invitation = await connection.retrieve_invitation(self.context) connection_key = connection.invitation_key ConnectionRecord.log_state(self.context, "Found invitation", {"invitation": invitation}) if connection.is_multiuse_invitation: wallet: BaseWallet = await self.context.inject(BaseWallet) my_info = await wallet.create_local_did() new_connection = ConnectionRecord( initiator=ConnectionRecord.INITIATOR_MULTIUSE, invitation_key=connection_key, my_did=my_info.did, state=ConnectionRecord.STATE_INVITATION, accept=connection.accept, their_role=connection.their_role, ) await new_connection.save( self.context, reason= "Received connection request from multi-use invitation DID", ) connection = new_connection conn_did_doc = request.connection.did_doc if not conn_did_doc: raise ConnectionManagerError( "No DIDDoc provided; cannot connect to public DID") if request.connection.did != conn_did_doc.did: raise ConnectionManagerError( "Connection DID does not match DIDDoc id", error_code=ProblemReportReason.REQUEST_NOT_ACCEPTED, ) await self.store_did_document(conn_did_doc) if connection: connection.their_label = request.label connection.their_did = request.connection.did connection.state = ConnectionRecord.STATE_REQUEST await connection.save( self.context, reason="Received connection request from invitation") elif not self.context.settings.get("public_invites"): raise ConnectionManagerError("Public invitations are not enabled") else: my_info = await wallet.create_local_did() connection = ConnectionRecord( initiator=ConnectionRecord.INITIATOR_EXTERNAL, invitation_key=connection_key, my_did=my_info.did, their_did=request.connection.did, their_label=request.label, state=ConnectionRecord.STATE_REQUEST, ) if self.context.settings.get("debug.auto_accept_requests"): connection.accept = ConnectionRecord.ACCEPT_AUTO await connection.save( self.context, reason="Received connection request from public DID") # Attach the connection request so it can be found and responded to await connection.attach_request(self.context, request) if connection.accept == ConnectionRecord.ACCEPT_AUTO: response = await self.create_response(connection) responder: BaseResponder = await self._context.inject( BaseResponder, required=False) if responder: await responder.send_reply( response, connection_id=connection.connection_id) # refetch connection for accurate state connection = await ConnectionRecord.retrieve_by_id( self._context, connection.connection_id) else: self._logger.debug("Connection request will await acceptance") return connection