diff --git a/aries_cloudagent/wallet/askar.py b/aries_cloudagent/wallet/askar.py index 425db90d4d..fd8185b3fa 100644 --- a/aries_cloudagent/wallet/askar.py +++ b/aries_cloudagent/wallet/askar.py @@ -79,7 +79,7 @@ async def create_signing_key( Raises: WalletDuplicateError: If the resulting verkey already exists in the wallet - WalletError: If there is an aries_askar error + WalletError: If there is another backend error """ @@ -112,7 +112,7 @@ async def get_signing_key(self, verkey: str) -> KeyInfo: Raises: WalletNotFoundError: If no keypair is associated with the verification key - WalletError: If there is a aries_askar error + WalletError: If there is another backend error """ @@ -173,7 +173,7 @@ async def create_local_did( Raises: WalletDuplicateError: If the DID already exists in the wallet - WalletError: If there is a aries_askar error + WalletError: If there is another backend error """ @@ -250,8 +250,6 @@ async def create_local_did( did=did, verkey=verkey, metadata=metadata, method=method, key_type=key_type ) - # FIXME implement get_public_did more efficiently (store lookup record) - async def get_local_dids(self) -> Sequence[DIDInfo]: """ Get list of defined local DIDs. @@ -278,7 +276,7 @@ async def get_local_did(self, did: str) -> DIDInfo: Raises: WalletNotFoundError: If the DID is not found - WalletError: If there is an aries_askar error + WalletError: If there is another backend error """ @@ -350,9 +348,12 @@ async def get_public_did(self) -> DIDInfo: """ public_did = None public_info = None + public_item = None storage = AskarStorage(self._session) try: - public = await storage.get_record(CATEGORY_CONFIG, RECORD_NAME_PUBLIC_DID) + public_item = await storage.get_record( + CATEGORY_CONFIG, RECORD_NAME_PUBLIC_DID + ) except StorageNotFoundError: # populate public DID record # this should only happen once, for an upgraded wallet @@ -375,9 +376,11 @@ async def get_public_did(self) -> DIDInfo: ) except StorageDuplicateError: # another process stored the record first - pass - else: - public_did = json.loads(public.value)["did"] + public_item = await storage.get_record( + CATEGORY_CONFIG, RECORD_NAME_PUBLIC_DID + ) + if public_item: + public_did = json.loads(public_item.value)["did"] if public_did: try: public_info = await self.get_local_did(public_did) @@ -396,10 +399,18 @@ async def set_public_did(self, did: Union[str, DIDInfo]) -> DIDInfo: """ if isinstance(did, str): - # will raise an exception if not found - info = await self.get_local_did(did) + try: + item = await self._session.handle.fetch( + CATEGORY_DID, did, for_update=True + ) + except AskarError as err: + raise WalletError("Error when fetching local DID") from err + if not item: + raise WalletNotFoundError("Unknown DID: {}".format(did)) + info = _load_did_entry(item) else: info = did + item = None if info.method != DIDMethod.SOV: raise WalletError("Setting public DID is only allowed for did:sov DIDs") @@ -407,6 +418,19 @@ async def set_public_did(self, did: Union[str, DIDInfo]) -> DIDInfo: public = await self.get_public_did() if not public or public.did != info.did: storage = AskarStorage(self._session) + if not info.metadata.get("posted"): + metadata = {**info.metadata, "posted": True} + if item: + entry_val = item.value_json + entry_val["metadata"] = metadata + await self._session.handle.replace( + CATEGORY_DID, did, value_json=entry_val, tags=item.tags + ) + else: + await self.replace_local_did_metadata(info.did, metadata) + info = info._replace( + metadata=metadata, + ) await storage.update_record( StorageRecord( type=CATEGORY_CONFIG, @@ -558,7 +582,7 @@ async def sign_message( Raises: WalletError: If the message is not provided WalletError: If the verkey is not provided - WalletError: If an aries_askar error occurs + WalletError: If another backend error occurs """ if not message: @@ -606,7 +630,7 @@ async def verify_message( WalletError: If the verkey is not provided WalletError: If the signature is not provided WalletError: If the message is not provided - WalletError: If an aries_askar error occurs + WalletError: If another backend error occurs """ if not from_verkey: @@ -649,7 +673,7 @@ async def pack_message( Raises: WalletError: If no message is provided - WalletError: If an aries_askar error occurs + WalletError: If another backend error occurs """ if message is None: @@ -680,7 +704,7 @@ async def unpack_message(self, enc_message: bytes) -> Tuple[str, str, str]: Raises: WalletError: If the message is not provided - WalletError: If an aries_askar error occurs + WalletError: If another backend error occurs """ if not enc_message: diff --git a/aries_cloudagent/wallet/indy.py b/aries_cloudagent/wallet/indy.py index 8300ec62ca..a5d40732f6 100644 --- a/aries_cloudagent/wallet/indy.py +++ b/aries_cloudagent/wallet/indy.py @@ -620,9 +620,10 @@ async def get_public_did(self) -> DIDInfo: public_did = None public_info = None + public_item = None storage = IndySdkStorage(self.opened) try: - public = await storage.get_record( + public_item = await storage.get_record( RECORD_TYPE_CONFIG, RECORD_NAME_PUBLIC_DID ) except StorageNotFoundError: @@ -647,9 +648,11 @@ async def get_public_did(self) -> DIDInfo: ) except StorageDuplicateError: # another process stored the record first - pass - else: - public_did = json.loads(public.value)["did"] + public_item = await storage.get_record( + RECORD_TYPE_CONFIG, RECORD_NAME_PUBLIC_DID + ) + if public_item: + public_did = json.loads(public_item.value)["did"] if public_did: try: public_info = await self.get_local_did(public_did) @@ -678,6 +681,10 @@ async def set_public_did(self, did: Union[str, DIDInfo]) -> DIDInfo: public = await self.get_public_did() if not public or public.did != info.did: + if not info.metadata.get("posted"): + metadata = {**info.metadata, "posted": True} + await self.replace_local_did_metadata(info.did, metadata) + info = info._replace(metadata=metadata) storage = IndySdkStorage(self.opened) await storage.update_record( StorageRecord( diff --git a/aries_cloudagent/wallet/tests/test_in_memory_wallet.py b/aries_cloudagent/wallet/tests/test_in_memory_wallet.py index 234bc9374c..6554336908 100644 --- a/aries_cloudagent/wallet/tests/test_in_memory_wallet.py +++ b/aries_cloudagent/wallet/tests/test_in_memory_wallet.py @@ -403,6 +403,7 @@ async def test_set_public_did(self, wallet: InMemoryWallet): self.test_sov_did, self.test_metadata, ) + assert not info.metadata.get("posted") with pytest.raises(WalletNotFoundError): await wallet.set_public_did("55GkHamhTU1ZbTbV2ab9DF") @@ -410,17 +411,20 @@ async def test_set_public_did(self, wallet: InMemoryWallet): # test assign info_same = await wallet.set_public_did(info.did) assert info_same.did == info.did + assert info_same.metadata.get("posted") info_new = await wallet.create_local_did(DIDMethod.SOV, KeyType.ED25519) assert info_new.did != info_same.did loc = await wallet.get_local_did(self.test_sov_did) - pub = await wallet.set_public_did(loc.did) + pub = await wallet.set_public_did(loc) assert pub.did == loc.did + assert pub.metadata.get("posted") # test replace info_final = await wallet.set_public_did(info_new.did) assert info_final.did == info_new.did + assert info_final.metadata.get("posted") @pytest.mark.asyncio async def test_set_public_did_x_not_sov(self, wallet: InMemoryWallet):