diff --git a/aries_cloudagent/ledger/base.py b/aries_cloudagent/ledger/base.py index 099cf92143..4b0ab0b8f3 100644 --- a/aries_cloudagent/ledger/base.py +++ b/aries_cloudagent/ledger/base.py @@ -6,6 +6,8 @@ from ..issuer.base import BaseIssuer +from .util import EndpointType + class BaseLedger(ABC, metaclass=ABCMeta): """Base class for ledger.""" @@ -39,20 +41,29 @@ async def get_key_for_did(self, did: str) -> str: """ @abstractmethod - async def get_endpoint_for_did(self, did: str) -> str: + async def get_endpoint_for_did( + self, did: str, endpoint_type: EndpointType = EndpointType.ENDPOINT + ) -> str: """Fetch the endpoint for a ledger DID. Args: did: The DID to look up on the ledger or in the cache + endpoint_type: The type of the endpoint (default 'endpoint') """ @abstractmethod - async def update_endpoint_for_did(self, did: str, endpoint: str) -> bool: + async def update_endpoint_for_did( + self, + did: str, + endpoint: str, + endpoint_type: EndpointType = EndpointType.ENDPOINT, + ) -> bool: """Check and update the endpoint on the ledger. Args: did: The ledger DID endpoint: The endpoint address + endpoint_type: The type of the endpoint (default 'endpoint') """ @abstractmethod diff --git a/aries_cloudagent/ledger/indy.py b/aries_cloudagent/ledger/indy.py index d38cb26ae3..7077fa6215 100644 --- a/aries_cloudagent/ledger/indy.py +++ b/aries_cloudagent/ledger/indy.py @@ -34,7 +34,7 @@ LedgerError, LedgerTransactionError, ) -from .util import TAA_ACCEPTED_RECORD_TYPE +from .util import TAA_ACCEPTED_RECORD_TYPE, EndpointType GENESIS_TRANSACTION_PATH = tempfile.gettempdir() @@ -753,12 +753,41 @@ async def get_key_for_did(self, did: str) -> str: data_json = (json.loads(response_json))["result"]["data"] return json.loads(data_json)["verkey"] if data_json else None - async def get_endpoint_for_did(self, did: str) -> str: + async def get_all_endpoints_for_did(self, did: str) -> dict: + """Fetch all endpoints for a ledger DID. + + Args: + did: The DID to look up on the ledger or in the cache + """ + nym = self.did_to_nym(did) + public_info = await self.wallet.get_public_did() + public_did = public_info.did if public_info else None + with IndyErrorHandler("Exception when building attribute request", LedgerError): + request_json = await indy.ledger.build_get_attrib_request( + public_did, nym, "endpoint", None, None + ) + response_json = await self._submit(request_json, sign_did=public_info) + data_json = json.loads(response_json)["result"]["data"] + + if data_json: + endpoints = json.loads(data_json).get("endpoint", None) + else: + endpoints = None + + return endpoints + + async def get_endpoint_for_did( + self, did: str, endpoint_type: EndpointType = None + ) -> str: """Fetch the endpoint for a ledger DID. Args: did: The DID to look up on the ledger or in the cache + endpoint_type: The type of the endpoint. If none given, returns all """ + + if not endpoint_type: + endpoint_type = EndpointType.ENDPOINT nym = self.did_to_nym(did) public_info = await self.wallet.get_public_did() public_did = public_info.did if public_info else None @@ -770,28 +799,46 @@ async def get_endpoint_for_did(self, did: str) -> str: data_json = json.loads(response_json)["result"]["data"] if data_json: endpoint = json.loads(data_json).get("endpoint", None) - address = endpoint.get("endpoint", None) if endpoint else None + address = endpoint.get(endpoint_type.value, None) if endpoint else None else: address = None return address - async def update_endpoint_for_did(self, did: str, endpoint: str) -> bool: + async def update_endpoint_for_did( + self, did: str, endpoint: str, endpoint_type: EndpointType = None + ) -> bool: """Check and update the endpoint on the ledger. Args: did: The ledger DID endpoint: The endpoint address + endpoint_type: The type of the endpoint """ - exist_endpoint = await self.get_endpoint_for_did(did) - if exist_endpoint != endpoint: + if not endpoint_type: + endpoint_type = EndpointType.ENDPOINT + + all_exist_endpoints = await self.get_all_endpoints_for_did(did) + exist_endpoint_of_type = ( + all_exist_endpoints.get(endpoint_type.value, None) + if all_exist_endpoints + else None + ) + + if exist_endpoint_of_type != endpoint: if self.read_only: raise LedgerError( "Error cannot update endpoint when ledger is in read only mode" ) nym = self.did_to_nym(did) - attr_json = json.dumps({"endpoint": {"endpoint": endpoint}}) + + if all_exist_endpoints: + all_exist_endpoints[endpoint_type.value] = endpoint + attr_json = json.dumps({"endpoint": all_exist_endpoints}) + else: + attr_json = json.dumps({"endpoint": {endpoint_type.value: endpoint}}) + with IndyErrorHandler( "Exception when building attribute request", LedgerError ): diff --git a/aries_cloudagent/ledger/routes.py b/aries_cloudagent/ledger/routes.py index c370f08be8..331630e726 100644 --- a/aries_cloudagent/ledger/routes.py +++ b/aries_cloudagent/ledger/routes.py @@ -6,13 +6,15 @@ from marshmallow import fields, validate from ..messaging.models.openapi import OpenAPISchema -from ..messaging.valid import INDY_DID, INDY_RAW_PUBLIC_KEY +from ..messaging.valid import ENDPOINT_TYPE, INDY_DID, INDY_RAW_PUBLIC_KEY from ..storage.error import StorageError from ..wallet.error import WalletError from .base import BaseLedger from .indy import Role from .error import BadLedgerRequestError, LedgerError, LedgerTransactionError +from .util import EndpointType + class AMLRecordSchema(OpenAPISchema): """Ledger AML record.""" @@ -83,6 +85,17 @@ class QueryStringDIDSchema(OpenAPISchema): did = fields.Str(description="DID of interest", required=True, **INDY_DID) +class QueryStringEndpointSchema(OpenAPISchema): + """Parameters and validators for query string with DID and endpoint type.""" + + did = fields.Str(description="DID of interest", required=True, **INDY_DID) + endpoint_type = fields.Str( + description="Endpoint type of interest (default 'endpoint')", + required=False, + **ENDPOINT_TYPE, + ) + + @docs( tags=["ledger"], summary="Send a NYM registration to the ledger.", ) @@ -185,7 +198,7 @@ async def get_did_verkey(request: web.BaseRequest): @docs( tags=["ledger"], summary="Get the endpoint for a DID from the ledger.", ) -@querystring_schema(QueryStringDIDSchema()) +@querystring_schema(QueryStringEndpointSchema()) async def get_did_endpoint(request: web.BaseRequest): """ Request handler for getting a verkey for a DID from the ledger. @@ -202,12 +215,14 @@ async def get_did_endpoint(request: web.BaseRequest): raise web.HTTPForbidden(reason=reason) did = request.query.get("did") + endpoint_type = EndpointType(request.query.get("endpoint_type", "endpoint")) + if not did: raise web.HTTPBadRequest(reason="Request query must include DID") async with ledger: try: - r = await ledger.get_endpoint_for_did(did) + r = await ledger.get_endpoint_for_did(did, endpoint_type) except LedgerError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err diff --git a/aries_cloudagent/ledger/tests/test_indy.py b/aries_cloudagent/ledger/tests/test_indy.py index be4dcce16b..028f7956c7 100644 --- a/aries_cloudagent/ledger/tests/test_indy.py +++ b/aries_cloudagent/ledger/tests/test_indy.py @@ -25,6 +25,8 @@ from aries_cloudagent.storage.record import StorageRecord from aries_cloudagent.wallet.base import DIDInfo +from ...ledger.util import EndpointType + class TestRole(AsyncTestCase): async def test_role(self): @@ -1651,6 +1653,101 @@ async def test_get_endpoint_for_did( ) assert response == endpoint + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") + @async_mock.patch("indy.ledger.build_get_attrib_request") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._submit") + async def test_get_endpoint_of_type_profile_for_did( + self, mock_submit, mock_build_get_attrib_req, mock_close, mock_open + ): + mock_wallet = async_mock.MagicMock() + mock_wallet.type = "indy" + + endpoint = "http://company.com/masterdata" + endpoint_type = EndpointType.PROFILE + mock_submit.return_value = json.dumps( + {"result": {"data": json.dumps({"endpoint": {"Profile": endpoint}})}} + ) + ledger = IndyLedger("name", mock_wallet) + + async with ledger: + mock_wallet.get_public_did = async_mock.CoroutineMock( + return_value=self.test_did_info + ) + response = await ledger.get_endpoint_for_did(self.test_did, endpoint_type) + + assert mock_build_get_attrib_req.called_once_with( + self.test_did, ledger.did_to_nym(self.test_did), "endpoint", None, None + ) + assert mock_submit.called_once_with( + mock_build_get_attrib_req.return_value, + sign_did=mock_wallet.get_public_did.return_value, + ) + assert response == endpoint + + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") + @async_mock.patch("indy.ledger.build_get_attrib_request") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._submit") + async def test_get_all_endpoints_for_did( + self, mock_submit, mock_build_get_attrib_req, mock_close, mock_open + ): + mock_wallet = async_mock.MagicMock() + mock_wallet.type = "indy" + + profile_endpoint = "http://company.com/masterdata" + default_endpoint = "http://agent.company.com" + data_json = json.dumps( + {"endpoint": {"endpoint": default_endpoint, "Profile": profile_endpoint}} + ) + mock_submit.return_value = json.dumps({"result": {"data": data_json}}) + ledger = IndyLedger("name", mock_wallet) + + async with ledger: + mock_wallet.get_public_did = async_mock.CoroutineMock( + return_value=self.test_did_info + ) + response = await ledger.get_all_endpoints_for_did(self.test_did) + + assert mock_build_get_attrib_req.called_once_with( + self.test_did, ledger.did_to_nym(self.test_did), "endpoint", None, None + ) + assert mock_submit.called_once_with( + mock_build_get_attrib_req.return_value, + sign_did=mock_wallet.get_public_did.return_value, + ) + assert response == json.loads(data_json).get("endpoint") + + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") + @async_mock.patch("indy.ledger.build_get_attrib_request") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._submit") + async def test_get_all_endpoints_for_did_none( + self, mock_submit, mock_build_get_attrib_req, mock_close, mock_open + ): + mock_wallet = async_mock.MagicMock() + mock_wallet.type = "indy" + + profile_endpoint = "http://company.com/masterdata" + default_endpoint = "http://agent.company.com" + mock_submit.return_value = json.dumps({"result": {"data": None}}) + ledger = IndyLedger("name", mock_wallet) + + async with ledger: + mock_wallet.get_public_did = async_mock.CoroutineMock( + return_value=self.test_did_info + ) + response = await ledger.get_all_endpoints_for_did(self.test_did) + + assert mock_build_get_attrib_req.called_once_with( + self.test_did, ledger.did_to_nym(self.test_did), "endpoint", None, None + ) + assert mock_submit.called_once_with( + mock_build_get_attrib_req.return_value, + sign_did=mock_wallet.get_public_did.return_value, + ) + assert response is None + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") @async_mock.patch("indy.ledger.build_get_attrib_request") @@ -1758,6 +1855,101 @@ async def test_update_endpoint_for_did( ) assert response + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") + @async_mock.patch("indy.ledger.build_get_attrib_request") + @async_mock.patch("indy.ledger.build_attrib_request") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._submit") + async def test_update_endpoint_for_did_no_prior_endpoints( + self, + mock_submit, + mock_build_attrib_req, + mock_build_get_attrib_req, + mock_close, + mock_open, + ): + mock_wallet = async_mock.MagicMock() + mock_wallet.type = "indy" + + endpoint = "http://new.aries.ca" + ledger = IndyLedger("name", mock_wallet) + + async with ledger: + with async_mock.patch.object( + ledger, "get_all_endpoints_for_did", async_mock.CoroutineMock() + ) as mock_get_all: + mock_get_all.return_value = None + mock_wallet.get_public_did = async_mock.CoroutineMock( + return_value=self.test_did_info + ) + response = await ledger.update_endpoint_for_did(self.test_did, endpoint) + + assert mock_build_get_attrib_req.called_once_with( + self.test_did, + ledger.did_to_nym(self.test_did), + "endpoint", + None, + None, + ) + mock_submit.assert_has_calls( + [async_mock.call(mock_build_attrib_req.return_value, True, True),] + ) + assert response + + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") + @async_mock.patch("indy.ledger.build_get_attrib_request") + @async_mock.patch("indy.ledger.build_attrib_request") + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._submit") + async def test_update_endpoint_of_type_profile_for_did( + self, + mock_submit, + mock_build_attrib_req, + mock_build_get_attrib_req, + mock_close, + mock_open, + ): + mock_wallet = async_mock.MagicMock() + mock_wallet.type = "indy" + + endpoint = ["http://company.com/oldProfile", "http://company.com/newProfile"] + endpoint_type = EndpointType.PROFILE + mock_submit.side_effect = [ + json.dumps( + { + "result": { + "data": json.dumps( + {"endpoint": {endpoint_type.value: endpoint[i]}} + ) + } + } + ) + for i in range(len(endpoint)) + ] + ledger = IndyLedger("name", mock_wallet) + + async with ledger: + mock_wallet.get_public_did = async_mock.CoroutineMock( + return_value=self.test_did_info + ) + response = await ledger.update_endpoint_for_did( + self.test_did, endpoint[1], endpoint_type + ) + + assert mock_build_get_attrib_req.called_once_with( + self.test_did, ledger.did_to_nym(self.test_did), "endpoint", None, None + ) + mock_submit.assert_has_calls( + [ + async_mock.call( + mock_build_get_attrib_req.return_value, + sign_did=mock_wallet.get_public_did.return_value, + ), + async_mock.call(mock_build_attrib_req.return_value, True, True), + ] + ) + assert response + @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open") @async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close") @async_mock.patch("indy.ledger.build_get_attrib_request") diff --git a/aries_cloudagent/ledger/tests/test_routes.py b/aries_cloudagent/ledger/tests/test_routes.py index f0de4ba4df..24c409fcbe 100644 --- a/aries_cloudagent/ledger/tests/test_routes.py +++ b/aries_cloudagent/ledger/tests/test_routes.py @@ -4,6 +4,7 @@ from ...config.injection_context import InjectionContext from ...ledger.base import BaseLedger +from ...ledger.util import EndpointType from .. import routes as test_module @@ -21,6 +22,8 @@ def setUp(self): self.test_did = "did" self.test_verkey = "verkey" self.test_endpoint = "http://localhost:8021" + self.test_endpoint_type = EndpointType.PROFILE + self.test_endpoint_type_profile = "http://company.com/profile" async def test_missing_ledger(self): request = async_mock.MagicMock(app=self.app,) @@ -89,6 +92,22 @@ async def test_get_endpoint(self): ) assert result is json_response.return_value + async def test_get_endpoint_of_type_profile(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did, "endpoint_type": self.test_endpoint_type} + with async_mock.patch.object( + test_module.web, "json_response", async_mock.Mock() + ) as json_response: + self.ledger.get_endpoint_for_did.return_value = ( + self.test_endpoint_type_profile + ) + result = await test_module.get_did_endpoint(request) + json_response.assert_called_once_with( + {"endpoint": self.ledger.get_endpoint_for_did.return_value} + ) + assert result is json_response.return_value + async def test_get_endpoint_no_did(self): request = async_mock.MagicMock() request.app = self.app diff --git a/aries_cloudagent/ledger/util.py b/aries_cloudagent/ledger/util.py index 558ea411a9..09b2a33460 100644 --- a/aries_cloudagent/ledger/util.py +++ b/aries_cloudagent/ledger/util.py @@ -1,3 +1,13 @@ """Ledger utilities.""" +from enum import Enum + TAA_ACCEPTED_RECORD_TYPE = "taa_accepted" + + +class EndpointType(Enum): + """Enum for endpoint/service types.""" + + ENDPOINT = "endpoint" + PROFILE = "Profile" + LINKED_DOMAINS = "LinkedDomains" diff --git a/aries_cloudagent/messaging/valid.py b/aries_cloudagent/messaging/valid.py index f5552d3410..a3dfa2dfcc 100644 --- a/aries_cloudagent/messaging/valid.py +++ b/aries_cloudagent/messaging/valid.py @@ -10,6 +10,8 @@ from .util import epoch_to_str +from ..ledger.util import EndpointType as EndpointTypeEnum + B58 = alphabet if isinstance(alphabet, str) else alphabet.decode("ascii") @@ -426,6 +428,20 @@ def __init__(self): ) +class EndpointType(OneOf): + """Validate value against allowed endpoint/service types.""" + + EXAMPLE = "endpoint" + + def __init__(self): + """Initializer.""" + + super().__init__( + choices=[e.value for e in EndpointTypeEnum], + error="Value {input} must be one of {choices}", + ) + + # Instances for marshmallow schema specification INT_EPOCH = {"validate": IntEpoch(), "example": IntEpoch.EXAMPLE} WHOLE_NUM = {"validate": WholeNumber(), "example": WholeNumber.EXAMPLE} @@ -460,3 +476,4 @@ def __init__(self): } UUID4 = {"validate": UUIDFour(), "example": UUIDFour.EXAMPLE} ENDPOINT = {"validate": Endpoint(), "example": Endpoint.EXAMPLE} +ENDPOINT_TYPE = {"validate": EndpointType(), "example": EndpointType.EXAMPLE} diff --git a/aries_cloudagent/wallet/base.py b/aries_cloudagent/wallet/base.py index ac23724bba..caac3d6e07 100644 --- a/aries_cloudagent/wallet/base.py +++ b/aries_cloudagent/wallet/base.py @@ -5,6 +5,7 @@ from typing import Sequence from ..ledger.base import BaseLedger +from ..ledger.util import EndpointType KeyInfo = namedtuple("KeyInfo", "verkey metadata") @@ -271,21 +272,30 @@ async def replace_local_did_metadata(self, did: str, metadata: dict): """ - async def set_did_endpoint(self, did: str, endpoint: str, ledger: BaseLedger): + async def set_did_endpoint( + self, + did: str, + endpoint: str, + ledger: BaseLedger, + endpoint_type: EndpointType = None, + ): """ Update the endpoint for a DID in the wallet, send to ledger if public. Args: did: DID for which to set endpoint endpoint: the endpoint to set, None to clear - ledger: the ledger to which to send endpoint update - if DID is public - specify None for basic wallet - + ledger: the ledger to which to send endpoint update if DID is public + endpoint_type: the type of the endpoint/service. Only endpoint_type + 'endpoint' affects local wallet """ did_info = await self.get_local_did(did) metadata = {**did_info.metadata} - metadata.pop("endpoint", None) - metadata["endpoint"] = endpoint + if not endpoint_type: + endpoint_type = EndpointType.ENDPOINT + if endpoint_type == EndpointType.ENDPOINT: + metadata.pop("endpoint", None) + metadata["endpoint"] = endpoint await self.replace_local_did_metadata(did, metadata) diff --git a/aries_cloudagent/wallet/indy.py b/aries_cloudagent/wallet/indy.py index 0edc5c281b..70f9e23431 100644 --- a/aries_cloudagent/wallet/indy.py +++ b/aries_cloudagent/wallet/indy.py @@ -20,6 +20,8 @@ from .plugin import load_postgres_plugin from .util import bytes_to_b64 +from ..ledger.util import EndpointType + class IndyWallet(BaseWallet): """Indy wallet implementation.""" @@ -549,7 +551,13 @@ async def replace_local_did_metadata(self, did: str, metadata: dict): await self.get_local_did(did) # throw exception if undefined await indy.did.set_did_metadata(self.handle, did, meta_json) - async def set_did_endpoint(self, did: str, endpoint: str, ledger: BaseLedger): + async def set_did_endpoint( + self, + did: str, + endpoint: str, + ledger: BaseLedger, + endpoint_type: EndpointType = None, + ): """ Update the endpoint for a DID in the wallet, send to ledger if public. @@ -557,12 +565,16 @@ async def set_did_endpoint(self, did: str, endpoint: str, ledger: BaseLedger): did: DID for which to set endpoint endpoint: the endpoint to set, None to clear ledger: the ledger to which to send endpoint update if DID is public - + endpoint_type: the type of the endpoint/service. Only endpoint_type + 'endpoint' affects local wallet """ did_info = await self.get_local_did(did) metadata = {**did_info.metadata} - metadata.pop("endpoint", None) - metadata["endpoint"] = endpoint + if not endpoint_type: + endpoint_type = EndpointType.ENDPOINT + if endpoint_type == EndpointType.ENDPOINT: + metadata.pop("endpoint", None) + metadata["endpoint"] = endpoint wallet_public_didinfo = await self.get_public_did() if wallet_public_didinfo and wallet_public_didinfo.did == did: @@ -572,7 +584,7 @@ async def set_did_endpoint(self, did: str, endpoint: str, ledger: BaseLedger): f"No ledger available but DID {did} is public: missing wallet-type?" ) async with ledger: - await ledger.update_endpoint_for_did(did, endpoint) + await ledger.update_endpoint_for_did(did, endpoint, endpoint_type) await self.replace_local_did_metadata(did, metadata) diff --git a/aries_cloudagent/wallet/routes.py b/aries_cloudagent/wallet/routes.py index 860e802eb2..ca3a91281d 100644 --- a/aries_cloudagent/wallet/routes.py +++ b/aries_cloudagent/wallet/routes.py @@ -16,11 +16,19 @@ from ..ledger.base import BaseLedger from ..ledger.error import LedgerConfigError, LedgerError from ..messaging.models.openapi import OpenAPISchema -from ..messaging.valid import ENDPOINT, INDY_CRED_DEF_ID, INDY_DID, INDY_RAW_PUBLIC_KEY +from ..messaging.valid import ( + ENDPOINT, + ENDPOINT_TYPE, + INDY_CRED_DEF_ID, + INDY_DID, + INDY_RAW_PUBLIC_KEY, +) from .base import DIDInfo, BaseWallet from .error import WalletError, WalletNotFoundError +from ..ledger.util import EndpointType + class DIDSchema(OpenAPISchema): """Result schema for a DID.""" @@ -42,6 +50,21 @@ class DIDListSchema(OpenAPISchema): results = fields.List(fields.Nested(DIDSchema()), description="DID list") +class DIDEndpointWithTypeSchema(OpenAPISchema): + """Request schema to set DID endpoint of particular type.""" + + did = fields.Str(description="DID of interest", required=True, **INDY_DID) + endpoint = fields.Str( + description="Endpoint to set (omit to delete)", required=False, **ENDPOINT + ) + endpoint_type = fields.Str( + description=""" + Endpoint type to set (default 'endpoint'). Affects only public DIDs.""", + required=False, + **ENDPOINT_TYPE, + ) + + class DIDEndpointSchema(OpenAPISchema): """Request schema to set DID endpoint; response schema to get DID endpoint.""" @@ -252,7 +275,7 @@ async def wallet_set_public_did(request: web.BaseRequest): @docs(tags=["wallet"], summary="Update endpoint in wallet and, if public, on ledger") -@request_schema(DIDEndpointSchema) +@request_schema(DIDEndpointWithTypeSchema) async def wallet_set_did_endpoint(request: web.BaseRequest): """ Request handler for setting an endpoint for a public or local DID. @@ -268,10 +291,11 @@ async def wallet_set_did_endpoint(request: web.BaseRequest): body = await request.json() did = body["did"] endpoint = body.get("endpoint") + endpoint_type = EndpointType(body.get("endpoint_type", "endpoint")) try: ledger: BaseLedger = await context.inject(BaseLedger, required=False) - await wallet.set_did_endpoint(did, endpoint, ledger) + await wallet.set_did_endpoint(did, endpoint, ledger, endpoint_type) except WalletNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err except LedgerConfigError as err: