Skip to content

Commit

Permalink
Merge pull request #215 from andrewwhitehead/fix-unsigned-req
Browse files Browse the repository at this point in the history
Fix ledger request signing issue; avoid duplicate public DID lookups
  • Loading branch information
swcurran authored Oct 18, 2019
2 parents 0ea871c + c878cb2 commit a094dd7
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 43 deletions.
82 changes: 51 additions & 31 deletions aries_cloudagent/ledger/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,21 @@ async def __aexit__(self, exc_type, exc, tb):
"""Context manager exit."""
await self._context_close()

async def _submit(self, request_json: str, sign=True, taa_accept=False) -> str:
async def _submit(
self,
request_json: str,
sign: bool = None,
taa_accept: bool = False,
public_did: str = "",
) -> str:
"""
Sign and submit request to ledger.
Args:
request_json: The json string to submit
sign: whether or not to sign the request
taa_accept: whether to apply TAA acceptance to the (signed, write) request
public_did: override the public DID used to sign the request
"""

Expand All @@ -229,8 +236,14 @@ async def _submit(self, request_json: str, sign=True, taa_accept=False) -> str:
)
)

if (sign is None and public_did == "") or (sign and not public_did):
did_info = await self.wallet.get_public_did()
if did_info:
public_did = did_info.did
if public_did and sign is None:
sign = True

if sign:
public_did = await self.wallet.get_public_did()
if not public_did:
raise BadLedgerRequestError("Cannot sign request without a public DID")
if taa_accept:
Expand All @@ -247,7 +260,7 @@ async def _submit(self, request_json: str, sign=True, taa_accept=False) -> str:
)
)
submit_op = indy.ledger.sign_and_submit_request(
self.pool_handle, self.wallet.handle, public_did.did, request_json
self.pool_handle, self.wallet.handle, public_did, request_json
)
else:
submit_op = indy.ledger.submit_request(self.pool_handle, request_json)
Expand Down Expand Up @@ -311,7 +324,7 @@ async def send_schema(
)

try:
await self._submit(request_json, True, True)
await self._submit(request_json, public_did=public_info.did)
except LedgerTransactionError as e:
# Identify possible duplicate schema errors on indy-node < 1.9 and > 1.9
if (
Expand Down Expand Up @@ -384,14 +397,16 @@ async def fetch_schema_by_id(self, schema_id: str):
Indy schema dict
"""
public_did = await self.wallet.get_public_did()

public_info = await self.wallet.get_public_did()
public_did = public_info.did if public_info else None

with IndyErrorHandler("Exception when building schema request"):
request_json = await indy.ledger.build_get_schema_request(
public_did.did if public_did else None, schema_id
public_did, schema_id
)

response_json = await self._submit(request_json, sign=bool(public_did))
response_json = await self._submit(request_json, public_did=public_did)
response = json.loads(response_json)
if not response["result"]["seqNo"]:
# schema not found
Expand Down Expand Up @@ -444,7 +459,7 @@ async def fetch_schema_by_seq_no(self, seq_no: int):
f"Could not get schema from ledger for seq no {seq_no}"
)

async def send_credential_definition(self, schema_id: str, tag: str = "default"):
async def send_credential_definition(self, schema_id: str, tag: str = None):
"""
Send credential definition to ledger and store relevant key matter in wallet.
Expand All @@ -454,8 +469,8 @@ async def send_credential_definition(self, schema_id: str, tag: str = "default")
"""

public_did = await self.wallet.get_public_did()
if not public_did:
public_info = await self.wallet.get_public_did()
if not public_info:
raise BadLedgerRequestError(
"Cannot publish credential definition without a public DID"
)
Expand All @@ -469,9 +484,9 @@ async def send_credential_definition(self, schema_id: str, tag: str = "default")
credential_definition_json,
) = await indy.anoncreds.issuer_create_and_store_credential_def(
self.wallet.handle,
public_did.did,
public_info.did,
json.dumps(schema),
tag,
tag or "default",
"CL",
json.dumps({"support_revocation": False}),
)
Expand Down Expand Up @@ -508,9 +523,9 @@ async def send_credential_definition(self, schema_id: str, tag: str = "default")
if not exist_def:
with IndyErrorHandler("Exception when building cred def request"):
request_json = await indy.ledger.build_cred_def_request(
public_did.did, credential_definition_json
public_info.did, credential_definition_json
)
await self._submit(request_json, True, True)
await self._submit(request_json, True, public_did=public_info.did)
else:
self.logger.warning(
"Ledger definition of cred def %s already exists",
Expand Down Expand Up @@ -545,14 +560,15 @@ async def fetch_credential_definition(self, credential_definition_id: str):
"""

public_did = await self.wallet.get_public_did()
public_info = await self.wallet.get_public_did()
public_did = public_info.did if public_info else None

with IndyErrorHandler("Exception when building cred def request"):
request_json = await indy.ledger.build_get_cred_def_request(
public_did.did if public_did else None, credential_definition_id
public_did, credential_definition_id
)

response_json = await self._submit(request_json, sign=bool(public_did))
response_json = await self._submit(request_json, public_did=public_did)

with IndyErrorHandler("Exception when parsing cred def response"):
try:
Expand Down Expand Up @@ -599,12 +615,13 @@ async def get_key_for_did(self, did: str) -> str:
did: The DID to look up on the ledger or in the cache
"""
nym = self.did_to_nym(did)
public_did = await self.wallet.get_public_did()
public_info = await self.wallet.get_public_did()
public_did = public_info.did if public_info else None
with IndyErrorHandler("Exception when building nym request"):
request_json = await indy.ledger.build_get_nym_request(
public_did and public_did.did, nym
public_did, nym
)
response_json = await self._submit(request_json, bool(public_did))
response_json = await self._submit(request_json, public_did=public_did)
data_json = (json.loads(response_json))["result"]["data"]
return json.loads(data_json)["verkey"]

Expand All @@ -615,12 +632,13 @@ async def get_endpoint_for_did(self, did: str) -> str:
did: The DID to look up on the ledger or in the cache
"""
nym = self.did_to_nym(did)
public_did = await self.wallet.get_public_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"):
request_json = await indy.ledger.build_get_attrib_request(
public_did and public_did.did, nym, "endpoint", None, None
public_did, nym, "endpoint", None, None
)
response_json = await self._submit(request_json, sign=bool(public_did))
response_json = await self._submit(request_json, public_did=public_did)
endpoint_json = json.loads(response_json)["result"]["data"]
if endpoint_json:
address = json.loads(endpoint_json)["endpoint"].get("endpoint", None)
Expand Down Expand Up @@ -661,11 +679,12 @@ async def register_nym(
alias: Human-friendly alias to assign to the DID.
role: For permissioned ledgers, what role should the new DID have.
"""
public_did = await self.wallet.get_public_did()
public_info = await self.wallet.get_public_did()
public_did = public_info.did if public_info else None
r = await indy.ledger.build_nym_request(
public_did and public_did.did, did, verkey, alias, role
public_did, did, verkey, alias, role
)
await self._submit(r, True, True)
await self._submit(r, True, True, public_did=public_did)

def nym_to_did(self, nym: str) -> str:
"""Format a nym with the ledger's DID prefix."""
Expand All @@ -682,18 +701,19 @@ async def get_txn_author_agreement(self, reload: bool = False):

async def fetch_txn_author_agreement(self):
"""Fetch the current AML and TAA from the ledger."""
did_info = await self.wallet.get_public_did()
public_info = await self.wallet.get_public_did()
public_did = public_info.did if public_info else None

get_aml_req = await indy.ledger.build_get_acceptance_mechanisms_request(
did_info and did_info.did, None, None
public_did, None, None
)
response_json = await self._submit(get_aml_req, sign=bool(did_info))
response_json = await self._submit(get_aml_req, public_did=public_did)
aml_found = (json.loads(response_json))["result"]["data"]

get_taa_req = await indy.ledger.build_get_txn_author_agreement_request(
did_info and did_info.did, None
public_did, None
)
response_json = await self._submit(get_taa_req, sign=bool(did_info))
response_json = await self._submit(get_taa_req, public_did=public_did)
taa_found = (json.loads(response_json))["result"]["data"]
taa_required = taa_found and taa_found["text"]
if taa_found:
Expand Down
28 changes: 17 additions & 11 deletions aries_cloudagent/ledger/tests/test_indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ async def test_send_schema(
mock_did.did, mock_create_schema.return_value[1]
)

mock_submit.assert_called_once_with(mock_build_schema_req.return_value, True, True)
mock_submit.assert_called_once_with(
mock_build_schema_req.return_value, public_did=mock_did.did
)

assert schema_id == mock_create_schema.return_value[0]

Expand Down Expand Up @@ -311,7 +313,7 @@ async def test_get_schema(

mock_parse_get_schema_req.return_value = (None, "{}")

mock_submit.return_value = "{\"result\":{\"seqNo\":1}}"
mock_submit.return_value = '{"result":{"seqNo":1}}'

ledger = IndyLedger("name", mock_wallet)

Expand All @@ -321,7 +323,7 @@ async def test_get_schema(
mock_wallet.get_public_did.assert_called_once_with()
mock_build_get_schema_req.assert_called_once_with(mock_did.did, "schema_id")
mock_submit.assert_called_once_with(
mock_build_get_schema_req.return_value, sign=True
mock_build_get_schema_req.return_value, public_did=mock_did.did
)
mock_parse_get_schema_req.assert_called_once_with(mock_submit.return_value)

Expand All @@ -330,7 +332,9 @@ async def test_get_schema(
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger.get_schema")
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open")
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close")
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger.fetch_credential_definition")
@async_mock.patch(
"aries_cloudagent.ledger.indy.IndyLedger.fetch_credential_definition"
)
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._submit")
@async_mock.patch("indy.anoncreds.issuer_create_and_store_credential_def")
@async_mock.patch("indy.ledger.build_cred_def_request")
Expand Down Expand Up @@ -406,22 +410,23 @@ async def test_get_credential_definition(
response = await ledger.get_credential_definition("cred_def_id")

mock_wallet.get_public_did.assert_called_once_with()
mock_build_get_cred_def_req.assert_called_once_with(mock_did.did, "cred_def_id")
mock_build_get_cred_def_req.assert_called_once_with(
mock_did.did, "cred_def_id"
)
mock_submit.assert_called_once_with(
mock_build_get_cred_def_req.return_value, sign=True
mock_build_get_cred_def_req.return_value, public_did=mock_did.did
)
mock_parse_get_cred_def_req.assert_called_once_with(
mock_submit.return_value
)
mock_parse_get_cred_def_req.assert_called_once_with(mock_submit.return_value)

assert response == json.loads(mock_parse_get_cred_def_req.return_value[1])

@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_open")
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger._context_close")
@async_mock.patch("aries_cloudagent.ledger.indy.IndyLedger.get_schema")
async def test_credential_definition_id2schema_id(
self,
mock_get_schema,
mock_close,
mock_open,
self, mock_get_schema, mock_close, mock_open
):
mock_wallet = async_mock.MagicMock()
mock_wallet.WALLET_TYPE = "indy"
Expand All @@ -436,6 +441,7 @@ async def test_credential_definition_id2schema_id(
s_id_short = await ledger.credential_definition_id2schema_id(
f"{TestIndyLedger.test_did}:3:CL:{SEQ_NO}:tag"
)

mock_get_schema.assert_called_once_with(SEQ_NO)

assert s_id_short == S_ID
Expand Down
3 changes: 2 additions & 1 deletion aries_cloudagent/messaging/present_proof/v1_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,8 @@ async def presentation_exchange_credentials_list(request: web.BaseRequest):
context = request.app["request_context"]

presentation_exchange_id = request.match_info["pres_ex_id"]
presentation_referents = request.match_info.get("referent").split(",")
referents = request.match_info.get("referent")
presentation_referents = referents.split(",") if referents else ()

try:
presentation_exchange_record = await V10PresentationExchange.retrieve_by_id(
Expand Down

0 comments on commit a094dd7

Please sign in to comment.