Skip to content

Commit

Permalink
Merge pull request #564 from sklump/no-hopeless-offers
Browse files Browse the repository at this point in the history
No hopeless offers
  • Loading branch information
andrewwhitehead authored Jun 20, 2020
2 parents de8d75d + e71479c commit 8b6aea0
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 25 deletions.
14 changes: 13 additions & 1 deletion aries_cloudagent/protocols/issue_credential/v1_0/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ async def receive_proposal(self) -> V10CredentialExchange:
The resulting credential exchange record, created
"""
# go to cred def via ledger to get authoritative schema id
credential_proposal_message = self.context.message
connection_id = self.context.connection_record.connection_id

Expand Down Expand Up @@ -242,6 +241,19 @@ async def _create(cred_def_id):
)
cred_preview = credential_proposal_message.credential_proposal

# vet attributes
ledger: BaseLedger = await self.context.inject(BaseLedger)
async with ledger:
schema_id = await ledger.credential_definition_id2schema_id()
schema = await ledger.get_schema(schema_id)
schema_attrs = {attr for attr in schema["attrNames"]}
preview_attrs = {attr for attr in cred_preview.attr_dict()}
if preview_attrs != schema_attrs:
raise CredentialManagerError(
f"Preview attributes {preview_attrs} "
f"mismatch corresponding schema attributes {schema_attrs}"
)

credential_offer = None
cache_key = f"credential_offer::{cred_def_id}"
cache: BaseCache = await self.context.inject(BaseCache, required=False)
Expand Down
14 changes: 10 additions & 4 deletions aries_cloudagent/protocols/issue_credential/v1_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from ....connections.models.connection_record import ConnectionRecord
from ....issuer.indy import IssuerRevocationRegistryFullError
from ....ledger.error import LedgerError
from ....messaging.credential_definitions.util import CRED_DEF_TAGS
from ....messaging.models.base import BaseModelError
from ....messaging.valid import (
Expand All @@ -35,7 +36,7 @@

from ...problem_report.v1_0.message import ProblemReport

from .manager import CredentialManager
from .manager import CredentialManager, CredentialManagerError
from .message_types import SPEC_URI
from .messages.credential_proposal import CredentialProposal
from .messages.credential_offer import CredentialOfferSchema
Expand Down Expand Up @@ -600,7 +601,7 @@ async def credential_exchange_create_free_offer(request: web.BaseRequest):
context, credential_offer_message, conn_did, endpoint
)
result = credential_exchange_record.serialize()
except BaseModelError as err:
except (BaseModelError, CredentialManagerError, LedgerError) as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err

response = {"record": result, "oob_url": oob_url}
Expand Down Expand Up @@ -672,7 +673,12 @@ async def credential_exchange_send_free_offer(request: web.BaseRequest):
trace_msg,
)
result = credential_exchange_record.serialize()
except (StorageNotFoundError, BaseModelError) as err:
except (
StorageNotFoundError,
BaseModelError,
CredentialManagerError,
LedgerError,
) as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err

await outbound_handler(credential_offer_message, connection_id=connection_id)
Expand Down Expand Up @@ -749,7 +755,7 @@ async def credential_exchange_send_bound_offer(request: web.BaseRequest):
)

result = credential_exchange_record.serialize()
except (StorageError, BaseModelError) as err:
except (StorageError, BaseModelError, CredentialManagerError, LedgerError) as err:
raise web.HTTPBadRequest(reason=err.roll_up) from err

await outbound_handler(credential_offer_message, connection_id=connection_id)
Expand Down
129 changes: 109 additions & 20 deletions aries_cloudagent/protocols/issue_credential/v1_0/tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@
"primary": {
"n": "...",
"s": "...",
"r": {"master_secret": "...", "number": "...", "remainder": "..."},
"r": {
"master_secret": "...",
"legalName": "...",
"jurisdictionId": "...",
"incorporationDate": "...",
},
"rctxt": "...",
"z": "...",
},
Expand Down Expand Up @@ -108,6 +113,9 @@ async def setUp(self):
return_value=REV_REG_DEF
)
self.ledger.__aenter__ = async_mock.CoroutineMock(return_value=self.ledger)
self.ledger.credential_definition_id2schema_id = async_mock.CoroutineMock(
return_value=SCHEMA_ID
)
self.context.injector.bind_instance(BaseLedger, self.ledger)

self.manager = CredentialManager(self.context)
Expand Down Expand Up @@ -152,7 +160,11 @@ async def test_record_eq(self):
async def test_prepare_send(self):
connection_id = "test_conn_id"
preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)
proposal = CredentialProposal(
credential_proposal=preview, cred_def_id=CRED_DEF_ID, schema_id=SCHEMA_ID
Expand All @@ -178,7 +190,11 @@ async def test_create_proposal(self):
connection_id = "test_conn_id"
comment = "comment"
preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)

self.ledger.credential_definition_id2schema_id = async_mock.CoroutineMock(
Expand Down Expand Up @@ -250,15 +266,15 @@ async def test_receive_proposal(self):
comment = "comment"

preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)
self.context.connection_record = async_mock.MagicMock()
self.context.connection_record.connection_id = connection_id

self.ledger.credential_definition_id2schema_id = async_mock.CoroutineMock(
return_value=SCHEMA_ID
)

with async_mock.patch.object(
V10CredentialExchange, "save", autospec=True
) as save_ex:
Expand Down Expand Up @@ -294,7 +310,11 @@ async def test_create_free_offer(self):
schema_id_parts = SCHEMA_ID.split(":")

preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)
proposal = CredentialProposal(
credential_proposal=preview, cred_def_id=CRED_DEF_ID, schema_id=None
Expand All @@ -309,9 +329,7 @@ async def test_create_free_offer(self):
with async_mock.patch.object(
V10CredentialExchange, "save", autospec=True
) as save_ex:
self.ledger.get_credential_definition = async_mock.CoroutineMock(
return_value={"value": {}}
)

self.cache = BasicCache()
self.context.injector.bind_instance(BaseCache, self.cache)

Expand Down Expand Up @@ -361,15 +379,77 @@ async def test_create_free_offer(self):
credential_exchange_record=exchange, comment=comment
) # once more to cover case where offer is available in cache

async def test_create_free_offer_attr_mismatch(self):
connection_id = "test_conn_id"
comment = "comment"
schema_id_parts = SCHEMA_ID.split(":")

preview = CredentialPreview(
attributes=(
CredAttrSpec(name="legal name", value="value"),
CredAttrSpec(name="jurisdiction id", value="value"),
CredAttrSpec(name="incorporation date", value="value"),
)
)
proposal = CredentialProposal(
credential_proposal=preview, cred_def_id=CRED_DEF_ID, schema_id=None
)

exchange = V10CredentialExchange(
credential_definition_id=CRED_DEF_ID,
role=V10CredentialExchange.ROLE_ISSUER,
credential_proposal_dict=proposal.serialize(),
)

with async_mock.patch.object(
V10CredentialExchange, "save", autospec=True
) as save_ex:
self.cache = BasicCache()
self.context.injector.bind_instance(BaseCache, self.cache)

cred_offer = {"cred_def_id": CRED_DEF_ID, "schema_id": SCHEMA_ID}

issuer = async_mock.MagicMock(BaseIssuer, autospec=True)
issuer.create_credential_offer = async_mock.CoroutineMock(
return_value=json.dumps(cred_offer)
)
self.context.injector.bind_instance(BaseIssuer, issuer)

self.storage = BasicStorage()
self.context.injector.bind_instance(BaseStorage, self.storage)
cred_def_record = StorageRecord(
CRED_DEF_SENT_RECORD_TYPE,
CRED_DEF_ID,
{
"schema_id": SCHEMA_ID,
"schema_issuer_did": schema_id_parts[0],
"schema_name": schema_id_parts[-2],
"schema_version": schema_id_parts[-1],
"issuer_did": TEST_DID,
"cred_def_id": CRED_DEF_ID,
"epoch": str(int(time())),
},
)
storage: BaseStorage = await self.context.inject(BaseStorage)
await storage.add_record(cred_def_record)

with self.assertRaises(CredentialManagerError):
await self.manager.create_offer(
credential_exchange_record=exchange, comment=comment
)

async def test_create_bound_offer(self):
TEST_DID = "LjgpST2rjsoxYegQDRm7EL"
schema_id_parts = SCHEMA_ID.split(":")
cred_def_id = f"{TEST_DID}:3:CL:18:tag"
connection_id = "test_conn_id"
comment = "comment"

preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)
proposal = CredentialProposal(credential_proposal=preview)
exchange = V10CredentialExchange(
Expand All @@ -384,9 +464,6 @@ async def test_create_bound_offer(self):
) as get_cached_key, async_mock.patch.object(
V10CredentialExchange, "set_cached_key", autospec=True
) as set_cached_key:
self.ledger.get_credential_definition = async_mock.CoroutineMock(
return_value={"value": {}}
)
get_cached_key.return_value = None
cred_offer = {"cred_def_id": CRED_DEF_ID, "schema_id": SCHEMA_ID}
issuer = async_mock.MagicMock(BaseIssuer, autospec=True)
Expand Down Expand Up @@ -438,7 +515,11 @@ async def test_create_bound_offer_no_cred_def(self):
comment = "comment"

preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)
proposal = CredentialProposal(credential_proposal=preview)
exchange = V10CredentialExchange(
Expand Down Expand Up @@ -475,7 +556,11 @@ async def test_receive_offer_proposed(self):
thread_id = "thread-id"

preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)
proposal = CredentialProposal(credential_proposal=preview)

Expand Down Expand Up @@ -523,7 +608,11 @@ async def test_receive_free_offer(self):
connection_id = "test_conn_id"
indy_offer = {"schema_id": SCHEMA_ID, "cred_def_id": CRED_DEF_ID}
preview = CredentialPreview(
attributes=(CredAttrSpec(name="attr", value="value"),)
attributes=(
CredAttrSpec(name="legalName", value="value"),
CredAttrSpec(name="jurisdictionId", value="value"),
CredAttrSpec(name="incorporationDate", value="value"),
)
)

offer = CredentialOffer(
Expand Down

0 comments on commit 8b6aea0

Please sign in to comment.