Skip to content

Commit

Permalink
Merge pull request #2295 from mkempa/Allow_any_DID_to_be_public
Browse files Browse the repository at this point in the history
Allow any did to be public
  • Loading branch information
dbluhm committed Jul 18, 2023
2 parents ed7e856 + 8655d3c commit d1341f5
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 62 deletions.
6 changes: 6 additions & 0 deletions aries_cloudagent/ledger/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from typing import List, Sequence, Tuple, Union

from ..indy.issuer import DEFAULT_CRED_DEF_TAG, IndyIssuer, IndyIssuerError
from ..messaging.valid import IndyDID
from ..utils import sentinel
from ..wallet.did_info import DIDInfo

Expand Down Expand Up @@ -295,6 +296,11 @@ async def create_and_send_schema(
if not public_info:
raise BadLedgerRequestError("Cannot publish schema without a public DID")

if not bool(IndyDID.PATTERN.match(public_info.did)):
raise BadLedgerRequestError(
"Cannot publish schema when public DID is not an IndyDID"
)

schema_info = await self.check_existing_schema(
public_info.did, schema_name, schema_version, attribute_names
)
Expand Down
6 changes: 6 additions & 0 deletions aries_cloudagent/ledger/indy_vdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from ..cache.base import BaseCache
from ..core.profile import Profile
from ..messaging.valid import IndyDID
from ..storage.base import BaseStorage, StorageRecord
from ..utils import sentinel
from ..utils.env import storage_path
Expand Down Expand Up @@ -605,6 +606,11 @@ async def get_key_for_did(self, did: str) -> str:
nym = self.did_to_nym(did)
public_info = await self.get_wallet_public_did()
public_did = public_info.did if public_info else None

# current public_did may be non-indy -> create nym request with empty public did
if public_did is not None and not bool(IndyDID.PATTERN.match(public_did)):
public_did = None

try:
nym_req = ledger.build_get_nym_request(public_did, nym)
except VdrError as err:
Expand Down
56 changes: 54 additions & 2 deletions aries_cloudagent/ledger/tests/test_indy_vdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
from ...indy.issuer import IndyIssuer
from ...wallet.base import BaseWallet
from ...wallet.key_type import KeyType, ED25519
from ...wallet.did_method import SOV, DIDMethods
from ...wallet.did_method import SOV, DIDMethods, DIDMethod, HolderDefinedDid
from ...wallet.did_info import DIDInfo
from ...wallet.did_posture import DIDPosture

from ..endpoint_type import EndpointType
from ..indy_vdr import (
Expand All @@ -25,10 +26,19 @@
VdrError,
)

WEB = DIDMethod(
name="web",
key_types=[ED25519],
rotation=True,
holder_defined_did=HolderDefinedDid.REQUIRED,
)


@pytest.fixture()
def ledger():
profile = InMemoryProfile.test_profile(bind={DIDMethods: DIDMethods()})
did_methods = DIDMethods()
did_methods.register(WEB)
profile = InMemoryProfile.test_profile(bind={DIDMethods: did_methods})
ledger = IndyVdrLedger(IndyVdrLedgerPool("test-ledger"), profile)

async def open():
Expand Down Expand Up @@ -341,6 +351,28 @@ async def test_send_schema_ledger_transaction_error(
issuer, "schema_name", "9.1", ["a", "b"]
)

@pytest.mark.asyncio
async def test_send_schema_no_indy_did(
self,
ledger: IndyVdrLedger,
):
wallet = async_mock.MagicMock((await ledger.profile.session()).wallet)
wallet.create_public_did.return_value = {
"result": {
"did": "did:web:doma.in",
"verkey": "verkey",
"posture": DIDPosture.PUBLIC.moniker,
"key_type": ED25519.key_type,
"method": WEB.method_name,
}
}
issuer = async_mock.MagicMock(IndyIssuer)
async with ledger:
with pytest.raises(BadLedgerRequestError):
schema_id, schema_def = await ledger.create_and_send_schema(
issuer, "schema_name", "9.1", ["a", "b"]
)

@pytest.mark.asyncio
async def test_get_schema(
self,
Expand Down Expand Up @@ -526,6 +558,26 @@ async def test_get_key_for_did(
result = await ledger.get_key_for_did("55GkHamhTU1ZbTbV2ab9DE")
assert result == "VK"

@pytest.mark.asyncio
async def test_get_key_for_did_non_sov_public_did(
self,
ledger: IndyVdrLedger,
):
async with ledger:
wallet = async_mock.MagicMock((await ledger.profile.session()).wallet)
wallet.get_public_did.return_value = DIDInfo(
"did:web:doma.in",
"verkey",
DIDPosture.PUBLIC.metadata,
WEB,
ED25519,
)
ledger.pool_handle.submit_request.return_value = {
"data": r'{"verkey": "VK"}',
}
result = await ledger.get_key_for_did("55GkHamhTU1ZbTbV2ab9DE")
assert result == "VK"

@pytest.mark.asyncio
async def test_get_all_endpoints_for_did(
self,
Expand Down
7 changes: 6 additions & 1 deletion aries_cloudagent/protocols/connections/v1_0/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ....core.error import BaseError
from ....core.profile import Profile
from ....messaging.responder import BaseResponder
from ....messaging.valid import IndyDID
from ....multitenant.base import BaseMultitenantManager
from ....storage.error import StorageError, StorageNotFoundError
from ....transport.inbound.receipt import MessageReceipt
Expand Down Expand Up @@ -176,8 +177,12 @@ async def create_invitation(
)

# FIXME - allow ledger instance to format public DID with prefix?
public_did_did = public_did.did
if bool(IndyDID.PATTERN.match(public_did_did)):
public_did_did = f"did:sov:{public_did.did}"

invitation = ConnectionInvitation(
label=my_label, did=f"did:sov:{public_did.did}", image_url=image_url
label=my_label, did=public_did_did, image_url=image_url
)

connection = ConnRecord( # create connection record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from marshmallow import EXCLUDE, fields, validates_schema, ValidationError

from .....messaging.agent_message import AgentMessage, AgentMessageSchema
from .....messaging.valid import INDY_DID, INDY_RAW_PUBLIC_KEY
from .....messaging.valid import GENERIC_DID, INDY_RAW_PUBLIC_KEY
from .....wallet.util import b64_to_bytes, bytes_to_b64

from ..message_types import CONNECTION_INVITATION, PROTOCOL_PACKAGE
Expand Down Expand Up @@ -106,7 +106,7 @@ class Meta:
example="Bob",
)
did = fields.Str(
required=False, description="DID for connection invitation", **INDY_DID
required=False, description="DID for connection invitation", **GENERIC_DID
)
recipient_keys = fields.List(
fields.Str(description="Recipient public key", **INDY_RAW_PUBLIC_KEY),
Expand Down
12 changes: 10 additions & 2 deletions aries_cloudagent/protocols/out_of_band/v1_0/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ....core.profile import Profile
from ....did.did_key import DIDKey
from ....messaging.responder import BaseResponder
from ....messaging.valid import IndyDID
from ....storage.error import StorageNotFoundError
from ....transport.inbound.receipt import MessageReceipt
from ....wallet.base import BaseWallet
Expand Down Expand Up @@ -223,12 +224,16 @@ async def create_invitation(
"Cannot create public invitation with no public DID"
)

public_did_did = public_did.did
if bool(IndyDID.PATTERN.match(public_did.did)):
public_did_did = f"did:sov:{public_did.did}"

invi_msg = InvitationMessage( # create invitation message
_id=invitation_message_id,
label=my_label or self.profile.settings.get("default_label"),
handshake_protocols=handshake_protocols,
requests_attach=message_attachments,
services=[f"did:sov:{public_did.did}"],
services=[public_did_did],
accept=service_accept if protocol_version != "1.0" else None,
version=protocol_version or DEFAULT_VERSION,
image_url=image_url,
Expand Down Expand Up @@ -446,7 +451,10 @@ async def receive_invitation(
# Get the DID public did, if any
public_did = None
if isinstance(oob_service_item, str):
public_did = oob_service_item.split(":")[-1]
if bool(IndyDID.PATTERN.match(oob_service_item)):
public_did = oob_service_item.split(":")[-1]
else:
public_did = oob_service_item

conn_rec = None

Expand Down
92 changes: 50 additions & 42 deletions aries_cloudagent/wallet/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
GENERIC_DID,
INDY_DID,
INDY_RAW_PUBLIC_KEY,
IndyDID,
JWT,
Uri,
)
Expand Down Expand Up @@ -604,53 +605,60 @@ async def promote_wallet_public_did(
"""Promote supplied DID to the wallet public DID."""
info: DIDInfo = None
endorser_did = None

is_indy_did = bool(IndyDID.PATTERN.match(did))
# write only Indy DID
write_ledger = is_indy_did and write_ledger

ledger = profile.inject_or(BaseLedger)
if not ledger:
reason = "No ledger available"
if not context.settings.get_value("wallet.type"):
reason += ": missing wallet-type?"
raise PermissionError(reason)

async with ledger:
if not await ledger.get_key_for_did(did):
raise LookupError(f"DID {did} is not posted to the ledger")
if is_indy_did:
if not ledger:
reason = "No ledger available"
if not context.settings.get_value("wallet.type"):
reason += ": missing wallet-type?"
raise PermissionError(reason)

# check if we need to endorse
if is_author_role(profile):
# authors cannot write to the ledger
write_ledger = False
async with ledger:
if not await ledger.get_key_for_did(did):
raise LookupError(f"DID {did} is not posted to the ledger")

# check if we need to endorse
if is_author_role(profile):
# authors cannot write to the ledger
write_ledger = False

# author has not provided a connection id, so determine which to use
if not connection_id:
connection_id = await get_endorser_connection_id(profile)
if not connection_id:
raise web.HTTPBadRequest(reason="No endorser connection found")
if not write_ledger:
try:
async with profile.session() as session:
connection_record = await ConnRecord.retrieve_by_id(
session, connection_id
)
except StorageNotFoundError as err:
raise web.HTTPNotFound(reason=err.roll_up) from err
except BaseModelError as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err

# author has not provided a connection id, so determine which to use
if not connection_id:
connection_id = await get_endorser_connection_id(profile)
if not connection_id:
raise web.HTTPBadRequest(reason="No endorser connection found")
if not write_ledger:
try:
async with profile.session() as session:
connection_record = await ConnRecord.retrieve_by_id(
session, connection_id
endorser_info = await connection_record.metadata_get(
session, "endorser_info"
)
except StorageNotFoundError as err:
raise web.HTTPNotFound(reason=err.roll_up) from err
except BaseModelError as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err

async with profile.session() as session:
endorser_info = await connection_record.metadata_get(
session, "endorser_info"
)
if not endorser_info:
raise web.HTTPForbidden(
reason="Endorser Info is not set up in "
"connection metadata for this connection record"
)
if "endorser_did" not in endorser_info.keys():
raise web.HTTPForbidden(
reason=' "endorser_did" is not set in "endorser_info"'
" in connection metadata for this connection record"
)
endorser_did = endorser_info["endorser_did"]
if not endorser_info:
raise web.HTTPForbidden(
reason="Endorser Info is not set up in "
"connection metadata for this connection record"
)
if "endorser_did" not in endorser_info.keys():
raise web.HTTPForbidden(
reason=' "endorser_did" is not set in "endorser_info"'
" in connection metadata for this connection record"
)
endorser_did = endorser_info["endorser_did"]

did_info: DIDInfo = None
attrib_def = None
Expand All @@ -663,7 +671,7 @@ async def promote_wallet_public_did(
# Publish endpoint if necessary
endpoint = did_info.metadata.get("endpoint")

if not endpoint:
if is_indy_did and not endpoint:
async with session_fn() as session:
wallet = session.inject_or(BaseWallet)
endpoint = mediator_endpoint or context.settings.get("default_endpoint")
Expand Down
Loading

0 comments on commit d1341f5

Please sign in to comment.