diff --git a/aries_cloudagent/ledger/indy.py b/aries_cloudagent/ledger/indy.py index 92e048bab3..72e640db22 100644 --- a/aries_cloudagent/ledger/indy.py +++ b/aries_cloudagent/ledger/indy.py @@ -744,7 +744,7 @@ async def get_key_for_did(self, did: str) -> str: request_json = await indy.ledger.build_get_nym_request(public_did, nym) response_json = await self._submit(request_json, sign_did=public_info) data_json = (json.loads(response_json))["result"]["data"] - return json.loads(data_json)["verkey"] + return json.loads(data_json)["verkey"] if data_json else None async def get_endpoint_for_did(self, did: str) -> str: """Fetch the endpoint for a ledger DID. diff --git a/aries_cloudagent/ledger/routes.py b/aries_cloudagent/ledger/routes.py index db3b1ddd19..bf6105865f 100644 --- a/aries_cloudagent/ledger/routes.py +++ b/aries_cloudagent/ledger/routes.py @@ -173,6 +173,8 @@ async def get_did_verkey(request: web.BaseRequest): async with ledger: try: result = await ledger.get_key_for_did(did) + if not result: + raise web.HTTPNotFound(reason=f"DID {did} is not on the ledger") except LedgerError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err diff --git a/aries_cloudagent/ledger/tests/test_routes.py b/aries_cloudagent/ledger/tests/test_routes.py index e500f99b1c..a040bcda86 100644 --- a/aries_cloudagent/ledger/tests/test_routes.py +++ b/aries_cloudagent/ledger/tests/test_routes.py @@ -59,6 +59,14 @@ async def test_get_verkey_no_did(self): with self.assertRaises(test_module.web.HTTPBadRequest): await test_module.get_did_verkey(request) + async def test_get_verkey_did_not_public(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did} + self.ledger.get_key_for_did.return_value = None + with self.assertRaises(test_module.web.HTTPNotFound): + await test_module.get_did_verkey(request) + async def test_get_verkey_x(self): request = async_mock.MagicMock() request.app = self.app @@ -196,6 +204,16 @@ async def test_get_taa_required(self): json_response.assert_called_once_with({"result": taa_info}) assert result is json_response.return_value + async def test_get_taa_x(self): + request = async_mock.MagicMock() + request.app = self.app + + self.ledger.LEDGER_TYPE = "indy" + self.ledger.get_txn_author_agreement.side_effect = test_module.LedgerError() + + with self.assertRaises(test_module.web.HTTPBadRequest): + await test_module.ledger_get_taa(request) + async def test_taa_accept_not_required(self): request = async_mock.MagicMock() request.app = self.app diff --git a/aries_cloudagent/messaging/schemas/routes.py b/aries_cloudagent/messaging/schemas/routes.py index def0e3655a..5515570f29 100644 --- a/aries_cloudagent/messaging/schemas/routes.py +++ b/aries_cloudagent/messaging/schemas/routes.py @@ -12,12 +12,13 @@ ) from marshmallow import fields, Schema +from marshmallow.validate import Regexp from ...issuer.base import BaseIssuer, IssuerError from ...ledger.base import BaseLedger from ...ledger.error import LedgerError from ...storage.base import BaseStorage -from ..valid import NATURAL_NUM, INDY_SCHEMA_ID, INDY_VERSION +from ..valid import B58, NATURAL_NUM, INDY_SCHEMA_ID, INDY_VERSION from .util import SchemaQueryStringSchema, SCHEMA_SENT_RECORD_TYPE, SCHEMA_TAGS @@ -38,8 +39,10 @@ class SchemaSendRequestSchema(Schema): class SchemaSendResultsSchema(Schema): """Results schema for schema send request.""" - schema_id = fields.Str(description="Schema identifier", **INDY_SCHEMA_ID) - schema = fields.Dict(description="Schema result") + schema_id = fields.Str( + description="Schema identifier", required=True, **INDY_SCHEMA_ID + ) + schema = fields.Dict(description="Schema result", required=True) class SchemaSchema(Schema): @@ -77,7 +80,10 @@ class SchemaIdMatchInfoSchema(Schema): """Path parameters and validators for request taking schema id.""" schema_id = fields.Str( - description="Schema identifier", required=True, **INDY_SCHEMA_ID, + description="Schema identifier", + required=True, + validate=Regexp(rf"^[1-9][0-9]*|[{B58}]{{21,22}}:2:.+:[0-9.]+$"), + example=INDY_SCHEMA_ID["example"], ) diff --git a/aries_cloudagent/messaging/schemas/tests/test_routes.py b/aries_cloudagent/messaging/schemas/tests/test_routes.py index 67a699707b..946187af3d 100644 --- a/aries_cloudagent/messaging/schemas/tests/test_routes.py +++ b/aries_cloudagent/messaging/schemas/tests/test_routes.py @@ -119,6 +119,16 @@ async def test_get_schema(self): assert result == mock_response.return_value mock_response.assert_called_once_with({"schema": {"schema": "def"}}) + async def test_get_schema_on_seq_no(self): + mock_request = async_mock.MagicMock( + app=self.app, match_info={"schema_id": "12345"}, + ) + + with async_mock.patch.object(test_module.web, "json_response") as mock_response: + result = await test_module.schemas_get_schema(mock_request) + assert result == mock_response.return_value + mock_response.assert_called_once_with({"schema": {"schema": "def"}}) + async def test_get_schema_no_ledger(self): mock_request = async_mock.MagicMock( app=self.app, match_info={"schema_id": SCHEMA_ID}, diff --git a/aries_cloudagent/wallet/indy.py b/aries_cloudagent/wallet/indy.py index 76d622604a..da8698b800 100644 --- a/aries_cloudagent/wallet/indy.py +++ b/aries_cloudagent/wallet/indy.py @@ -671,6 +671,7 @@ async def unpack_message(self, enc_message: bytes) -> (str, str, str): from_verkey = unpacked.get("sender_verkey", None) return message, from_verkey, to_verkey + ''' async def get_credential_definition_tag_policy(self, credential_definition_id: str): """Return the tag policy for a given credential definition ID.""" try: @@ -716,6 +717,7 @@ async def set_credential_definition_tag_policy( raise IndyErrorHandler.wrap_error( x_indy, "Wallet {} error".format(self.name), WalletError ) from x_indy + ''' @classmethod async def generate_wallet_key(self, seed: str = None) -> str: diff --git a/aries_cloudagent/wallet/routes.py b/aries_cloudagent/wallet/routes.py index 6aff9ace55..f2a978f051 100644 --- a/aries_cloudagent/wallet/routes.py +++ b/aries_cloudagent/wallet/routes.py @@ -5,7 +5,7 @@ from aiohttp import web from aiohttp_apispec import ( docs, - match_info_schema, + # match_info_schema, querystring_schema, request_schema, response_schema, @@ -14,10 +14,11 @@ from marshmallow import fields, Schema from ..ledger.base import BaseLedger -from ..messaging.valid import INDY_CRED_DEF_ID, INDY_DID, INDY_RAW_PUBLIC_KEY +from ..ledger.error import LedgerError +from ..messaging.valid import ENDPOINT, INDY_CRED_DEF_ID, INDY_DID, INDY_RAW_PUBLIC_KEY from .base import DIDInfo, BaseWallet -from .error import WalletError +from .error import WalletError, WalletNotFoundError class DIDSchema(Schema): @@ -40,23 +41,12 @@ class DIDListSchema(Schema): results = fields.List(fields.Nested(DIDSchema()), description="DID list") -class GetTagPolicyResultSchema(Schema): - """Result schema for tagging policy get request.""" +class DIDEndpointSchema(Schema): + """Request schema to set DID endpoint; response schema to get DID endpoint.""" - taggables = fields.List( - fields.Str(description="Taggable attribute", example="score"), - description=( - "List of attributes taggable for credential search under current policy" - ), - ) - - -class SetTagPolicyRequestSchema(Schema): - """Request schema for tagging policy set request.""" - - taggables = fields.List( - fields.Str(description="Taggable attribute", example="score"), - description="List of attributes to set taggable for credential search", + did = fields.Str(description="DID of interest", required=True, **INDY_DID) + endpoint = fields.Str( + description="Endpoint to set (omit to delete)", required=False, **ENDPOINT ) @@ -163,7 +153,7 @@ async def wallet_did_list(request: web.BaseRequest): @response_schema(DIDResultSchema, 200) async def wallet_create_did(request: web.BaseRequest): """ - Request handler for creating a new wallet DID. + Request handler for creating a new local DID in the wallet. Args: request: aiohttp request object @@ -230,97 +220,119 @@ async def wallet_set_public_did(request: web.BaseRequest): did = request.query.get("did") if not did: raise web.HTTPBadRequest(reason="Request query must include DID") + try: - await wallet.get_local_did(did) - except WalletError as err: - # DID not found or not in valid format - raise web.HTTPBadRequest(reason=err.roll_up) from err - info = await wallet.set_public_did(did) - if info: - # Publish endpoint if necessary - endpoint = context.settings.get("default_endpoint") ledger = await context.inject(BaseLedger, required=False) - if ledger: + if not ledger: + reason = f"No ledger available" + if not context.settings.get_value("wallet.type"): + reason += ": missing wallet-type?" + raise web.HTTPForbidden(reason=reason) + + async with ledger: + if not await ledger.get_key_for_did(did): + raise web.HTTPNotFound(reason=f"DID {did} is not public") + + did_info = await wallet.get_local_did(did) + info = await wallet.set_public_did(did) + if info: + # Publish endpoint if necessary + endpoint = did_info.metadata.get( + "endpoint", context.settings.get("default_endpoint") + ) async with ledger: await ledger.update_endpoint_for_did(info.did, endpoint) + except WalletNotFoundError as err: + raise web.HTTPNotFound(reason=err.roll_up) from err + except (LedgerError, WalletError) as err: + raise web.HTTPBadRequest(reason=err.roll_up) from err return web.json_response({"result": format_did_info(info)}) -@docs(tags=["wallet"], summary="Rotate keypair for a local non-public DID") -@querystring_schema(DIDQueryStringSchema()) -async def wallet_rotate_did_keypair(request: web.BaseRequest): +@docs(tags=["wallet"], summary="Update endpoint in wallet and, if public, on ledger") +@request_schema(DIDEndpointSchema) +async def wallet_set_did_endpoint(request: web.BaseRequest): """ - Request handler for rotating local DID keypair. + Request handler for setting an endpoint for a public or local DID. Args: request: aiohttp request object - - Returns: - An empty JSON response - """ context = request.app["request_context"] wallet: BaseWallet = await context.inject(BaseWallet, required=False) if not wallet: raise web.HTTPForbidden(reason="No wallet available") - did = request.query.get("did") - if not did: - raise web.HTTPBadRequest(reason="Request query must include DID") + + body = await request.json() + did = body["did"] + endpoint = body.get("endpoint") + try: did_info = await wallet.get_local_did(did) - except WalletError as err: - # DID not found or not in valid format - raise web.HTTPBadRequest(reason=err.roll_up) from err - else: - if did_info.metadata.get("public", False): - # call from ledger API to propagate through ledger NYM transaction - raise web.HTTPBadRequest(reason=f"DID {did} is public") + metadata = {**did_info.metadata} + if "endpoint" in metadata: + metadata.pop("endpoint") + metadata["endpoint"] = endpoint # set null to clear so making public sends null + + wallet_public_didinfo = await wallet.get_public_did() + if wallet_public_didinfo and wallet_public_didinfo.did == did: + # if public DID, set endpoint on ledger first + ledger = await context.inject(BaseLedger, required=False) + if not ledger: + reason = f"No ledger available but DID {did} is public" + if not context.settings.get_value("wallet.type"): + reason += ": missing wallet-type?" + raise web.HTTPForbidden(reason=reason) + async with ledger: + await ledger.update_endpoint_for_did(did, endpoint) - await wallet.rotate_did_keypair_start(did) # do not take seed over the wire - await wallet.rotate_did_keypair_apply(did) + await wallet.replace_local_did_metadata(did, metadata) + except WalletNotFoundError as err: + raise web.HTTPNotFound(reason=err.roll_up) from err + except (LedgerError, WalletError) as err: + raise web.HTTPBadRequest(reason=err.roll_up) from err return web.json_response({}) -@docs(tags=["wallet"], summary="Get the tagging policy for a credential definition") -@match_info_schema(CredDefIdMatchInfoSchema()) -@response_schema(GetTagPolicyResultSchema()) -async def wallet_get_tagging_policy(request: web.BaseRequest): +@docs(tags=["wallet"], summary="Query DID endpoint in wallet") +@querystring_schema(DIDQueryStringSchema()) +@response_schema(DIDEndpointSchema, 200) +async def wallet_get_did_endpoint(request: web.BaseRequest): """ - Request handler for getting the tag policy associated with a cred def. + Request handler for getting the current DID endpoint from the wallet. Args: request: aiohttp request object Returns: - A JSON object containing the tagging policy + The updated DID info """ context = request.app["request_context"] - - credential_definition_id = request.match_info["cred_def_id"] - wallet: BaseWallet = await context.inject(BaseWallet, required=False) - if not wallet or wallet.WALLET_TYPE != "indy": - raise web.HTTPForbidden(reason="No indy wallet available") - + if not wallet: + raise web.HTTPForbidden(reason="No wallet available") + did = request.query.get("did") + if not did: + raise web.HTTPBadRequest(reason="Request query must include DID") try: - result = await wallet.get_credential_definition_tag_policy( - credential_definition_id - ) + did_info = await wallet.get_local_did(did) + endpoint = did_info.metadata.get("endpoint") + except WalletNotFoundError as err: + raise web.HTTPNotFound(reason=err.roll_up) from err except WalletError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err - return web.json_response({"taggables": result}) + return web.json_response({"did": did, "endpoint": endpoint}) -@docs(tags=["wallet"], summary="Set the tagging policy for a credential definition") -@match_info_schema(CredDefIdMatchInfoSchema()) -@request_schema(SetTagPolicyRequestSchema()) -async def wallet_set_tagging_policy(request: web.BaseRequest): +@docs(tags=["wallet"], summary="Rotate keypair for a local non-public DID") +@querystring_schema(DIDQueryStringSchema()) +async def wallet_rotate_did_keypair(request: web.BaseRequest): """ - Request handler for setting the tag policy associated with a cred def. + Request handler for rotating local DID keypair. Args: request: aiohttp request object @@ -330,19 +342,21 @@ async def wallet_set_tagging_policy(request: web.BaseRequest): """ context = request.app["request_context"] - - credential_definition_id = request.match_info["cred_def_id"] - - body = await request.json() - taggables = body.get("taggables") # None for all attrs, [] for no attrs - wallet: BaseWallet = await context.inject(BaseWallet, required=False) - if not wallet or wallet.WALLET_TYPE != "indy": - raise web.HTTPForbidden(reason="No indy wallet available") + if not wallet: + raise web.HTTPForbidden(reason="No wallet available") + did = request.query.get("did") + if not did: + raise web.HTTPBadRequest(reason="Request query must include DID") try: - await wallet.set_credential_definition_tag_policy( - credential_definition_id, taggables - ) + did_info = await wallet.get_local_did(did) + if did_info.metadata.get("public", False): + # call from ledger API instead to propagate through ledger NYM transaction + raise web.HTTPBadRequest(reason=f"DID {did} is public") + await wallet.rotate_did_keypair_start(did) # do not take seed over the wire + await wallet.rotate_did_keypair_apply(did) + except WalletNotFoundError as err: + raise web.HTTPNotFound(reason=err.roll_up) from err except WalletError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err @@ -358,13 +372,11 @@ async def register(app: web.Application): web.post("/wallet/did/create", wallet_create_did), web.get("/wallet/did/public", wallet_get_public_did, allow_head=False), web.post("/wallet/did/public", wallet_set_public_did), - web.patch("/wallet/did/local/rotate-keypair", wallet_rotate_did_keypair), + web.post("/wallet/set-did-endpoint", wallet_set_did_endpoint), web.get( - "/wallet/tag-policy/{cred_def_id}", - wallet_get_tagging_policy, - allow_head=False, + "/wallet/get-did-endpoint", wallet_get_did_endpoint, allow_head=False ), - web.post("/wallet/tag-policy/{cred_def_id}", wallet_set_tagging_policy), + web.patch("/wallet/did/local/rotate-keypair", wallet_rotate_did_keypair), ] ) diff --git a/aries_cloudagent/wallet/tests/test_indy_wallet.py b/aries_cloudagent/wallet/tests/test_indy_wallet.py index e583417a16..a3e8605233 100644 --- a/aries_cloudagent/wallet/tests/test_indy_wallet.py +++ b/aries_cloudagent/wallet/tests/test_indy_wallet.py @@ -60,6 +60,7 @@ async def test_properties(self, wallet): assert wallet.master_secret_id == wallet.name assert wallet._wallet_config + """ @pytest.mark.asyncio async def test_catpol(self, wallet): with pytest.raises(test_module.WalletError): @@ -80,6 +81,7 @@ async def test_catpol(self, wallet): with pytest.raises(test_module.WalletError) as excinfo: await wallet.set_credential_definition_tag_policy(CD_ID) assert "outlier" in str(excinfo.value) + """ @pytest.mark.asyncio async def test_rotate_did_keypair_x(self, wallet): diff --git a/aries_cloudagent/wallet/tests/test_routes.py b/aries_cloudagent/wallet/tests/test_routes.py index e39257b5e9..e42f8c2208 100644 --- a/aries_cloudagent/wallet/tests/test_routes.py +++ b/aries_cloudagent/wallet/tests/test_routes.py @@ -9,7 +9,6 @@ from ...wallet.base import BaseWallet, DIDInfo from .. import routes as test_module -from ..error import WalletNotFoundError class TestWalletRoutes(AsyncTestCase): @@ -41,6 +40,12 @@ async def test_missing_wallet(self): with self.assertRaises(HTTPForbidden): await test_module.wallet_set_public_did(request) + with self.assertRaises(HTTPForbidden): + await test_module.wallet_set_did_endpoint(request) + + with self.assertRaises(HTTPForbidden): + await test_module.wallet_get_did_endpoint(request) + def test_format_did_info(self): did_info = DIDInfo(self.test_did, self.test_verkey, {}) result = test_module.format_did_info(did_info) @@ -229,6 +234,14 @@ async def test_set_public_did(self): request = async_mock.MagicMock() request.app = self.app request.query = {"did": self.test_did} + + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.get_key_for_did = async_mock.CoroutineMock() + self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + with async_mock.patch.object( test_module.web, "json_response", async_mock.Mock() ) as json_response, async_mock.patch.object( @@ -247,7 +260,7 @@ async def test_set_public_did(self): ) assert result is json_response.return_value - async def test_set_public_did_no_did(self): + async def test_set_public_did_no_query_did(self): request = async_mock.MagicMock() request.app = self.app request.query = {} @@ -255,15 +268,91 @@ async def test_set_public_did_no_did(self): with self.assertRaises(test_module.web.HTTPBadRequest): await test_module.wallet_set_public_did(request) + async def test_set_public_did_no_ledger(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did} + + with self.assertRaises(test_module.web.HTTPForbidden): + await test_module.wallet_set_public_did(request) + + async def test_set_public_did_not_public(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did} + + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.get_key_for_did = async_mock.CoroutineMock(return_value=None) + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + with self.assertRaises(test_module.web.HTTPNotFound): + await test_module.wallet_set_public_did(request) + async def test_set_public_did_not_found(self): request = async_mock.MagicMock() request.app = self.app request.query = {"did": self.test_did} - self.wallet.get_local_did.side_effect = test_module.WalletError() - with self.assertRaises(test_module.web.HTTPBadRequest): + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.get_key_for_did = async_mock.CoroutineMock(return_value=None) + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + self.wallet.get_local_did.side_effect = test_module.WalletNotFoundError() + with self.assertRaises(test_module.web.HTTPNotFound): await test_module.wallet_set_public_did(request) + async def test_set_public_did_x(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did} + + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.get_key_for_did = async_mock.CoroutineMock() + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + with async_mock.patch.object( + test_module.web, "json_response", async_mock.Mock() + ) as json_response, async_mock.patch.object( + test_module, "format_did_info", async_mock.Mock() + ) as format_did_info: + self.wallet.get_public_did.return_value = DIDInfo( + self.test_did, self.test_verkey, {} + ) + self.wallet.set_public_did.side_effect = test_module.WalletError() + with self.assertRaises(test_module.web.HTTPBadRequest): + await test_module.wallet_set_public_did(request) + + async def test_set_public_did_no_wallet_did(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did} + + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.get_key_for_did = async_mock.CoroutineMock() + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + with async_mock.patch.object( + test_module.web, "json_response", async_mock.Mock() + ) as json_response, async_mock.patch.object( + test_module, "format_did_info", async_mock.Mock() + ) as format_did_info: + self.wallet.get_public_did.return_value = DIDInfo( + self.test_did, self.test_verkey, {} + ) + self.wallet.set_public_did.side_effect = test_module.WalletNotFoundError() + with self.assertRaises(test_module.web.HTTPNotFound): + await test_module.wallet_set_public_did(request) + async def test_set_public_did_update_endpoint(self): request = async_mock.MagicMock() request.app = self.app @@ -272,6 +361,7 @@ async def test_set_public_did_update_endpoint(self): Ledger = async_mock.MagicMock() self.ledger = Ledger() self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.get_key_for_did = async_mock.CoroutineMock() self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) self.context.injector.bind_instance(BaseLedger, self.ledger) @@ -293,133 +383,217 @@ async def test_set_public_did_update_endpoint(self): ) assert result is json_response.return_value - async def test_rotate_did_keypair(self): + async def test_set_did_endpoint(self): request = async_mock.MagicMock() request.app = self.app - request.query = {"did": "did"} + request.json = async_mock.CoroutineMock( + return_value={ + "did": self.test_did, + "endpoint": "https://my-endpoint.ca:8020", + } + ) + + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + self.wallet.get_local_did.return_value = DIDInfo( + self.test_did, + self.test_verkey, + {"public": False, "endpoint": "http://old-endpoint.ca"}, + ) + self.wallet.get_public_did.return_value = DIDInfo( + self.test_did, self.test_verkey, {} + ) with async_mock.patch.object( test_module.web, "json_response", async_mock.Mock() ) as json_response: - self.wallet.get_local_did = async_mock.CoroutineMock( - return_value=DIDInfo("did", "verkey", {"public": False}) - ) - self.wallet.rotate_did_keypair_start = async_mock.CoroutineMock() - self.wallet.rotate_did_keypair_apply = async_mock.CoroutineMock() - - await test_module.wallet_rotate_did_keypair(request) + await test_module.wallet_set_did_endpoint(request) json_response.assert_called_once_with({}) - async def test_rotate_did_keypair_missing_wallet(self): + async def test_set_did_endpoint_public_did_no_ledger(self): request = async_mock.MagicMock() request.app = self.app - request.query = {"did": "did"} - self.context.injector.clear_binding(BaseWallet) + request.json = async_mock.CoroutineMock( + return_value={ + "did": self.test_did, + "endpoint": "https://my-endpoint.ca:8020", + } + ) - with self.assertRaises(HTTPForbidden): - await test_module.wallet_rotate_did_keypair(request) + self.wallet.get_local_did.return_value = DIDInfo( + self.test_did, + self.test_verkey, + {"public": False, "endpoint": "http://old-endpoint.ca"}, + ) + self.wallet.get_public_did.return_value = DIDInfo( + self.test_did, self.test_verkey, {} + ) - async def test_rotate_did_keypair_no_query_did(self): + with self.assertRaises(test_module.web.HTTPForbidden): + await test_module.wallet_set_did_endpoint(request) + + async def test_set_did_endpoint_x(self): request = async_mock.MagicMock() request.app = self.app - request.query = {} + request.json = async_mock.CoroutineMock( + return_value={ + "did": self.test_did, + "endpoint": "https://my-endpoint.ca:8020", + } + ) + + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + self.wallet.get_local_did.side_effect = test_module.WalletError() with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.wallet_rotate_did_keypair(request) + await test_module.wallet_set_did_endpoint(request) - async def test_rotate_did_keypair_did_not_local(self): + async def test_set_did_endpoint_no_wallet_did(self): request = async_mock.MagicMock() request.app = self.app - request.query = {"did": "did"} - - self.wallet.get_local_did = async_mock.CoroutineMock( - side_effect=WalletNotFoundError("Unknown DID") + request.json = async_mock.CoroutineMock( + return_value={ + "did": self.test_did, + "endpoint": "https://my-endpoint.ca:8020", + } ) - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.wallet_rotate_did_keypair(request) - self.wallet.get_local_did = async_mock.CoroutineMock( - return_value=DIDInfo("did", "verkey", {"public": True}) - ) - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.wallet_rotate_did_keypair(request) + Ledger = async_mock.MagicMock() + self.ledger = Ledger() + self.ledger.update_endpoint_for_did = async_mock.CoroutineMock() + self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger) + self.context.injector.bind_instance(BaseLedger, self.ledger) + + self.wallet.get_local_did.side_effect = test_module.WalletNotFoundError() + + with self.assertRaises(test_module.web.HTTPNotFound): + await test_module.wallet_set_did_endpoint(request) - async def test_get_catpol(self): + async def test_get_did_endpoint(self): request = async_mock.MagicMock() request.app = self.app + request.query = {"did": self.test_did} + + self.wallet.get_local_did.return_value = DIDInfo( + self.test_did, + self.test_verkey, + {"public": False, "endpoint": "http://old-endpoint.ca"}, + ) with async_mock.patch.object( test_module.web, "json_response", async_mock.Mock() ) as json_response: - self.wallet.WALLET_TYPE = "indy" - self.wallet.get_credential_definition_tag_policy = async_mock.CoroutineMock( - return_value=["a", "b", "c"] + await test_module.wallet_get_did_endpoint(request) + json_response.assert_called_once_with( + { + "did": self.test_did, + "endpoint": self.wallet.get_local_did.return_value.metadata[ + "endpoint" + ], + } ) - result = await test_module.wallet_get_tagging_policy(request) - json_response.assert_called_once_with({"taggables": ["a", "b", "c"]}) - assert result is json_response.return_value - async def test_get_catpol_not_indy_x(self): + async def test_get_did_endpoint_no_did(self): request = async_mock.MagicMock() request.app = self.app + request.query = {} - self.wallet.WALLET_TYPE = "rich-corinthian-leather" - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.wallet_get_tagging_policy(request) + with self.assertRaises(test_module.web.HTTPBadRequest): + await test_module.wallet_get_did_endpoint(request) - async def test_get_catpol_wallet_err(self): + async def test_get_did_endpoint_no_wallet_did(self): request = async_mock.MagicMock() request.app = self.app + request.query = {"did": self.test_did} + + self.wallet.get_local_did.side_effect = test_module.WalletNotFoundError() + + with self.assertRaises(test_module.web.HTTPNotFound): + await test_module.wallet_get_did_endpoint(request) + + async def test_get_did_endpoint_wallet_x(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": self.test_did} + + self.wallet.get_local_did.side_effect = test_module.WalletError() - self.wallet.WALLET_TYPE = "indy" - self.wallet.get_credential_definition_tag_policy = async_mock.CoroutineMock( - side_effect=test_module.WalletError() - ) with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.wallet_get_tagging_policy(request) + await test_module.wallet_get_did_endpoint(request) - async def test_set_catpol(self): + async def test_rotate_did_keypair(self): request = async_mock.MagicMock() request.app = self.app - request.json = async_mock.CoroutineMock( - return_value={"taggables": ["a", "b", "c"]} - ) + request.query = {"did": "did"} with async_mock.patch.object( test_module.web, "json_response", async_mock.Mock() ) as json_response: - self.wallet.WALLET_TYPE = "indy" - self.wallet.set_credential_definition_tag_policy = async_mock.CoroutineMock( - return_value=["a", "b", "c"] + self.wallet.get_local_did = async_mock.CoroutineMock( + return_value=DIDInfo("did", "verkey", {"public": False}) ) - result = await test_module.wallet_set_tagging_policy(request) + self.wallet.rotate_did_keypair_start = async_mock.CoroutineMock() + self.wallet.rotate_did_keypair_apply = async_mock.CoroutineMock() + + await test_module.wallet_rotate_did_keypair(request) json_response.assert_called_once_with({}) - assert result is json_response.return_value - async def test_set_catpol_not_indy_x(self): + async def test_rotate_did_keypair_missing_wallet(self): request = async_mock.MagicMock() request.app = self.app - request.json = async_mock.CoroutineMock( - return_value={"taggables": ["a", "b", "c"]} - ) + request.query = {"did": "did"} + self.context.injector.clear_binding(BaseWallet) - self.wallet.WALLET_TYPE = "rich-corinthian-leather" - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.wallet_set_tagging_policy(request) + with self.assertRaises(HTTPForbidden): + await test_module.wallet_rotate_did_keypair(request) - async def test_set_catpol_wallet_err(self): + async def test_rotate_did_keypair_no_query_did(self): request = async_mock.MagicMock() request.app = self.app - request.json = async_mock.CoroutineMock( - return_value={"taggables": ["a", "b", "c"]} + request.query = {} + + with self.assertRaises(test_module.web.HTTPBadRequest): + await test_module.wallet_rotate_did_keypair(request) + + async def test_rotate_did_keypair_did_not_local(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": "did"} + + self.wallet.get_local_did = async_mock.CoroutineMock( + side_effect=test_module.WalletNotFoundError("Unknown DID") ) + with self.assertRaises(test_module.web.HTTPNotFound): + await test_module.wallet_rotate_did_keypair(request) - self.wallet.WALLET_TYPE = "indy" - self.wallet.set_credential_definition_tag_policy = async_mock.CoroutineMock( + self.wallet.get_local_did = async_mock.CoroutineMock( + return_value=DIDInfo("did", "verkey", {"public": True}) + ) + with self.assertRaises(test_module.web.HTTPBadRequest): + await test_module.wallet_rotate_did_keypair(request) + + async def test_rotate_did_keypair_x(self): + request = async_mock.MagicMock() + request.app = self.app + request.query = {"did": "did"} + + self.wallet.get_local_did = async_mock.CoroutineMock( + return_value=DIDInfo("did", "verkey", {"public": False}) + ) + self.wallet.rotate_did_keypair_start = async_mock.CoroutineMock( side_effect=test_module.WalletError() ) with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.wallet_set_tagging_policy(request) + await test_module.wallet_rotate_did_keypair(request) async def test_register(self): mock_app = async_mock.MagicMock()