Module mydata_did.patched_protocols.present_proof.v1_0.manager
Classes to manage presentations.
Expand source code
"""Classes to manage presentations."""
import json
import logging
import time
from aries_cloudagent.revocation.models.revocation_registry import RevocationRegistry
from aries_cloudagent.config.injection_context import InjectionContext
from aries_cloudagent.core.error import BaseError
from aries_cloudagent.holder.base import BaseHolder, HolderError
from aries_cloudagent.ledger.base import BaseLedger
from aries_cloudagent.messaging.decorators.attach_decorator import AttachDecorator
from aries_cloudagent.messaging.responder import BaseResponder
from aries_cloudagent.verifier.base import BaseVerifier
from .models.presentation_exchange import V10PresentationExchange
from .messages.presentation_ack import PresentationAck
from .messages.presentation_proposal import PresentationProposal
from .messages.presentation_request import PresentationRequest
from .messages.presentation import Presentation
from .message_types import ATTACH_DECO_IDS, PRESENTATION, PRESENTATION_REQUEST
LOGGER = logging.getLogger(__name__)
class PresentationManagerError(BaseError):
"""Presentation error."""
class PresentationManager:
"""Class for managing presentations."""
def __init__(self, context: InjectionContext):
"""
Initialize a PresentationManager.
Args:
context: The context for this presentation
"""
self._context = context
@property
def context(self) -> InjectionContext:
"""
Accessor for the current request context.
Returns:
The injection context for this presentation manager
"""
return self._context
async def create_exchange_for_proposal(
self,
connection_id: str,
presentation_proposal_message: PresentationProposal,
auto_present: bool = None,
):
"""
Create a presentation exchange record for input presentation proposal.
Args:
connection_id: connection identifier
presentation_proposal_message: presentation proposal to serialize
to exchange record
auto_present: whether to present proof upon receiving proof request
(default to configuration setting)
Returns:
Presentation exchange record, created
"""
presentation_exchange_record = V10PresentationExchange(
connection_id=connection_id,
thread_id=presentation_proposal_message._thread_id,
initiator=V10PresentationExchange.INITIATOR_SELF,
role=V10PresentationExchange.ROLE_PROVER,
state=V10PresentationExchange.STATE_PROPOSAL_SENT,
presentation_proposal_dict=presentation_proposal_message.serialize(),
auto_present=auto_present,
trace=(presentation_proposal_message._trace is not None),
)
await presentation_exchange_record.save(
self.context, reason="create presentation proposal"
)
return presentation_exchange_record
async def receive_proposal(self):
"""
Receive a presentation proposal from message in context on manager creation.
Returns:
Presentation exchange record, created
"""
presentation_proposal_message = self.context.message
presentation_exchange_record = V10PresentationExchange(
connection_id=self.context.connection_record.connection_id,
thread_id=presentation_proposal_message._thread_id,
initiator=V10PresentationExchange.INITIATOR_EXTERNAL,
role=V10PresentationExchange.ROLE_VERIFIER,
state=V10PresentationExchange.STATE_PROPOSAL_RECEIVED,
presentation_proposal_dict=presentation_proposal_message.serialize(),
trace=(presentation_proposal_message._trace is not None),
)
await presentation_exchange_record.save(
self.context, reason="receive presentation request"
)
return presentation_exchange_record
async def create_bound_request(
self,
presentation_exchange_record: V10PresentationExchange,
name: str = None,
version: str = None,
nonce: str = None,
comment: str = None,
):
"""
Create a presentation request bound to a proposal.
Args:
presentation_exchange_record: Presentation exchange record for which
to create presentation request
name: name to use in presentation request (None for default)
version: version to use in presentation request (None for default)
nonce: nonce to use in presentation request (None to generate)
comment: Optional human-readable comment pertaining to request creation
Returns:
A tuple (updated presentation exchange record, presentation request message)
"""
indy_proof_request = await (
PresentationProposal.deserialize(
presentation_exchange_record.presentation_proposal_dict
)
).presentation_proposal.indy_proof_request(
name=name,
version=version,
nonce=nonce,
ledger=await self.context.inject(BaseLedger),
)
presentation_request_message = PresentationRequest(
comment=comment,
request_presentations_attach=[
AttachDecorator.from_indy_dict(
indy_dict=indy_proof_request,
ident=ATTACH_DECO_IDS[PRESENTATION_REQUEST],
)
],
)
presentation_request_message._thread = {
"thid": presentation_exchange_record.thread_id
}
presentation_request_message.assign_trace_decorator(
self.context.settings, presentation_exchange_record.trace
)
presentation_exchange_record.thread_id = presentation_request_message._thread_id
presentation_exchange_record.state = V10PresentationExchange.STATE_REQUEST_SENT
presentation_exchange_record.presentation_request = indy_proof_request
await presentation_exchange_record.save(
self.context, reason="create (bound) presentation request"
)
return presentation_exchange_record, presentation_request_message
async def create_exchange_for_request(
self, connection_id: str, presentation_request_message: PresentationRequest
):
"""
Create a presentation exchange record for input presentation request.
Args:
connection_id: connection identifier
presentation_request_message: presentation request to use in creating
exchange record, extracting indy proof request and thread id
Returns:
Presentation exchange record, updated
"""
presentation_exchange_record = V10PresentationExchange(
connection_id=connection_id,
thread_id=presentation_request_message._thread_id,
initiator=V10PresentationExchange.INITIATOR_SELF,
role=V10PresentationExchange.ROLE_VERIFIER,
state=V10PresentationExchange.STATE_REQUEST_SENT,
presentation_request=presentation_request_message.indy_proof_request(),
presentation_request_dict=presentation_request_message.serialize(),
trace=(presentation_request_message._trace is not None),
)
await presentation_exchange_record.save(
self.context, reason="create (free) presentation request"
)
return presentation_exchange_record
async def receive_request(
self, presentation_exchange_record: V10PresentationExchange
):
"""
Receive a presentation request.
Args:
presentation_exchange_record: presentation exchange record with
request to receive
Returns:
The presentation_exchange_record, updated
"""
presentation_exchange_record.state = (
V10PresentationExchange.STATE_REQUEST_RECEIVED
)
await presentation_exchange_record.save(
self.context, reason="receive presentation request"
)
return presentation_exchange_record
async def create_presentation(
self,
presentation_exchange_record: V10PresentationExchange,
requested_credentials: dict,
comment: str = None,
):
"""
Create a presentation.
Args:
presentation_exchange_record: Record to update
requested_credentials: Indy formatted requested_credentials
comment: optional human-readable comment
Example `requested_credentials` format:
::
{
"self_attested_attributes": {
"j233ffbc-bd35-49b1-934f-51e083106f6d": "value"
},
"requested_attributes": {
"6253ffbb-bd35-49b3-934f-46e083106f6c": {
"cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e",
"revealed": true
}
},
"requested_predicates": {
"bfc8a97d-60d3-4f21-b998-85eeabe5c8c0": {
"cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e"
}
}
}
Returns:
A tuple (updated presentation exchange record, presentation message)
"""
# Get all credentials for this presentation
holder: BaseHolder = await self.context.inject(BaseHolder)
credentials = {}
# extract credential ids and non_revoked
requested_referents = {}
presentation_request = presentation_exchange_record.presentation_request
attr_creds = requested_credentials.get("requested_attributes", {})
req_attrs = presentation_request.get("requested_attributes", {})
for referent in attr_creds:
requested_referents[referent] = {"cred_id": attr_creds[referent]["cred_id"]}
if referent in req_attrs and "non_revoked" in req_attrs[referent]:
requested_referents[referent]["non_revoked"] = req_attrs[referent][
"non_revoked"
]
preds_creds = requested_credentials.get("requested_predicates", {})
req_preds = presentation_request.get("requested_predicates", {})
for referent in preds_creds:
requested_referents[referent] = {
"cred_id": preds_creds[referent]["cred_id"]
}
if referent in req_preds and "non_revoked" in req_preds[referent]:
requested_referents[referent]["non_revoked"] = req_preds[referent][
"non_revoked"
]
# extract mapping of presentation referents to credential ids
for referent in requested_referents:
credential_id = requested_referents[referent]["cred_id"]
if credential_id not in credentials:
credentials[credential_id] = json.loads(
await holder.get_credential(credential_id)
)
# Get all schema, credential definition, and revocation registry in use
ledger: BaseLedger = await self.context.inject(BaseLedger)
schemas = {}
credential_definitions = {}
revocation_registries = {}
async with ledger:
for credential in credentials.values():
schema_id = credential["schema_id"]
if schema_id not in schemas:
schemas[schema_id] = await ledger.get_schema(schema_id)
credential_definition_id = credential["cred_def_id"]
if credential_definition_id not in credential_definitions:
credential_definitions[
credential_definition_id
] = await ledger.get_credential_definition(credential_definition_id)
if credential.get("rev_reg_id"):
revocation_registry_id = credential["rev_reg_id"]
if revocation_registry_id not in revocation_registries:
revocation_registries[
revocation_registry_id
] = RevocationRegistry.from_definition(
await ledger.get_revoc_reg_def(revocation_registry_id), True
)
# Get delta with non-revocation interval defined in "non_revoked"
# of the presentation request or attributes
epoch_now = int(time.time())
non_revoc_interval = {"from": 0, "to": epoch_now}
non_revoc_interval.update(
presentation_exchange_record.presentation_request.get("non_revoked") or {}
)
revoc_reg_deltas = {}
async with ledger:
for precis in requested_referents.values(): # cred_id, non-revoc interval
credential_id = precis["cred_id"]
if not credentials[credential_id].get("rev_reg_id"):
continue
if "timestamp" in precis:
continue
rev_reg_id = credentials[credential_id]["rev_reg_id"]
referent_non_revoc_interval = precis.get(
"non_revoked", non_revoc_interval
)
if referent_non_revoc_interval:
key = (
f"{rev_reg_id}_{referent_non_revoc_interval.get('from', 0)}_"
f"{referent_non_revoc_interval.get('to', epoch_now)}"
)
if key not in revoc_reg_deltas:
(delta, delta_timestamp) = await ledger.get_revoc_reg_delta(
rev_reg_id,
referent_non_revoc_interval.get("from", 0),
referent_non_revoc_interval.get("to", epoch_now),
)
revoc_reg_deltas[key] = (
rev_reg_id,
credential_id,
delta,
delta_timestamp,
)
for stamp_me in requested_referents.values():
# often one cred satisfies many requested attrs/preds
if stamp_me["cred_id"] == credential_id:
stamp_me["timestamp"] = revoc_reg_deltas[key][3]
# Get revocation states to prove non-revoked
revocation_states = {}
for (
rev_reg_id,
credential_id,
delta,
delta_timestamp,
) in revoc_reg_deltas.values():
if rev_reg_id not in revocation_states:
revocation_states[rev_reg_id] = {}
rev_reg = revocation_registries[rev_reg_id]
tails_local_path = await rev_reg.get_or_fetch_local_tails_path()
try:
revocation_states[rev_reg_id][delta_timestamp] = json.loads(
await holder.create_revocation_state(
credentials[credential_id]["cred_rev_id"],
rev_reg.reg_def,
delta,
delta_timestamp,
tails_local_path,
)
)
except HolderError as e:
LOGGER.error(
f"Failed to create revocation state: {e.error_code}, {e.message}"
)
raise e
for (referent, precis) in requested_referents.items():
if "timestamp" not in precis:
continue
if referent in requested_credentials["requested_attributes"]:
requested_credentials["requested_attributes"][referent][
"timestamp"
] = precis["timestamp"]
if referent in requested_credentials["requested_predicates"]:
requested_credentials["requested_predicates"][referent][
"timestamp"
] = precis["timestamp"]
indy_proof_json = await holder.create_presentation(
presentation_exchange_record.presentation_request,
requested_credentials,
schemas,
credential_definitions,
revocation_states,
)
indy_proof = json.loads(indy_proof_json)
presentation_message = Presentation(
comment=comment,
presentations_attach=[
AttachDecorator.from_indy_dict(
indy_dict=indy_proof, ident=ATTACH_DECO_IDS[PRESENTATION]
)
],
)
presentation_message._thread = {"thid": presentation_exchange_record.thread_id}
presentation_message.assign_trace_decorator(
self.context.settings, presentation_exchange_record.trace
)
# save presentation exchange state
presentation_exchange_record.state = (
V10PresentationExchange.STATE_PRESENTATION_SENT
)
presentation_exchange_record.presentation = indy_proof
await presentation_exchange_record.save(
self.context, reason="create presentation"
)
return presentation_exchange_record, presentation_message
async def receive_presentation(self):
"""
Receive a presentation, from message in context on manager creation.
Returns:
presentation exchange record, retrieved and updated
"""
presentation = self.context.message.indy_proof()
thread_id = self.context.message._thread_id
connection_id_filter = (
{"connection_id": self.context.connection_record.connection_id}
if self.context.connection_record is not None
else None
)
(
presentation_exchange_record
) = await V10PresentationExchange.retrieve_by_tag_filter(
self.context, {"thread_id": thread_id}, connection_id_filter
)
# Check for bait-and-switch in presented attribute values vs. proposal
if presentation_exchange_record.presentation_proposal_dict:
exchange_pres_proposal = PresentationProposal.deserialize(
presentation_exchange_record.presentation_proposal_dict
)
presentation_preview = exchange_pres_proposal.presentation_proposal
proof_req = presentation_exchange_record.presentation_request
for (reft, attr_spec) in presentation["requested_proof"][
"revealed_attrs"
].items():
name = proof_req["requested_attributes"][reft]["name"]
value = attr_spec["raw"]
if not presentation_preview.has_attr_spec(
cred_def_id=presentation["identifiers"][
attr_spec["sub_proof_index"]
]["cred_def_id"],
name=name,
value=value,
):
raise PresentationManagerError(
f"Presentation {name}={value} mismatches proposal value"
)
presentation_exchange_record.presentation = presentation
presentation_exchange_record.state = (
V10PresentationExchange.STATE_PRESENTATION_RECEIVED
)
await presentation_exchange_record.save(
self.context, reason="receive presentation"
)
return presentation_exchange_record
async def verify_presentation(
self, presentation_exchange_record: V10PresentationExchange
):
"""
Verify a presentation.
Args:
presentation_exchange_record: presentation exchange record
with presentation request and presentation to verify
Returns:
presentation record, updated
"""
indy_proof_request = presentation_exchange_record.presentation_request
indy_proof = presentation_exchange_record.presentation
schema_ids = []
credential_definition_ids = []
schemas = {}
credential_definitions = {}
rev_reg_defs = {}
rev_reg_entries = {}
identifiers = indy_proof["identifiers"]
ledger: BaseLedger = await self.context.inject(BaseLedger)
async with ledger:
for identifier in identifiers:
schema_ids.append(identifier["schema_id"])
credential_definition_ids.append(identifier["cred_def_id"])
# Build schemas for anoncreds
if identifier["schema_id"] not in schemas:
schemas[identifier["schema_id"]] = await ledger.get_schema(
identifier["schema_id"]
)
if identifier["cred_def_id"] not in credential_definitions:
credential_definitions[
identifier["cred_def_id"]
] = await ledger.get_credential_definition(
identifier["cred_def_id"]
)
if identifier.get("rev_reg_id"):
if identifier["rev_reg_id"] not in rev_reg_defs:
rev_reg_defs[
identifier["rev_reg_id"]
] = await ledger.get_revoc_reg_def(identifier["rev_reg_id"])
if identifier.get("timestamp"):
rev_reg_entries.setdefault(identifier["rev_reg_id"], {})
if (
identifier["timestamp"]
not in rev_reg_entries[identifier["rev_reg_id"]]
):
(
found_rev_reg_entry,
_found_timestamp,
) = await ledger.get_revoc_reg_entry(
identifier["rev_reg_id"], identifier["timestamp"]
)
rev_reg_entries[identifier["rev_reg_id"]][
identifier["timestamp"]
] = found_rev_reg_entry
verifier: BaseVerifier = await self.context.inject(BaseVerifier)
presentation_exchange_record.verified = json.dumps( # tag: needs string value
await verifier.verify_presentation(
indy_proof_request,
indy_proof,
schemas,
credential_definitions,
rev_reg_defs,
rev_reg_entries,
)
)
presentation_exchange_record.state = V10PresentationExchange.STATE_VERIFIED
await presentation_exchange_record.save(
self.context, reason="verify presentation"
)
await self.send_presentation_ack(presentation_exchange_record)
return presentation_exchange_record
async def send_presentation_ack(
self, presentation_exchange_record: V10PresentationExchange
):
"""
Send acknowledgement of presentation receipt.
Args:
presentation_exchange_record: presentation exchange record with thread id
"""
responder = await self.context.inject(BaseResponder, required=False)
if responder:
presentation_ack_message = PresentationAck()
presentation_ack_message._thread = {
"thid": presentation_exchange_record.thread_id
}
presentation_ack_message.assign_trace_decorator(
self.context.settings, presentation_exchange_record.trace
)
await responder.send_reply(
presentation_ack_message,
connection_id=presentation_exchange_record.connection_id,
)
else:
LOGGER.warning(
"Configuration has no BaseResponder: cannot ack presentation on %s",
presentation_exchange_record.thread_id,
)
async def receive_presentation_ack(self):
"""
Receive a presentation ack, from message in context on manager creation.
Returns:
presentation exchange record, retrieved and updated
"""
(
presentation_exchange_record
) = await V10PresentationExchange.retrieve_by_tag_filter(
self.context,
{"thread_id": self.context.message._thread_id},
{"connection_id": self.context.connection_record.connection_id},
)
presentation_exchange_record.state = (
V10PresentationExchange.STATE_PRESENTATION_ACKED
)
await presentation_exchange_record.save(
self.context, reason="receive presentation ack"
)
return presentation_exchange_record
Classes
class PresentationManager (context: aries_cloudagent.config.injection_context.InjectionContext)
-
Class for managing presentations.
Initialize a PresentationManager.
Args
context
- The context for this presentation
Expand source code
class PresentationManager: """Class for managing presentations.""" def __init__(self, context: InjectionContext): """ Initialize a PresentationManager. Args: context: The context for this presentation """ self._context = context @property def context(self) -> InjectionContext: """ Accessor for the current request context. Returns: The injection context for this presentation manager """ return self._context async def create_exchange_for_proposal( self, connection_id: str, presentation_proposal_message: PresentationProposal, auto_present: bool = None, ): """ Create a presentation exchange record for input presentation proposal. Args: connection_id: connection identifier presentation_proposal_message: presentation proposal to serialize to exchange record auto_present: whether to present proof upon receiving proof request (default to configuration setting) Returns: Presentation exchange record, created """ presentation_exchange_record = V10PresentationExchange( connection_id=connection_id, thread_id=presentation_proposal_message._thread_id, initiator=V10PresentationExchange.INITIATOR_SELF, role=V10PresentationExchange.ROLE_PROVER, state=V10PresentationExchange.STATE_PROPOSAL_SENT, presentation_proposal_dict=presentation_proposal_message.serialize(), auto_present=auto_present, trace=(presentation_proposal_message._trace is not None), ) await presentation_exchange_record.save( self.context, reason="create presentation proposal" ) return presentation_exchange_record async def receive_proposal(self): """ Receive a presentation proposal from message in context on manager creation. Returns: Presentation exchange record, created """ presentation_proposal_message = self.context.message presentation_exchange_record = V10PresentationExchange( connection_id=self.context.connection_record.connection_id, thread_id=presentation_proposal_message._thread_id, initiator=V10PresentationExchange.INITIATOR_EXTERNAL, role=V10PresentationExchange.ROLE_VERIFIER, state=V10PresentationExchange.STATE_PROPOSAL_RECEIVED, presentation_proposal_dict=presentation_proposal_message.serialize(), trace=(presentation_proposal_message._trace is not None), ) await presentation_exchange_record.save( self.context, reason="receive presentation request" ) return presentation_exchange_record async def create_bound_request( self, presentation_exchange_record: V10PresentationExchange, name: str = None, version: str = None, nonce: str = None, comment: str = None, ): """ Create a presentation request bound to a proposal. Args: presentation_exchange_record: Presentation exchange record for which to create presentation request name: name to use in presentation request (None for default) version: version to use in presentation request (None for default) nonce: nonce to use in presentation request (None to generate) comment: Optional human-readable comment pertaining to request creation Returns: A tuple (updated presentation exchange record, presentation request message) """ indy_proof_request = await ( PresentationProposal.deserialize( presentation_exchange_record.presentation_proposal_dict ) ).presentation_proposal.indy_proof_request( name=name, version=version, nonce=nonce, ledger=await self.context.inject(BaseLedger), ) presentation_request_message = PresentationRequest( comment=comment, request_presentations_attach=[ AttachDecorator.from_indy_dict( indy_dict=indy_proof_request, ident=ATTACH_DECO_IDS[PRESENTATION_REQUEST], ) ], ) presentation_request_message._thread = { "thid": presentation_exchange_record.thread_id } presentation_request_message.assign_trace_decorator( self.context.settings, presentation_exchange_record.trace ) presentation_exchange_record.thread_id = presentation_request_message._thread_id presentation_exchange_record.state = V10PresentationExchange.STATE_REQUEST_SENT presentation_exchange_record.presentation_request = indy_proof_request await presentation_exchange_record.save( self.context, reason="create (bound) presentation request" ) return presentation_exchange_record, presentation_request_message async def create_exchange_for_request( self, connection_id: str, presentation_request_message: PresentationRequest ): """ Create a presentation exchange record for input presentation request. Args: connection_id: connection identifier presentation_request_message: presentation request to use in creating exchange record, extracting indy proof request and thread id Returns: Presentation exchange record, updated """ presentation_exchange_record = V10PresentationExchange( connection_id=connection_id, thread_id=presentation_request_message._thread_id, initiator=V10PresentationExchange.INITIATOR_SELF, role=V10PresentationExchange.ROLE_VERIFIER, state=V10PresentationExchange.STATE_REQUEST_SENT, presentation_request=presentation_request_message.indy_proof_request(), presentation_request_dict=presentation_request_message.serialize(), trace=(presentation_request_message._trace is not None), ) await presentation_exchange_record.save( self.context, reason="create (free) presentation request" ) return presentation_exchange_record async def receive_request( self, presentation_exchange_record: V10PresentationExchange ): """ Receive a presentation request. Args: presentation_exchange_record: presentation exchange record with request to receive Returns: The presentation_exchange_record, updated """ presentation_exchange_record.state = ( V10PresentationExchange.STATE_REQUEST_RECEIVED ) await presentation_exchange_record.save( self.context, reason="receive presentation request" ) return presentation_exchange_record async def create_presentation( self, presentation_exchange_record: V10PresentationExchange, requested_credentials: dict, comment: str = None, ): """ Create a presentation. Args: presentation_exchange_record: Record to update requested_credentials: Indy formatted requested_credentials comment: optional human-readable comment Example `requested_credentials` format: :: { "self_attested_attributes": { "j233ffbc-bd35-49b1-934f-51e083106f6d": "value" }, "requested_attributes": { "6253ffbb-bd35-49b3-934f-46e083106f6c": { "cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e", "revealed": true } }, "requested_predicates": { "bfc8a97d-60d3-4f21-b998-85eeabe5c8c0": { "cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e" } } } Returns: A tuple (updated presentation exchange record, presentation message) """ # Get all credentials for this presentation holder: BaseHolder = await self.context.inject(BaseHolder) credentials = {} # extract credential ids and non_revoked requested_referents = {} presentation_request = presentation_exchange_record.presentation_request attr_creds = requested_credentials.get("requested_attributes", {}) req_attrs = presentation_request.get("requested_attributes", {}) for referent in attr_creds: requested_referents[referent] = {"cred_id": attr_creds[referent]["cred_id"]} if referent in req_attrs and "non_revoked" in req_attrs[referent]: requested_referents[referent]["non_revoked"] = req_attrs[referent][ "non_revoked" ] preds_creds = requested_credentials.get("requested_predicates", {}) req_preds = presentation_request.get("requested_predicates", {}) for referent in preds_creds: requested_referents[referent] = { "cred_id": preds_creds[referent]["cred_id"] } if referent in req_preds and "non_revoked" in req_preds[referent]: requested_referents[referent]["non_revoked"] = req_preds[referent][ "non_revoked" ] # extract mapping of presentation referents to credential ids for referent in requested_referents: credential_id = requested_referents[referent]["cred_id"] if credential_id not in credentials: credentials[credential_id] = json.loads( await holder.get_credential(credential_id) ) # Get all schema, credential definition, and revocation registry in use ledger: BaseLedger = await self.context.inject(BaseLedger) schemas = {} credential_definitions = {} revocation_registries = {} async with ledger: for credential in credentials.values(): schema_id = credential["schema_id"] if schema_id not in schemas: schemas[schema_id] = await ledger.get_schema(schema_id) credential_definition_id = credential["cred_def_id"] if credential_definition_id not in credential_definitions: credential_definitions[ credential_definition_id ] = await ledger.get_credential_definition(credential_definition_id) if credential.get("rev_reg_id"): revocation_registry_id = credential["rev_reg_id"] if revocation_registry_id not in revocation_registries: revocation_registries[ revocation_registry_id ] = RevocationRegistry.from_definition( await ledger.get_revoc_reg_def(revocation_registry_id), True ) # Get delta with non-revocation interval defined in "non_revoked" # of the presentation request or attributes epoch_now = int(time.time()) non_revoc_interval = {"from": 0, "to": epoch_now} non_revoc_interval.update( presentation_exchange_record.presentation_request.get("non_revoked") or {} ) revoc_reg_deltas = {} async with ledger: for precis in requested_referents.values(): # cred_id, non-revoc interval credential_id = precis["cred_id"] if not credentials[credential_id].get("rev_reg_id"): continue if "timestamp" in precis: continue rev_reg_id = credentials[credential_id]["rev_reg_id"] referent_non_revoc_interval = precis.get( "non_revoked", non_revoc_interval ) if referent_non_revoc_interval: key = ( f"{rev_reg_id}_{referent_non_revoc_interval.get('from', 0)}_" f"{referent_non_revoc_interval.get('to', epoch_now)}" ) if key not in revoc_reg_deltas: (delta, delta_timestamp) = await ledger.get_revoc_reg_delta( rev_reg_id, referent_non_revoc_interval.get("from", 0), referent_non_revoc_interval.get("to", epoch_now), ) revoc_reg_deltas[key] = ( rev_reg_id, credential_id, delta, delta_timestamp, ) for stamp_me in requested_referents.values(): # often one cred satisfies many requested attrs/preds if stamp_me["cred_id"] == credential_id: stamp_me["timestamp"] = revoc_reg_deltas[key][3] # Get revocation states to prove non-revoked revocation_states = {} for ( rev_reg_id, credential_id, delta, delta_timestamp, ) in revoc_reg_deltas.values(): if rev_reg_id not in revocation_states: revocation_states[rev_reg_id] = {} rev_reg = revocation_registries[rev_reg_id] tails_local_path = await rev_reg.get_or_fetch_local_tails_path() try: revocation_states[rev_reg_id][delta_timestamp] = json.loads( await holder.create_revocation_state( credentials[credential_id]["cred_rev_id"], rev_reg.reg_def, delta, delta_timestamp, tails_local_path, ) ) except HolderError as e: LOGGER.error( f"Failed to create revocation state: {e.error_code}, {e.message}" ) raise e for (referent, precis) in requested_referents.items(): if "timestamp" not in precis: continue if referent in requested_credentials["requested_attributes"]: requested_credentials["requested_attributes"][referent][ "timestamp" ] = precis["timestamp"] if referent in requested_credentials["requested_predicates"]: requested_credentials["requested_predicates"][referent][ "timestamp" ] = precis["timestamp"] indy_proof_json = await holder.create_presentation( presentation_exchange_record.presentation_request, requested_credentials, schemas, credential_definitions, revocation_states, ) indy_proof = json.loads(indy_proof_json) presentation_message = Presentation( comment=comment, presentations_attach=[ AttachDecorator.from_indy_dict( indy_dict=indy_proof, ident=ATTACH_DECO_IDS[PRESENTATION] ) ], ) presentation_message._thread = {"thid": presentation_exchange_record.thread_id} presentation_message.assign_trace_decorator( self.context.settings, presentation_exchange_record.trace ) # save presentation exchange state presentation_exchange_record.state = ( V10PresentationExchange.STATE_PRESENTATION_SENT ) presentation_exchange_record.presentation = indy_proof await presentation_exchange_record.save( self.context, reason="create presentation" ) return presentation_exchange_record, presentation_message async def receive_presentation(self): """ Receive a presentation, from message in context on manager creation. Returns: presentation exchange record, retrieved and updated """ presentation = self.context.message.indy_proof() thread_id = self.context.message._thread_id connection_id_filter = ( {"connection_id": self.context.connection_record.connection_id} if self.context.connection_record is not None else None ) ( presentation_exchange_record ) = await V10PresentationExchange.retrieve_by_tag_filter( self.context, {"thread_id": thread_id}, connection_id_filter ) # Check for bait-and-switch in presented attribute values vs. proposal if presentation_exchange_record.presentation_proposal_dict: exchange_pres_proposal = PresentationProposal.deserialize( presentation_exchange_record.presentation_proposal_dict ) presentation_preview = exchange_pres_proposal.presentation_proposal proof_req = presentation_exchange_record.presentation_request for (reft, attr_spec) in presentation["requested_proof"][ "revealed_attrs" ].items(): name = proof_req["requested_attributes"][reft]["name"] value = attr_spec["raw"] if not presentation_preview.has_attr_spec( cred_def_id=presentation["identifiers"][ attr_spec["sub_proof_index"] ]["cred_def_id"], name=name, value=value, ): raise PresentationManagerError( f"Presentation {name}={value} mismatches proposal value" ) presentation_exchange_record.presentation = presentation presentation_exchange_record.state = ( V10PresentationExchange.STATE_PRESENTATION_RECEIVED ) await presentation_exchange_record.save( self.context, reason="receive presentation" ) return presentation_exchange_record async def verify_presentation( self, presentation_exchange_record: V10PresentationExchange ): """ Verify a presentation. Args: presentation_exchange_record: presentation exchange record with presentation request and presentation to verify Returns: presentation record, updated """ indy_proof_request = presentation_exchange_record.presentation_request indy_proof = presentation_exchange_record.presentation schema_ids = [] credential_definition_ids = [] schemas = {} credential_definitions = {} rev_reg_defs = {} rev_reg_entries = {} identifiers = indy_proof["identifiers"] ledger: BaseLedger = await self.context.inject(BaseLedger) async with ledger: for identifier in identifiers: schema_ids.append(identifier["schema_id"]) credential_definition_ids.append(identifier["cred_def_id"]) # Build schemas for anoncreds if identifier["schema_id"] not in schemas: schemas[identifier["schema_id"]] = await ledger.get_schema( identifier["schema_id"] ) if identifier["cred_def_id"] not in credential_definitions: credential_definitions[ identifier["cred_def_id"] ] = await ledger.get_credential_definition( identifier["cred_def_id"] ) if identifier.get("rev_reg_id"): if identifier["rev_reg_id"] not in rev_reg_defs: rev_reg_defs[ identifier["rev_reg_id"] ] = await ledger.get_revoc_reg_def(identifier["rev_reg_id"]) if identifier.get("timestamp"): rev_reg_entries.setdefault(identifier["rev_reg_id"], {}) if ( identifier["timestamp"] not in rev_reg_entries[identifier["rev_reg_id"]] ): ( found_rev_reg_entry, _found_timestamp, ) = await ledger.get_revoc_reg_entry( identifier["rev_reg_id"], identifier["timestamp"] ) rev_reg_entries[identifier["rev_reg_id"]][ identifier["timestamp"] ] = found_rev_reg_entry verifier: BaseVerifier = await self.context.inject(BaseVerifier) presentation_exchange_record.verified = json.dumps( # tag: needs string value await verifier.verify_presentation( indy_proof_request, indy_proof, schemas, credential_definitions, rev_reg_defs, rev_reg_entries, ) ) presentation_exchange_record.state = V10PresentationExchange.STATE_VERIFIED await presentation_exchange_record.save( self.context, reason="verify presentation" ) await self.send_presentation_ack(presentation_exchange_record) return presentation_exchange_record async def send_presentation_ack( self, presentation_exchange_record: V10PresentationExchange ): """ Send acknowledgement of presentation receipt. Args: presentation_exchange_record: presentation exchange record with thread id """ responder = await self.context.inject(BaseResponder, required=False) if responder: presentation_ack_message = PresentationAck() presentation_ack_message._thread = { "thid": presentation_exchange_record.thread_id } presentation_ack_message.assign_trace_decorator( self.context.settings, presentation_exchange_record.trace ) await responder.send_reply( presentation_ack_message, connection_id=presentation_exchange_record.connection_id, ) else: LOGGER.warning( "Configuration has no BaseResponder: cannot ack presentation on %s", presentation_exchange_record.thread_id, ) async def receive_presentation_ack(self): """ Receive a presentation ack, from message in context on manager creation. Returns: presentation exchange record, retrieved and updated """ ( presentation_exchange_record ) = await V10PresentationExchange.retrieve_by_tag_filter( self.context, {"thread_id": self.context.message._thread_id}, {"connection_id": self.context.connection_record.connection_id}, ) presentation_exchange_record.state = ( V10PresentationExchange.STATE_PRESENTATION_ACKED ) await presentation_exchange_record.save( self.context, reason="receive presentation ack" ) return presentation_exchange_record
Instance variables
var context : aries_cloudagent.config.injection_context.InjectionContext
-
Accessor for the current request context.
Returns
The injection context for this presentation manager
Expand source code
@property def context(self) -> InjectionContext: """ Accessor for the current request context. Returns: The injection context for this presentation manager """ return self._context
Methods
async def create_bound_request(self, presentation_exchange_record: V10PresentationExchange, name: str = None, version: str = None, nonce: str = None, comment: str = None)
-
Create a presentation request bound to a proposal.
Args
presentation_exchange_record
- Presentation exchange record for which to create presentation request
name
- name to use in presentation request (None for default)
version
- version to use in presentation request (None for default)
nonce
- nonce to use in presentation request (None to generate)
comment
- Optional human-readable comment pertaining to request creation
Returns
A tuple (updated presentation exchange record, presentation request message)
Expand source code
async def create_bound_request( self, presentation_exchange_record: V10PresentationExchange, name: str = None, version: str = None, nonce: str = None, comment: str = None, ): """ Create a presentation request bound to a proposal. Args: presentation_exchange_record: Presentation exchange record for which to create presentation request name: name to use in presentation request (None for default) version: version to use in presentation request (None for default) nonce: nonce to use in presentation request (None to generate) comment: Optional human-readable comment pertaining to request creation Returns: A tuple (updated presentation exchange record, presentation request message) """ indy_proof_request = await ( PresentationProposal.deserialize( presentation_exchange_record.presentation_proposal_dict ) ).presentation_proposal.indy_proof_request( name=name, version=version, nonce=nonce, ledger=await self.context.inject(BaseLedger), ) presentation_request_message = PresentationRequest( comment=comment, request_presentations_attach=[ AttachDecorator.from_indy_dict( indy_dict=indy_proof_request, ident=ATTACH_DECO_IDS[PRESENTATION_REQUEST], ) ], ) presentation_request_message._thread = { "thid": presentation_exchange_record.thread_id } presentation_request_message.assign_trace_decorator( self.context.settings, presentation_exchange_record.trace ) presentation_exchange_record.thread_id = presentation_request_message._thread_id presentation_exchange_record.state = V10PresentationExchange.STATE_REQUEST_SENT presentation_exchange_record.presentation_request = indy_proof_request await presentation_exchange_record.save( self.context, reason="create (bound) presentation request" ) return presentation_exchange_record, presentation_request_message
async def create_exchange_for_proposal(self, connection_id: str, presentation_proposal_message: PresentationProposal, auto_present: bool = None)
-
Create a presentation exchange record for input presentation proposal.
Args
connection_id
- connection identifier
presentation_proposal_message
- presentation proposal to serialize to exchange record
auto_present
- whether to present proof upon receiving proof request (default to configuration setting)
Returns
Presentation exchange record, created
Expand source code
async def create_exchange_for_proposal( self, connection_id: str, presentation_proposal_message: PresentationProposal, auto_present: bool = None, ): """ Create a presentation exchange record for input presentation proposal. Args: connection_id: connection identifier presentation_proposal_message: presentation proposal to serialize to exchange record auto_present: whether to present proof upon receiving proof request (default to configuration setting) Returns: Presentation exchange record, created """ presentation_exchange_record = V10PresentationExchange( connection_id=connection_id, thread_id=presentation_proposal_message._thread_id, initiator=V10PresentationExchange.INITIATOR_SELF, role=V10PresentationExchange.ROLE_PROVER, state=V10PresentationExchange.STATE_PROPOSAL_SENT, presentation_proposal_dict=presentation_proposal_message.serialize(), auto_present=auto_present, trace=(presentation_proposal_message._trace is not None), ) await presentation_exchange_record.save( self.context, reason="create presentation proposal" ) return presentation_exchange_record
async def create_exchange_for_request(self, connection_id: str, presentation_request_message: PresentationRequest)
-
Create a presentation exchange record for input presentation request.
Args
connection_id
- connection identifier
presentation_request_message
- presentation request to use in creating exchange record, extracting indy proof request and thread id
Returns
Presentation exchange record, updated
Expand source code
async def create_exchange_for_request( self, connection_id: str, presentation_request_message: PresentationRequest ): """ Create a presentation exchange record for input presentation request. Args: connection_id: connection identifier presentation_request_message: presentation request to use in creating exchange record, extracting indy proof request and thread id Returns: Presentation exchange record, updated """ presentation_exchange_record = V10PresentationExchange( connection_id=connection_id, thread_id=presentation_request_message._thread_id, initiator=V10PresentationExchange.INITIATOR_SELF, role=V10PresentationExchange.ROLE_VERIFIER, state=V10PresentationExchange.STATE_REQUEST_SENT, presentation_request=presentation_request_message.indy_proof_request(), presentation_request_dict=presentation_request_message.serialize(), trace=(presentation_request_message._trace is not None), ) await presentation_exchange_record.save( self.context, reason="create (free) presentation request" ) return presentation_exchange_record
async def create_presentation(self, presentation_exchange_record: V10PresentationExchange, requested_credentials: dict, comment: str = None)
-
Create a presentation.
Args
presentation_exchange_record
- Record to update
requested_credentials
- Indy formatted requested_credentials
comment
- optional human-readable comment
Example
requested_credentials
format:::
{ "self_attested_attributes": { "j233ffbc-bd35-49b1-934f-51e083106f6d": "value" }, "requested_attributes": { "6253ffbb-bd35-49b3-934f-46e083106f6c": { "cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e", "revealed": true } }, "requested_predicates": { "bfc8a97d-60d3-4f21-b998-85eeabe5c8c0": { "cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e" } } }
Returns
A tuple (updated presentation exchange record, presentation message)
Expand source code
async def create_presentation( self, presentation_exchange_record: V10PresentationExchange, requested_credentials: dict, comment: str = None, ): """ Create a presentation. Args: presentation_exchange_record: Record to update requested_credentials: Indy formatted requested_credentials comment: optional human-readable comment Example `requested_credentials` format: :: { "self_attested_attributes": { "j233ffbc-bd35-49b1-934f-51e083106f6d": "value" }, "requested_attributes": { "6253ffbb-bd35-49b3-934f-46e083106f6c": { "cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e", "revealed": true } }, "requested_predicates": { "bfc8a97d-60d3-4f21-b998-85eeabe5c8c0": { "cred_id": "5bfa40b7-062b-4ae0-a251-a86c87922c0e" } } } Returns: A tuple (updated presentation exchange record, presentation message) """ # Get all credentials for this presentation holder: BaseHolder = await self.context.inject(BaseHolder) credentials = {} # extract credential ids and non_revoked requested_referents = {} presentation_request = presentation_exchange_record.presentation_request attr_creds = requested_credentials.get("requested_attributes", {}) req_attrs = presentation_request.get("requested_attributes", {}) for referent in attr_creds: requested_referents[referent] = {"cred_id": attr_creds[referent]["cred_id"]} if referent in req_attrs and "non_revoked" in req_attrs[referent]: requested_referents[referent]["non_revoked"] = req_attrs[referent][ "non_revoked" ] preds_creds = requested_credentials.get("requested_predicates", {}) req_preds = presentation_request.get("requested_predicates", {}) for referent in preds_creds: requested_referents[referent] = { "cred_id": preds_creds[referent]["cred_id"] } if referent in req_preds and "non_revoked" in req_preds[referent]: requested_referents[referent]["non_revoked"] = req_preds[referent][ "non_revoked" ] # extract mapping of presentation referents to credential ids for referent in requested_referents: credential_id = requested_referents[referent]["cred_id"] if credential_id not in credentials: credentials[credential_id] = json.loads( await holder.get_credential(credential_id) ) # Get all schema, credential definition, and revocation registry in use ledger: BaseLedger = await self.context.inject(BaseLedger) schemas = {} credential_definitions = {} revocation_registries = {} async with ledger: for credential in credentials.values(): schema_id = credential["schema_id"] if schema_id not in schemas: schemas[schema_id] = await ledger.get_schema(schema_id) credential_definition_id = credential["cred_def_id"] if credential_definition_id not in credential_definitions: credential_definitions[ credential_definition_id ] = await ledger.get_credential_definition(credential_definition_id) if credential.get("rev_reg_id"): revocation_registry_id = credential["rev_reg_id"] if revocation_registry_id not in revocation_registries: revocation_registries[ revocation_registry_id ] = RevocationRegistry.from_definition( await ledger.get_revoc_reg_def(revocation_registry_id), True ) # Get delta with non-revocation interval defined in "non_revoked" # of the presentation request or attributes epoch_now = int(time.time()) non_revoc_interval = {"from": 0, "to": epoch_now} non_revoc_interval.update( presentation_exchange_record.presentation_request.get("non_revoked") or {} ) revoc_reg_deltas = {} async with ledger: for precis in requested_referents.values(): # cred_id, non-revoc interval credential_id = precis["cred_id"] if not credentials[credential_id].get("rev_reg_id"): continue if "timestamp" in precis: continue rev_reg_id = credentials[credential_id]["rev_reg_id"] referent_non_revoc_interval = precis.get( "non_revoked", non_revoc_interval ) if referent_non_revoc_interval: key = ( f"{rev_reg_id}_{referent_non_revoc_interval.get('from', 0)}_" f"{referent_non_revoc_interval.get('to', epoch_now)}" ) if key not in revoc_reg_deltas: (delta, delta_timestamp) = await ledger.get_revoc_reg_delta( rev_reg_id, referent_non_revoc_interval.get("from", 0), referent_non_revoc_interval.get("to", epoch_now), ) revoc_reg_deltas[key] = ( rev_reg_id, credential_id, delta, delta_timestamp, ) for stamp_me in requested_referents.values(): # often one cred satisfies many requested attrs/preds if stamp_me["cred_id"] == credential_id: stamp_me["timestamp"] = revoc_reg_deltas[key][3] # Get revocation states to prove non-revoked revocation_states = {} for ( rev_reg_id, credential_id, delta, delta_timestamp, ) in revoc_reg_deltas.values(): if rev_reg_id not in revocation_states: revocation_states[rev_reg_id] = {} rev_reg = revocation_registries[rev_reg_id] tails_local_path = await rev_reg.get_or_fetch_local_tails_path() try: revocation_states[rev_reg_id][delta_timestamp] = json.loads( await holder.create_revocation_state( credentials[credential_id]["cred_rev_id"], rev_reg.reg_def, delta, delta_timestamp, tails_local_path, ) ) except HolderError as e: LOGGER.error( f"Failed to create revocation state: {e.error_code}, {e.message}" ) raise e for (referent, precis) in requested_referents.items(): if "timestamp" not in precis: continue if referent in requested_credentials["requested_attributes"]: requested_credentials["requested_attributes"][referent][ "timestamp" ] = precis["timestamp"] if referent in requested_credentials["requested_predicates"]: requested_credentials["requested_predicates"][referent][ "timestamp" ] = precis["timestamp"] indy_proof_json = await holder.create_presentation( presentation_exchange_record.presentation_request, requested_credentials, schemas, credential_definitions, revocation_states, ) indy_proof = json.loads(indy_proof_json) presentation_message = Presentation( comment=comment, presentations_attach=[ AttachDecorator.from_indy_dict( indy_dict=indy_proof, ident=ATTACH_DECO_IDS[PRESENTATION] ) ], ) presentation_message._thread = {"thid": presentation_exchange_record.thread_id} presentation_message.assign_trace_decorator( self.context.settings, presentation_exchange_record.trace ) # save presentation exchange state presentation_exchange_record.state = ( V10PresentationExchange.STATE_PRESENTATION_SENT ) presentation_exchange_record.presentation = indy_proof await presentation_exchange_record.save( self.context, reason="create presentation" ) return presentation_exchange_record, presentation_message
async def receive_presentation(self)
-
Receive a presentation, from message in context on manager creation.
Returns
presentation exchange record, retrieved and updated
Expand source code
async def receive_presentation(self): """ Receive a presentation, from message in context on manager creation. Returns: presentation exchange record, retrieved and updated """ presentation = self.context.message.indy_proof() thread_id = self.context.message._thread_id connection_id_filter = ( {"connection_id": self.context.connection_record.connection_id} if self.context.connection_record is not None else None ) ( presentation_exchange_record ) = await V10PresentationExchange.retrieve_by_tag_filter( self.context, {"thread_id": thread_id}, connection_id_filter ) # Check for bait-and-switch in presented attribute values vs. proposal if presentation_exchange_record.presentation_proposal_dict: exchange_pres_proposal = PresentationProposal.deserialize( presentation_exchange_record.presentation_proposal_dict ) presentation_preview = exchange_pres_proposal.presentation_proposal proof_req = presentation_exchange_record.presentation_request for (reft, attr_spec) in presentation["requested_proof"][ "revealed_attrs" ].items(): name = proof_req["requested_attributes"][reft]["name"] value = attr_spec["raw"] if not presentation_preview.has_attr_spec( cred_def_id=presentation["identifiers"][ attr_spec["sub_proof_index"] ]["cred_def_id"], name=name, value=value, ): raise PresentationManagerError( f"Presentation {name}={value} mismatches proposal value" ) presentation_exchange_record.presentation = presentation presentation_exchange_record.state = ( V10PresentationExchange.STATE_PRESENTATION_RECEIVED ) await presentation_exchange_record.save( self.context, reason="receive presentation" ) return presentation_exchange_record
async def receive_presentation_ack(self)
-
Receive a presentation ack, from message in context on manager creation.
Returns
presentation exchange record, retrieved and updated
Expand source code
async def receive_presentation_ack(self): """ Receive a presentation ack, from message in context on manager creation. Returns: presentation exchange record, retrieved and updated """ ( presentation_exchange_record ) = await V10PresentationExchange.retrieve_by_tag_filter( self.context, {"thread_id": self.context.message._thread_id}, {"connection_id": self.context.connection_record.connection_id}, ) presentation_exchange_record.state = ( V10PresentationExchange.STATE_PRESENTATION_ACKED ) await presentation_exchange_record.save( self.context, reason="receive presentation ack" ) return presentation_exchange_record
async def receive_proposal(self)
-
Receive a presentation proposal from message in context on manager creation.
Returns
Presentation exchange record, created
Expand source code
async def receive_proposal(self): """ Receive a presentation proposal from message in context on manager creation. Returns: Presentation exchange record, created """ presentation_proposal_message = self.context.message presentation_exchange_record = V10PresentationExchange( connection_id=self.context.connection_record.connection_id, thread_id=presentation_proposal_message._thread_id, initiator=V10PresentationExchange.INITIATOR_EXTERNAL, role=V10PresentationExchange.ROLE_VERIFIER, state=V10PresentationExchange.STATE_PROPOSAL_RECEIVED, presentation_proposal_dict=presentation_proposal_message.serialize(), trace=(presentation_proposal_message._trace is not None), ) await presentation_exchange_record.save( self.context, reason="receive presentation request" ) return presentation_exchange_record
async def receive_request(self, presentation_exchange_record: V10PresentationExchange)
-
Receive a presentation request.
Args
presentation_exchange_record
- presentation exchange record with request to receive
Returns
The presentation_exchange_record, updated
Expand source code
async def receive_request( self, presentation_exchange_record: V10PresentationExchange ): """ Receive a presentation request. Args: presentation_exchange_record: presentation exchange record with request to receive Returns: The presentation_exchange_record, updated """ presentation_exchange_record.state = ( V10PresentationExchange.STATE_REQUEST_RECEIVED ) await presentation_exchange_record.save( self.context, reason="receive presentation request" ) return presentation_exchange_record
async def send_presentation_ack(self, presentation_exchange_record: V10PresentationExchange)
-
Send acknowledgement of presentation receipt.
Args
presentation_exchange_record
- presentation exchange record with thread id
Expand source code
async def send_presentation_ack( self, presentation_exchange_record: V10PresentationExchange ): """ Send acknowledgement of presentation receipt. Args: presentation_exchange_record: presentation exchange record with thread id """ responder = await self.context.inject(BaseResponder, required=False) if responder: presentation_ack_message = PresentationAck() presentation_ack_message._thread = { "thid": presentation_exchange_record.thread_id } presentation_ack_message.assign_trace_decorator( self.context.settings, presentation_exchange_record.trace ) await responder.send_reply( presentation_ack_message, connection_id=presentation_exchange_record.connection_id, ) else: LOGGER.warning( "Configuration has no BaseResponder: cannot ack presentation on %s", presentation_exchange_record.thread_id, )
async def verify_presentation(self, presentation_exchange_record: V10PresentationExchange)
-
Verify a presentation.
Args
presentation_exchange_record
- presentation exchange record with presentation request and presentation to verify
Returns
presentation record, updated
Expand source code
async def verify_presentation( self, presentation_exchange_record: V10PresentationExchange ): """ Verify a presentation. Args: presentation_exchange_record: presentation exchange record with presentation request and presentation to verify Returns: presentation record, updated """ indy_proof_request = presentation_exchange_record.presentation_request indy_proof = presentation_exchange_record.presentation schema_ids = [] credential_definition_ids = [] schemas = {} credential_definitions = {} rev_reg_defs = {} rev_reg_entries = {} identifiers = indy_proof["identifiers"] ledger: BaseLedger = await self.context.inject(BaseLedger) async with ledger: for identifier in identifiers: schema_ids.append(identifier["schema_id"]) credential_definition_ids.append(identifier["cred_def_id"]) # Build schemas for anoncreds if identifier["schema_id"] not in schemas: schemas[identifier["schema_id"]] = await ledger.get_schema( identifier["schema_id"] ) if identifier["cred_def_id"] not in credential_definitions: credential_definitions[ identifier["cred_def_id"] ] = await ledger.get_credential_definition( identifier["cred_def_id"] ) if identifier.get("rev_reg_id"): if identifier["rev_reg_id"] not in rev_reg_defs: rev_reg_defs[ identifier["rev_reg_id"] ] = await ledger.get_revoc_reg_def(identifier["rev_reg_id"]) if identifier.get("timestamp"): rev_reg_entries.setdefault(identifier["rev_reg_id"], {}) if ( identifier["timestamp"] not in rev_reg_entries[identifier["rev_reg_id"]] ): ( found_rev_reg_entry, _found_timestamp, ) = await ledger.get_revoc_reg_entry( identifier["rev_reg_id"], identifier["timestamp"] ) rev_reg_entries[identifier["rev_reg_id"]][ identifier["timestamp"] ] = found_rev_reg_entry verifier: BaseVerifier = await self.context.inject(BaseVerifier) presentation_exchange_record.verified = json.dumps( # tag: needs string value await verifier.verify_presentation( indy_proof_request, indy_proof, schemas, credential_definitions, rev_reg_defs, rev_reg_entries, ) ) presentation_exchange_record.state = V10PresentationExchange.STATE_VERIFIED await presentation_exchange_record.save( self.context, reason="verify presentation" ) await self.send_presentation_ack(presentation_exchange_record) return presentation_exchange_record
class PresentationManagerError (*args, error_code: str = None, **kwargs)
-
Presentation error.
Initialize a BaseError instance.
Expand source code
class PresentationManagerError(BaseError): """Presentation error."""
Ancestors
- aries_cloudagent.core.error.BaseError
- builtins.Exception
- builtins.BaseException