diff --git a/aries_cloudagent/anoncreds/issuer.py b/aries_cloudagent/anoncreds/issuer.py index eea459a0ca..2dfb2dcb33 100644 --- a/aries_cloudagent/anoncreds/issuer.py +++ b/aries_cloudagent/anoncreds/issuer.py @@ -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() diff --git a/aries_cloudagent/indy/models/cred_abstract.py b/aries_cloudagent/indy/models/cred_abstract.py index c5e46f233b..999ccb8c2f 100644 --- a/aries_cloudagent/indy/models/cred_abstract.py +++ b/aries_cloudagent/indy/models/cred_abstract.py @@ -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, @@ -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) @@ -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 @@ -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, @@ -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( @@ -308,5 +346,7 @@ class Meta: ) credential = fields.Nested( - CredentialSchema(), required=True, metadata={"description": "", "example": ""} + CredentialSchema(), + required=True, + metadata={"description": "", "example": ""}, ) diff --git a/aries_cloudagent/indy/models/cred_request.py b/aries_cloudagent/indy/models/cred_request.py index 65849026f1..4438a99259 100644 --- a/aries_cloudagent/indy/models/cred_request.py +++ b/aries_cloudagent/indy/models/cred_request.py @@ -83,7 +83,7 @@ class Meta: ) -class BindingProof(BaseModel): +class AnoncredsLinkSecret(BaseModel): """Binding proof model.""" class Meta: @@ -109,13 +109,13 @@ def __init__( self.nonce = nonce -class BindingProofSchema(BaseModelSchema): +class AnoncredsLinkSecretSchema(BaseModelSchema): """VCDI credential request schema.""" class Meta: """VCDI credential request schema metadata.""" - model_class = BindingProof + model_class = AnoncredsLinkSecret unknown = EXCLUDE entropy = fields.Str( @@ -148,6 +148,76 @@ class Meta: ) +class DidcommSignedAttachment(BaseModel): + """Didcomm Signed Attachment Model.""" + + class Meta: + """Didcomm signed attachment metadata.""" + + schema_class = "DidcommSignedAttachmentSchema" + + def __init__(self, attachment_id: str = None, **kwargs): + """Initialize DidcommSignedAttachment.""" + super().__init__(**kwargs) + self.attachment_id = attachment_id + + +class DidcommSignedAttachmentSchema(BaseModelSchema): + """Didcomm Signed Attachment Schema.""" + + class Meta: + """Didcomm Signed Attachment schema metadata.""" + + model_class = DidcommSignedAttachment + unknown = EXCLUDE + + attachment_id = fields.Str( + required=True, metadata={"description": "", "example": ""} + ) + + +class BindingProof(BaseModel): + """Binding Proof Model.""" + + class Meta: + """Binding proof metadata.""" + + schema_class = "BindingProofSchema" + + def __init__( + self, + anoncreds_link_secret: str = None, + didcomm_signed_attachment: str = None, + **kwargs, + ): + """Initialize binding proof.""" + super().__init__(**kwargs) + self.anoncreds_link_secret = anoncreds_link_secret + self.didcomm_signed_attachment = didcomm_signed_attachment + + +class BindingProofSchema(BaseModelSchema): + """Binding Proof Schema.""" + + class Meta: + """Binding proof schema metadata.""" + + model_class = BindingProof + unknown = EXCLUDE + + anoncreds_link_secret = fields.Nested( + AnoncredsLinkSecretSchema(), + required=True, + metadata={"description": "", "example": ""}, + ) + + didcomm_signed_attachment = fields.Nested( + DidcommSignedAttachmentSchema(), + required=True, + metadata={"description": "", "example": ""}, + ) + + class VCDICredRequest(BaseModel): """VCDI credential request model.""" @@ -177,8 +247,12 @@ class Meta: model_class = VCDICredRequest unknown = EXCLUDE - data_model_version = fields.str( + data_model_version = fields.Str( required=True, metadata={"description": "", "example": ""} ) - binding_proof = fields.str(required=True, metadata={"description": "", "example": ""}) + binding_proof = fields.Nested( + BindingProofSchema(), + required=True, + metadata={"description": "", "example": ""}, + ) diff --git a/aries_cloudagent/protocols/issue_credential/v2_0/routes.py b/aries_cloudagent/protocols/issue_credential/v2_0/routes.py index 6ff08911b7..7188df85ce 100644 --- a/aries_cloudagent/protocols/issue_credential/v2_0/routes.py +++ b/aries_cloudagent/protocols/issue_credential/v2_0/routes.py @@ -213,46 +213,6 @@ class V20CredFilterVCDISchema(OpenAPISchema): ) -class V20CredFilterVCDISchema(OpenAPISchema): - """VCDI credential filtration criteria.""" - - cred_def_id = fields.Str( - required=False, - validate=INDY_CRED_DEF_ID_VALIDATE, - metadata={ - "description": "Credential definition identifier", - "example": INDY_CRED_DEF_ID_EXAMPLE, - }, - ) - schema_id = fields.Str( - required=False, - validate=INDY_SCHEMA_ID_VALIDATE, - metadata={ - "description": "Schema identifier", - "example": INDY_SCHEMA_ID_EXAMPLE, - }, - ) - schema_issuer_did = fields.Str( - required=False, - validate=INDY_DID_VALIDATE, - metadata={"description": "Schema issuer DID", "example": INDY_DID_EXAMPLE}, - ) - schema_name = fields.Str( - required=False, - metadata={"description": "Schema name", "example": "preferences"}, - ) - schema_version = fields.Str( - required=False, - validate=INDY_VERSION_VALIDATE, - metadata={"description": "Schema version", "example": INDY_VERSION_EXAMPLE}, - ) - issuer_did = fields.Str( - required=False, - validate=INDY_DID_VALIDATE, - metadata={"description": "Credential issuer DID", "example": INDY_DID_EXAMPLE}, - ) - - class V20CredFilterSchema(OpenAPISchema): """Credential filtration criteria.""" @@ -273,12 +233,6 @@ class V20CredFilterSchema(OpenAPISchema): metadata={"description": "Credential filter for vc_di"}, ) - vc_di = fields.Nested( - V20CredFilterVCDISchema, - required=False, - metadata={"description": "Credential filter for vc_di"}, - ) - @validates_schema def validate_fields(self, data, **kwargs): """Validate schema fields. diff --git a/demo/runners/agent_container.py b/demo/runners/agent_container.py index f07f16b29d..4cf7faa98d 100644 --- a/demo/runners/agent_container.py +++ b/demo/runners/agent_container.py @@ -213,7 +213,9 @@ async def handle_issue_credential(self, message): cred_attrs = self.cred_attrs[message["credential_definition_id"]] cred_preview = { "@type": CRED_PREVIEW_TYPE, - "attributes": [{"name": n, "value": v} for (n, v) in cred_attrs.items()], + "attributes": [ + {"name": n, "value": v} for (n, v) in cred_attrs.items() + ], } try: cred_ex_rec = await self.admin_POST( @@ -420,7 +422,9 @@ async def handle_present_proof_v2_0(self, message): pres_request_indy = ( message["by_format"].get("pres_request", {}).get("indy") ) - pres_request_dif = message["by_format"].get("pres_request", {}).get("dif") + pres_request_dif = ( + message["by_format"].get("pres_request", {}).get("dif") + ) request = {} if not pres_request_dif and not pres_request_indy: @@ -597,7 +601,9 @@ async def generate_invitation( self._connection_ready = asyncio.Future() with log_timer("Generate invitation duration:"): # Generate an invitation - log_status("#7 Create a connection to alice and print out the invite details") + log_status( + "#7 Create a connection to alice and print out the invite details" + ) invi_rec = await self.get_invite( use_did_exchange, auto_accept=auto_accept, @@ -809,7 +815,9 @@ async def initialize( raise Exception("Endorser agent returns None :-(") # set the endorser invite so the agent can auto-connect - self.agent.endorser_invite = self.endorser_agent.endorser_multi_invitation_url + self.agent.endorser_invite = ( + self.endorser_agent.endorser_multi_invitation_url + ) self.agent.endorser_did = self.endorser_agent.endorser_public_did else: self.endorser_agent = None @@ -845,17 +853,25 @@ async def initialize( if self.mediation: # we need to pre-connect the agent to its mediator self.agent.log("Connect wallet to mediator ...") - if not await connect_wallet_to_mediator(self.agent, self.mediator_agent): + if not await connect_wallet_to_mediator( + self.agent, self.mediator_agent + ): raise Exception("Mediation setup FAILED :-(") if self.endorser_agent: self.agent.log("Connect wallet to endorser ...") - if not await connect_wallet_to_endorser(self.agent, self.endorser_agent): + if not await connect_wallet_to_endorser( + self.agent, self.endorser_agent + ): raise Exception("Endorser setup FAILED :-(") if self.taa_accept: await self.agent.taa_accept() # if we are an author, create our public DID here ... - if self.endorser_role and self.endorser_role == "author" and self.endorser_agent: + if ( + self.endorser_role + and self.endorser_role == "author" + and self.endorser_agent + ): if self.public_did and self.cred_type != CRED_FORMAT_JSON_LD: new_did = await self.agent.admin_POST("/wallet/did/create") self.agent.did = new_did["result"]["did"] @@ -1304,7 +1320,9 @@ def arg_parser(ident: str = None, port: int = 8020): metavar=(""), help="API level (10 or 20 (default))", ) - parser.add_argument("--timing", action="store_true", help="Enable timing information") + parser.add_argument( + "--timing", action="store_true", help="Enable timing information" + ) parser.add_argument( "--multitenant", action="store_true", help="Enable multitenancy options" )