Skip to content

Commit

Permalink
Merge branch 'feat/w3c-implementation' of https://github.com/Whats-Co…
Browse files Browse the repository at this point in the history
…okin/aries-cloudagent-python into feat/w3c-implementation
  • Loading branch information
supersonicwisd1 committed Feb 19, 2024
2 parents ba5307a + 80df4c1 commit 229177f
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 79 deletions.
101 changes: 51 additions & 50 deletions aries_cloudagent/anoncreds/issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,60 +633,61 @@ async def create_credential(

return credential.to_json()

async def create_credential_vc_di(
self,
credential_offer: dict,
credential_request: dict,
credential_values: dict,
) -> str:
"""Create Credential."""
anoncreds_registry = self.profile.inject(AnonCredsRegistry)
schema_id = credential_offer["schema_id"]
schema_result = await anoncreds_registry.get_schema(self.profile, schema_id)
cred_def_id = credential_offer["cred_def_id"]
schema_attributes = schema_result.schema_value.attr_names

async def create_credential_vc_di(
self,
credential_offer: dict,
credential_request: dict,
credential_values: dict,
) -> str:
"""Create Credential."""
anoncreds_registry = self.profile.inject(AnonCredsRegistry)
schema_id = credential_offer["schema_id"]
schema_result = await anoncreds_registry.get_schema(self.profile, schema_id)
cred_def_id = credential_offer["cred_def_id"]
schema_attributes = schema_result.schema_value.attr_names

try:
async with self.profile.session() as session:
cred_def = await session.handle.fetch(CATEGORY_CRED_DEF, cred_def_id)
cred_def_private = await session.handle.fetch(
CATEGORY_CRED_DEF_PRIVATE, cred_def_id
)
except AskarError as err:
raise AnonCredsIssuerError("Error retrieving credential definition") from err

if not cred_def or not cred_def_private:
raise AnonCredsIssuerError(
"Credential definition not found for credential issuance"
)

raw_values = {}
for attribute in schema_attributes:
# Ensure every attribute present in schema to be set.
# Extraneous attribute names are ignored.
try:
credential_value = credential_values[attribute]
except KeyError:
async with self.profile.session() as session:
cred_def = await session.handle.fetch(CATEGORY_CRED_DEF, cred_def_id)
cred_def_private = await session.handle.fetch(
CATEGORY_CRED_DEF_PRIVATE, cred_def_id
)
except AskarError as err:
raise AnonCredsIssuerError(
"Provided credential values are missing a value "
f"for the schema attribute '{attribute}'"
"Error retrieving credential definition"
) from err

if not cred_def or not cred_def_private:
raise AnonCredsIssuerError(
"Credential definition not found for credential issuance"
)

raw_values[attribute] = str(credential_value)
raw_values = {}
for attribute in schema_attributes:
# Ensure every attribute present in schema to be set.
# Extraneous attribute names are ignored.
try:
credential_value = credential_values[attribute]
except KeyError:
raise AnonCredsIssuerError(
"Provided credential values are missing a value "
f"for the schema attribute '{attribute}'"
)

raw_values[attribute] = str(credential_value)

try:
credential = await asyncio.get_event_loop().run_in_executor(
None,
lambda: Credential.create(
cred_def.raw_value,
cred_def_private.raw_value,
credential_offer,
credential_request,
raw_values,
),
)
except AnoncredsError as err:
raise AnonCredsIssuerError("Error creating credential") from err
try:
credential = await asyncio.get_event_loop().run_in_executor(
None,
lambda: Credential.create(
cred_def.raw_value,
cred_def_private.raw_value,
credential_offer,
credential_request,
raw_values,
),
)
except AnoncredsError as err:
raise AnonCredsIssuerError("Error creating credential") from err

return credential.to_json()
return credential.to_json()
46 changes: 43 additions & 3 deletions aries_cloudagent/indy/models/cred_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ def __init__(
class AnoncredsLinkSecretSchema(BaseModelSchema):
"""Anoncreds Link Secret Schema."""

class Meta:
"""AnoncredsLinkSecret schema metadata."""

model_class = AnoncredsLinkSecret
unknown = EXCLUDE

nonce = fields.Str(
required=True,
validate=NUM_STR_WHOLE_VALIDATE,
Expand Down Expand Up @@ -230,6 +236,12 @@ def __init__(
class DidcommSignedAttachmentSchema(BaseModelSchema):
"""Didcomm Signed Attachment Schema."""

class Meta:
"""Didcomm signed attachment schema metadata."""

model_class = DidcommSignedAttachment
unknown = EXCLUDE

algs_supported = fields.List(fields.Str(), required=True)

did_methods_supported = fields.List(fields.Str(), required=True)
Expand All @@ -244,9 +256,35 @@ class DidcommSignedAttachmentSchema(BaseModelSchema):
)


class BindingMethod(BaseModel):
"""Binding Method Model."""

class Meta:
"""Binding method metadata."""

schema_class = "BindingMethodSchema"

def __init__(
self,
anoncreds_link_secret: Union[dict, AnoncredsLinkSecret] = None,
didcomm_signed_attachment: Union[dict, DidcommSignedAttachment] = None,
**kwargs,
):
"""Initialize values for DidcommSignedAttachment."""
super().__init__(**kwargs)
self.anoncreds_link_secret = anoncreds_link_secret
self.didcomm_signed_attachment = didcomm_signed_attachment


class BindingMethodSchema(BaseModelSchema):
"""VCDI Binding Method Schema."""

class Meta:
"""VCDI binding method schema metadata."""

model_class = BindingMethod
unknown = EXCLUDE

anoncreds_link_secret = fields.Nested(AnoncredsLinkSecretSchema, required=False)
didcomm_signed_attachment = fields.Nested(
DidcommSignedAttachmentSchema, required=True
Expand All @@ -263,7 +301,7 @@ class Meta:

def __init__(
self,
data_model_versions_supported: str = None,
data_model_versions_supported: Sequence[str] = None,
binding_required: str = None,
binding_methods: str = None,
credential: Union[dict, VerifiableCredential] = None,
Expand Down Expand Up @@ -294,7 +332,7 @@ class Meta:
unknown = EXCLUDE

data_model_versions_supported = fields.List(
required=True, validate="", metadata={"description": "", "example": ""}
fields.Str(), required=True, metadata={"description": "", "example": ""}
)

binding_required = fields.Bool(
Expand All @@ -308,5 +346,7 @@ class Meta:
)

credential = fields.Nested(
CredentialSchema(), required=True, metadata={"description": "", "example": ""}
CredentialSchema(),
required=True,
metadata={"description": "", "example": ""},
)
9 changes: 5 additions & 4 deletions aries_cloudagent/indy/models/cred_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from ...messaging.valid import (
INDY_CRED_DEF_ID_EXAMPLE,
INDY_CRED_DEF_ID_VALIDATE,
INDY_DID_EXAMPLE,
INDY_DID_VALIDATE,
UUID4_EXAMPLE,
NUM_STR_WHOLE_EXAMPLE,
NUM_STR_WHOLE_VALIDATE,
Expand Down Expand Up @@ -88,7 +90,6 @@ class Meta:
"""VCDI credential request schema metadata."""

schema_class = "BindingProofSchema"
unknown = EXCLUDE

def __init__(
self,
Expand Down Expand Up @@ -154,7 +155,6 @@ class Meta:
"""Didcomm signed attachment metadata."""

schema_class = "DidcommSignedAttachmentSchema"
unknown = EXCLUDE

def __init__(self, attachment_id: str = None, **kwargs):
"""Initialize DidcommSignedAttachment."""
Expand All @@ -169,8 +169,9 @@ class Meta:
"""Didcomm Signed Attachment schema metadata."""

model_class = DidcommSignedAttachment
unknown = EXCLUDE

attachment_id = fields.str(
attachment_id = fields.Str(
required=True, metadata={"description": "", "example": ""}
)

Expand All @@ -182,7 +183,6 @@ class Meta:
"""Binding proof metadata."""

schema_class = "BindingProofSchema"
unknown = EXCLUDE

def __init__(
self,
Expand All @@ -203,6 +203,7 @@ class Meta:
"""Binding proof schema metadata."""

model_class = BindingProof
unknown = EXCLUDE

anoncreds_link_secret = fields.Nested(
AnoncredsLinkSecretSchema(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ async def _match_sent_cred_def_id(self, tag_query: Mapping[str, str]) -> str:
async def create_proposal(
self, cred_ex_record: V20CredExRecord, proposal_data: Mapping[str, str]
) -> Tuple[V20CredFormat, AttachDecorator]:
"""Create indy credential proposal."""
"""Create vc_di credential proposal."""
if proposal_data is None:
proposal_data = {}

Expand Down Expand Up @@ -260,15 +260,15 @@ async def _create():
async def receive_offer(
self, cred_ex_record: V20CredExRecord, cred_offer_message: V20CredOffer
) -> None:
"""Receive indy credential offer."""
"""Receive vcdi credential offer."""

async def create_request(
self, cred_ex_record: V20CredExRecord, request_data: Mapping = None
) -> CredFormatAttachment:
"""Create indy credential request."""
"""Create vcdi credential request."""
if cred_ex_record.state != V20CredExRecord.STATE_OFFER_RECEIVED:
raise V20CredFormatError(
"Indy issue credential format cannot start from credential request"
"vcdi issue credential format cannot start from credential request"
)

await self._check_uniqueness(cred_ex_record.cred_ex_id)
Expand Down Expand Up @@ -332,16 +332,16 @@ async def _create():
async def receive_request(
self, cred_ex_record: V20CredExRecord, cred_request_message: V20CredRequest
) -> None:
"""Receive indy credential request."""
"""Receive vcdi credential request."""
if not cred_ex_record.cred_offer:
raise V20CredFormatError(
"Indy issue credential format cannot start from credential request"
"vcdi issue credential format cannot start from credential request"
)

async def issue_credential(
self, cred_ex_record: V20CredExRecord, retries: int = 5
) -> CredFormatAttachment:
"""Issue indy credential."""
"""Issue vcdi credential."""
await self._check_uniqueness(cred_ex_record.cred_ex_id)

attached_credential = cred_ex_record.cred_offer.attachment(
Expand Down Expand Up @@ -402,15 +402,15 @@ async def issue_credential(
async def receive_credential(
self, cred_ex_record: V20CredExRecord, cred_issue_message: V20CredIssue
) -> None:
"""Receive indy credential.
"""Receive vcdi credential.
Validation is done in the store credential step.
"""

async def store_credential(
self, cred_ex_record: V20CredExRecord, cred_id: str = None
) -> None:
"""Store indy credential."""
"""Store vcdi credential."""
cred = cred_ex_record.cred_issue.attachment(VCDICredFormatHandler.format)

rev_reg_def = None
Expand Down
32 changes: 23 additions & 9 deletions demo/runners/agent_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from runners.support.agent import ( # noqa:E402
CRED_FORMAT_VC_DI,
DemoAgent,
default_genesis_txns,
start_mediator_agent,
Expand Down Expand Up @@ -905,9 +906,7 @@ async def create_schema_and_cred_def(
):
if not self.public_did:
raise Exception("Can't create a schema/cred def without a public DID :-(")
if self.cred_type in [
CRED_FORMAT_INDY,
]:
if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]:
# need to redister schema and cred def on the ledger
self.cred_def_id = await self.agent.create_schema_and_cred_def(
schema_name,
Expand Down Expand Up @@ -974,6 +973,25 @@ async def issue_credential(

return cred_exchange

elif self.cred_type == CRED_FORMAT_VC_DI:
cred_preview = {
"@type": CRED_PREVIEW_TYPE,
"attributes": cred_attrs,
}
offer_request = {
"connection_id": self.agent.connection_id,
"comment": f"Offer on cred def id {cred_def_id}",
"auto_remove": False,
"credential_preview": cred_preview,
"filter": {"vc_di": {"cred_def_id": cred_def_id}},
"trace": self.exchange_tracing,
}
cred_exchange = await self.agent.admin_POST(
"/issue-credential-2.0/send-offer", offer_request
)

return cred_exchange

elif self.cred_type == CRED_FORMAT_JSON_LD:
# TODO create and send the json-ld credential offer
pass
Expand Down Expand Up @@ -1015,9 +1033,7 @@ async def receive_credential(
async def request_proof(self, proof_request, explicit_revoc_required: bool = False):
log_status("#20 Request proof of degree from alice")

if self.cred_type in [
CRED_FORMAT_INDY,
]:
if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]:
indy_proof_request = {
"name": (
proof_request["name"]
Expand Down Expand Up @@ -1100,9 +1116,7 @@ async def verify_proof(self, proof_request):

# log_status(f">>> last proof received: {self.agent.last_proof_received}")

if self.cred_type in [
CRED_FORMAT_INDY,
]:
if self.cred_type in [CRED_FORMAT_INDY, CRED_FORMAT_VC_DI]:
# return verified status
return self.agent.last_proof_received["verified"]

Expand Down
2 changes: 1 addition & 1 deletion demo/runners/faber.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ async def main(args):
else False
),
)
elif faber_agent.cred_type == (CRED_FORMAT_JSON_LD or CRED_FORMAT_VC_DI):
elif faber_agent.cred_type in [CRED_FORMAT_JSON_LD, CRED_FORMAT_VC_DI]:
faber_agent.public_did = True
await faber_agent.initialize(the_agent=agent)
else:
Expand Down
Loading

0 comments on commit 229177f

Please sign in to comment.