From 50a731e90bf461c4a81b8cec189b9027102f12c5 Mon Sep 17 00:00:00 2001 From: Andrew Whitehead Date: Wed, 15 Apr 2020 13:36:11 -0700 Subject: [PATCH] remove 0.1 credentials and presentations protocols Signed-off-by: Andrew Whitehead --- .../protocols/credentials/__init__.py | 0 .../credentials/handlers/__init__.py | 0 .../handlers/credential_issue_handler.py | 46 -- .../handlers/credential_offer_handler.py | 45 -- .../handlers/credential_request_handler.py | 48 -- .../handlers/credential_stored_handler.py | 34 - .../protocols/credentials/manager.py | 383 ----------- .../protocols/credentials/message_types.py | 40 -- .../credentials/messages/__init__.py | 0 .../credentials/messages/credential_issue.py | 43 -- .../credentials/messages/credential_offer.py | 55 -- .../messages/credential_request.py | 48 -- .../credentials/messages/credential_stored.py | 33 - .../credentials/messages/tests/__init__.py | 0 .../messages/tests/test_credential.py | 64 -- .../messages/tests/test_credential_offer.py | 63 -- .../messages/tests/test_credential_request.py | 87 --- .../protocols/credentials/models/__init__.py | 0 .../credentials/models/credential_exchange.py | 167 ----- .../protocols/credentials/routes.py | 631 ------------------ .../protocols/credentials/tests/__init__.py | 0 .../credentials/tests/test_routes.py | 595 ----------------- .../protocols/presentations/__init__.py | 0 .../presentations/handlers/__init__.py | 0 .../credential_presentation_handler.py | 37 - .../handlers/presentation_request_handler.py | 100 --- .../protocols/presentations/manager.py | 285 -------- .../protocols/presentations/message_types.py | 28 - .../presentations/messages/__init__.py | 0 .../messages/credential_presentation.py | 48 -- .../messages/presentation_request.py | 46 -- .../presentations/models/__init__.py | 0 .../models/presentation_exchange.py | 94 --- .../protocols/presentations/routes.py | 426 ------------ 34 files changed, 3446 deletions(-) delete mode 100644 aries_cloudagent/protocols/credentials/__init__.py delete mode 100644 aries_cloudagent/protocols/credentials/handlers/__init__.py delete mode 100644 aries_cloudagent/protocols/credentials/handlers/credential_issue_handler.py delete mode 100644 aries_cloudagent/protocols/credentials/handlers/credential_offer_handler.py delete mode 100644 aries_cloudagent/protocols/credentials/handlers/credential_request_handler.py delete mode 100644 aries_cloudagent/protocols/credentials/handlers/credential_stored_handler.py delete mode 100644 aries_cloudagent/protocols/credentials/manager.py delete mode 100644 aries_cloudagent/protocols/credentials/message_types.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/__init__.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/credential_issue.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/credential_offer.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/credential_request.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/credential_stored.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/tests/__init__.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/tests/test_credential.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/tests/test_credential_offer.py delete mode 100644 aries_cloudagent/protocols/credentials/messages/tests/test_credential_request.py delete mode 100644 aries_cloudagent/protocols/credentials/models/__init__.py delete mode 100644 aries_cloudagent/protocols/credentials/models/credential_exchange.py delete mode 100644 aries_cloudagent/protocols/credentials/routes.py delete mode 100644 aries_cloudagent/protocols/credentials/tests/__init__.py delete mode 100644 aries_cloudagent/protocols/credentials/tests/test_routes.py delete mode 100644 aries_cloudagent/protocols/presentations/__init__.py delete mode 100644 aries_cloudagent/protocols/presentations/handlers/__init__.py delete mode 100644 aries_cloudagent/protocols/presentations/handlers/credential_presentation_handler.py delete mode 100644 aries_cloudagent/protocols/presentations/handlers/presentation_request_handler.py delete mode 100644 aries_cloudagent/protocols/presentations/manager.py delete mode 100644 aries_cloudagent/protocols/presentations/message_types.py delete mode 100644 aries_cloudagent/protocols/presentations/messages/__init__.py delete mode 100644 aries_cloudagent/protocols/presentations/messages/credential_presentation.py delete mode 100644 aries_cloudagent/protocols/presentations/messages/presentation_request.py delete mode 100644 aries_cloudagent/protocols/presentations/models/__init__.py delete mode 100644 aries_cloudagent/protocols/presentations/models/presentation_exchange.py delete mode 100644 aries_cloudagent/protocols/presentations/routes.py diff --git a/aries_cloudagent/protocols/credentials/__init__.py b/aries_cloudagent/protocols/credentials/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/credentials/handlers/__init__.py b/aries_cloudagent/protocols/credentials/handlers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/credentials/handlers/credential_issue_handler.py b/aries_cloudagent/protocols/credentials/handlers/credential_issue_handler.py deleted file mode 100644 index 2adb88be7c..0000000000 --- a/aries_cloudagent/protocols/credentials/handlers/credential_issue_handler.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Basic message handler.""" - -from ....messaging.base_handler import ( - BaseHandler, - BaseResponder, - HandlerException, - RequestContext, -) - -from ..manager import CredentialManager -from ..messages.credential_issue import CredentialIssue - - -class CredentialIssueHandler(BaseHandler): - """Message handler class for credential offers.""" - - async def handle(self, context: RequestContext, responder: BaseResponder): - """ - Message handler logic for credential offers. - - Args: - context: request context - responder: responder callback - """ - self._logger.debug(f"CredentialHandler called with context {context}") - assert isinstance(context.message, CredentialIssue) - self._logger.info(f"Received credential: {context.message.issue}") - - if not context.connection_ready: - raise HandlerException("No connection established for credential request") - - credential_manager = CredentialManager(context) - - credential_exchange_record = await credential_manager.receive_credential( - context.message - ) - - # Automatically move to next state if flag is set - if context.settings.get("debug.auto_store_credential"): - ( - credential_exchange_record, - credential_stored_message, - ) = await credential_manager.store_credential(credential_exchange_record) - - # Notify issuer that credential was stored - await responder.send_reply(credential_stored_message) diff --git a/aries_cloudagent/protocols/credentials/handlers/credential_offer_handler.py b/aries_cloudagent/protocols/credentials/handlers/credential_offer_handler.py deleted file mode 100644 index 18e259fb9f..0000000000 --- a/aries_cloudagent/protocols/credentials/handlers/credential_offer_handler.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Basic message handler.""" - -from ....messaging.base_handler import ( - BaseHandler, - BaseResponder, - HandlerException, - RequestContext, -) - -from ..manager import CredentialManager -from ..messages.credential_offer import CredentialOffer - - -class CredentialOfferHandler(BaseHandler): - """Message handler class for credential offers.""" - - async def handle(self, context: RequestContext, responder: BaseResponder): - """ - Message handler logic for credential offers. - - Args: - context: request context - responder: responder callback - """ - self._logger.debug(f"CredentialOfferHandler called with context {context}") - - assert isinstance(context.message, CredentialOffer) - - self._logger.info("Received credential offer: %s", context.message.offer_json) - - if not context.connection_ready: - raise HandlerException("No connection established for credential offer") - - credential_manager = CredentialManager(context) - - credential_exchange_record = await credential_manager.receive_offer( - context.message, context.connection_record.connection_id - ) - - # If auto respond is turned on, automatically reply with credential request - if context.settings.get("debug.auto_respond_credential_offer"): - (_, credential_request_message) = await credential_manager.create_request( - credential_exchange_record, context.connection_record - ) - await responder.send_reply(credential_request_message) diff --git a/aries_cloudagent/protocols/credentials/handlers/credential_request_handler.py b/aries_cloudagent/protocols/credentials/handlers/credential_request_handler.py deleted file mode 100644 index 952888e45d..0000000000 --- a/aries_cloudagent/protocols/credentials/handlers/credential_request_handler.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Credential request handler.""" - -from ....messaging.base_handler import ( - BaseHandler, - BaseResponder, - HandlerException, - RequestContext, -) - -from ..manager import CredentialManager -from ..messages.credential_request import CredentialRequest - - -class CredentialRequestHandler(BaseHandler): - """Message handler class for credential requests.""" - - async def handle(self, context: RequestContext, responder: BaseResponder): - """ - Message handler logic for credential requests. - - Args: - context: request context - responder: responder callback - """ - self._logger.debug(f"CredentialRequestHandler called with context {context}") - - assert isinstance(context.message, CredentialRequest) - - self._logger.info( - "Received credential request: %s", context.message.serialize(as_string=True) - ) - - if not context.connection_ready: - raise HandlerException("No connection established for credential request") - - credential_manager = CredentialManager(context) - credential_exchange_record = await credential_manager.receive_request( - context.message - ) - - # If auto_issue is enabled, respond immediately - if credential_exchange_record.auto_issue: - ( - credential_exchange_record, - credential_issue_message, - ) = await credential_manager.issue_credential(credential_exchange_record) - - await responder.send_reply(credential_issue_message) diff --git a/aries_cloudagent/protocols/credentials/handlers/credential_stored_handler.py b/aries_cloudagent/protocols/credentials/handlers/credential_stored_handler.py deleted file mode 100644 index 4ccd793ac5..0000000000 --- a/aries_cloudagent/protocols/credentials/handlers/credential_stored_handler.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Credential stored message handler.""" - -from ....messaging.base_handler import ( - BaseHandler, - BaseResponder, - HandlerException, - RequestContext, -) - -from ..manager import CredentialManager -from ..messages.credential_stored import CredentialStored - - -class CredentialStoredHandler(BaseHandler): - """Message handler class for credential offers.""" - - async def handle(self, context: RequestContext, responder: BaseResponder): - """ - Message handler logic for credential stored messages. - - Args: - context: request context - responder: responder callback - """ - self._logger.debug(f"CredentialStoredHandler called with context {context}") - assert isinstance(context.message, CredentialStored) - self._logger.info(f"Received credential stored message: {context.message}") - - if not context.connection_ready: - raise HandlerException("No connection established for credential_exchange") - - credential_manager = CredentialManager(context) - - await credential_manager.credential_stored(context.message) diff --git a/aries_cloudagent/protocols/credentials/manager.py b/aries_cloudagent/protocols/credentials/manager.py deleted file mode 100644 index 77f9656f28..0000000000 --- a/aries_cloudagent/protocols/credentials/manager.py +++ /dev/null @@ -1,383 +0,0 @@ -"""Classes to manage credentials.""" - -import json -import logging - -from ...config.injection_context import InjectionContext -from ...connections.models.connection_record import ConnectionRecord -from ...core.error import BaseError -from ...holder.base import BaseHolder -from ...issuer.base import BaseIssuer -from ...ledger.base import BaseLedger - -from .messages.credential_issue import CredentialIssue -from .messages.credential_stored import CredentialStored -from .messages.credential_request import CredentialRequest -from .messages.credential_offer import CredentialOffer -from .models.credential_exchange import CredentialExchange - - -class CredentialManagerError(BaseError): - """Credential error.""" - - -class CredentialManager: - """Class for managing credentials.""" - - def __init__(self, context: InjectionContext): - """ - Initialize a CredentialManager. - - Args: - context: The context for this credential - """ - self._context = context - self._logger = logging.getLogger(__name__) - - @property - def context(self) -> InjectionContext: - """ - Accessor for the current injection context. - - Returns: - The injection context for this credential manager - - """ - return self._context - - async def create_offer( - self, - credential_definition_id: str, - connection_id: str, - auto_issue: bool = None, - credential_values: dict = None, - ): - """ - Create a new credential exchange representing an offer. - - Args: - credential_definition_id: Credential definition id for offer - connection_id: Connection to create offer for - - Returns: - A new credential exchange record - - """ - - cache_key = f"credential_offer::{credential_definition_id}" - cached = await CredentialExchange.get_cached_key(self.context, cache_key) - if cached: - credential_offer = cached["offer"] - else: - issuer: BaseIssuer = await self.context.inject(BaseIssuer) - credential_offer_json = await issuer.create_credential_offer( - credential_definition_id - ) - credential_offer = json.loads(credential_offer_json) - await CredentialExchange.set_cached_key( - self.context, cache_key, {"offer": credential_offer}, 3600 - ) - - credential_offer_message = CredentialOffer( - offer_json=json.dumps(credential_offer) - ) - - credential_exchange = CredentialExchange( - auto_issue=auto_issue, - connection_id=connection_id, - initiator=CredentialExchange.INITIATOR_SELF, - state=CredentialExchange.STATE_OFFER_SENT, - credential_definition_id=credential_definition_id, - schema_id=credential_offer["schema_id"], - credential_offer=credential_offer, - credential_values=credential_values, - thread_id=credential_offer_message._thread_id, - ) - await credential_exchange.save(self.context, reason="Create credential offer") - return credential_exchange, credential_offer_message - - async def receive_offer( - self, credential_offer_message: CredentialOffer, connection_id: str - ): - """ - Receive a credential offer. - - Args: - credential_offer: Credential offer to receive - connection_id: Connection to receive offer on - - Returns: - The credential_exchange_record - - """ - - credential_offer = json.loads(credential_offer_message.offer_json) - - credential_exchange = CredentialExchange( - connection_id=connection_id, - thread_id=credential_offer_message._thread_id, - initiator=CredentialExchange.INITIATOR_EXTERNAL, - state=CredentialExchange.STATE_OFFER_RECEIVED, - credential_definition_id=credential_offer["cred_def_id"], - schema_id=credential_offer["schema_id"], - credential_offer=credential_offer, - ) - await credential_exchange.save(self.context, reason="Receive credential offer") - - return credential_exchange - - async def create_request( - self, - credential_exchange_record: CredentialExchange, - connection_record: ConnectionRecord, - ): - """ - Create a credential request. - - Args: - credential_exchange_record: Credential exchange to create request for - connection_record: Connection to create the request for - - Return: - A tuple (credential_exchange_record, credential_request_message) - - """ - - credential_definition_id = credential_exchange_record.credential_definition_id - credential_offer = credential_exchange_record.credential_offer - - did = connection_record.my_did - - if credential_exchange_record.credential_request: - self._logger.warning( - "create_request called multiple times for credential exchange: %s", - credential_exchange_record.credential_exchange_id, - ) - else: - nonce = credential_offer["nonce"] - cache_key = ( - f"credential_request::{credential_definition_id}::{did}::{nonce}" - ) - cached = await CredentialExchange.get_cached_key(self.context, cache_key) - if cached: - ( - credential_exchange_record.credential_request, - credential_exchange_record.credential_request_metadata, - ) = (cached["request"], cached["metadata"]) - else: - ledger: BaseLedger = await self.context.inject(BaseLedger) - async with ledger: - credential_definition = await ledger.get_credential_definition( - credential_definition_id - ) - - holder: BaseHolder = await self.context.inject(BaseHolder) - ( - cred_req_json, - cred_req_meta_json, - ) = await holder.create_credential_request( - credential_offer, credential_definition, did - ) - ( - credential_exchange_record.credential_request, - credential_exchange_record.credential_request_metadata, - ) = (json.loads(cred_req_json), json.loads(cred_req_meta_json)) - - await CredentialExchange.set_cached_key( - self.context, - cache_key, - { - "request": credential_exchange_record.credential_request, - "metadata": ( - credential_exchange_record.credential_request_metadata - ), - }, - 7200, - ) - - credential_request_message = CredentialRequest( - request=json.dumps(credential_exchange_record.credential_request) - ) - - credential_request_message.assign_thread_id( - credential_exchange_record.thread_id - ) - - credential_exchange_record.state = CredentialExchange.STATE_REQUEST_SENT - await credential_exchange_record.save( - self.context, reason="Create credential request" - ) - - return credential_exchange_record, credential_request_message - - async def receive_request(self, credential_request_message: CredentialRequest): - """ - Receive a credential request. - - Args: - credential_request_message: Credential request to receive - - """ - - credential_request = json.loads(credential_request_message.request) - - ( - credential_exchange_record - ) = await CredentialExchange.retrieve_by_thread_and_initiator( - self.context, credential_request_message._thread_id, "self" - ) - credential_exchange_record.credential_request = credential_request - credential_exchange_record.state = CredentialExchange.STATE_REQUEST_RECEIVED - await credential_exchange_record.save( - self.context, reason="Receive credential request" - ) - - return credential_exchange_record - - async def issue_credential(self, credential_exchange_record: CredentialExchange): - """ - Issue a credential. - - Args: - credential_exchange_record: The credential exchange we are issuing a - credential for - - Returns: - Tuple: (Updated credential exchange record, credential message obj) - - """ - - schema_id = credential_exchange_record.schema_id - - if credential_exchange_record.credential: - self._logger.warning( - "issue_credential called multiple times for credential exchange: %s", - credential_exchange_record.credential_exchange_id, - ) - else: - credential_offer = credential_exchange_record.credential_offer - credential_request = credential_exchange_record.credential_request - credential_values = credential_exchange_record.credential_values - - ledger: BaseLedger = await self.context.inject(BaseLedger) - async with ledger: - schema = await ledger.get_schema(schema_id) - - issuer: BaseIssuer = await self.context.inject(BaseIssuer) - ( - credential_json, - credential_exchange_record.revocation_id, - ) = await issuer.create_credential( - schema, credential_offer, credential_request, credential_values - ) - credential_exchange_record.credential = json.loads(credential_json) - - credential_exchange_record.state = CredentialExchange.STATE_ISSUED - - credential_message = CredentialIssue( - issue=json.dumps(credential_exchange_record.credential) - ) - - if credential_exchange_record.thread_id: - credential_message.assign_thread_id( - thid=credential_exchange_record.thread_id - ) - else: - raise CredentialManagerError( - "The credential exchange object must have a " - + "thread id in order to issue a credential." - ) - - await credential_exchange_record.save(self.context, reason="Issue credential") - return credential_exchange_record, credential_message - - async def receive_credential(self, credential_message: CredentialIssue): - """ - Receive a credential a credential from an issuer. - - Hold in storage to be potentially processed by controller before storing. - - Args: - credential_message: credential to store - - """ - raw_credential = json.loads(credential_message.issue) - - ( - credential_exchange_record - ) = await CredentialExchange.retrieve_by_thread_and_initiator( - self.context, credential_message._thread_id, "external" - ) - - credential_exchange_record.raw_credential = raw_credential - credential_exchange_record.state = CredentialExchange.STATE_CREDENTIAL_RECEIVED - - await credential_exchange_record.save(self.context, reason="Receive credential") - - return credential_exchange_record - - async def store_credential( - self, credential_exchange_record: CredentialExchange, credential_id: str = None - ): - """ - Store a credential in the wallet. - - Args: - credential_message: credential to store - credential_id: string to use as id for record in wallet - - """ - - raw_credential = credential_exchange_record.raw_credential - - ledger: BaseLedger = await self.context.inject(BaseLedger) - async with ledger: - credential_definition = await ledger.get_credential_definition( - raw_credential["cred_def_id"] - ) - - holder: BaseHolder = await self.context.inject(BaseHolder) - credential_id = await holder.store_credential( - credential_definition, - raw_credential, - credential_exchange_record.credential_request_metadata, - credential_id=credential_id, - ) - - credential_json = await holder.get_credential(credential_id) - - credential_exchange_record.state = CredentialExchange.STATE_STORED - credential_exchange_record.credential_id = credential_id - credential_exchange_record.credential = json.loads(credential_json) - - await credential_exchange_record.save(self.context, reason="Store credential") - - credential_stored_message = CredentialStored() - credential_stored_message.assign_thread_id(credential_exchange_record.thread_id) - - # We're done so delete the exchange record - await credential_exchange_record.delete_record(self.context) - - return credential_exchange_record, credential_stored_message - - async def credential_stored(self, credential_stored_message: CredentialStored): - """ - Receive confirmation that holder stored credential. - - Args: - credential_message: credential to store - - """ - - # Get current exchange record by thread id - ( - credential_exchange_record - ) = await CredentialExchange.retrieve_by_thread_and_initiator( - self.context, credential_stored_message._thread_id, "self" - ) - - credential_exchange_record.state = CredentialExchange.STATE_STORED - await credential_exchange_record.save(self.context, reason="Credential stored") - - # We're done so delete the exchange record - await credential_exchange_record.delete_record(self.context) diff --git a/aries_cloudagent/protocols/credentials/message_types.py b/aries_cloudagent/protocols/credentials/message_types.py deleted file mode 100644 index 13c285cdff..0000000000 --- a/aries_cloudagent/protocols/credentials/message_types.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Message type identifiers for credentials.""" - -PROTOCOL_URI = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/0.1" - -CREDENTIAL_OFFER = f"{PROTOCOL_URI}/credential-offer" -CREDENTIAL_REQUEST = f"{PROTOCOL_URI}/credential-request" -CREDENTIAL_ISSUE = f"{PROTOCOL_URI}/credential-issue" -CREDENTIAL_STORED = f"{PROTOCOL_URI}/credential-stored" - -NEW_PROTOCOL_URI = "https://didcomm.org/credential-issuance/0.1" - -NEW_CREDENTIAL_OFFER = f"{NEW_PROTOCOL_URI}/credential-offer" -NEW_CREDENTIAL_REQUEST = f"{NEW_PROTOCOL_URI}/credential-request" -NEW_CREDENTIAL_ISSUE = f"{NEW_PROTOCOL_URI}/credential-issue" -NEW_CREDENTIAL_STORED = f"{NEW_PROTOCOL_URI}/credential-stored" - -PROTOCOL_PACKAGE = "aries_cloudagent.protocols.credentials" - -MESSAGE_TYPES = { - CREDENTIAL_OFFER: f"{PROTOCOL_PACKAGE}.messages.credential_offer.CredentialOffer", - CREDENTIAL_REQUEST: ( - f"{PROTOCOL_PACKAGE}.messages.credential_request.CredentialRequest" - ), - CREDENTIAL_ISSUE: f"{PROTOCOL_PACKAGE}.messages.credential_issue.CredentialIssue", - CREDENTIAL_STORED: ( - f"{PROTOCOL_PACKAGE}.messages.credential_stored.CredentialStored" - ), - NEW_CREDENTIAL_OFFER: ( - f"{PROTOCOL_PACKAGE}.messages.credential_offer.CredentialOffer" - ), - NEW_CREDENTIAL_REQUEST: ( - f"{PROTOCOL_PACKAGE}.messages.credential_request.CredentialRequest" - ), - NEW_CREDENTIAL_ISSUE: ( - f"{PROTOCOL_PACKAGE}.messages.credential_issue.CredentialIssue" - ), - NEW_CREDENTIAL_STORED: ( - f"{PROTOCOL_PACKAGE}.messages.credential_stored.CredentialStored" - ), -} diff --git a/aries_cloudagent/protocols/credentials/messages/__init__.py b/aries_cloudagent/protocols/credentials/messages/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/credentials/messages/credential_issue.py b/aries_cloudagent/protocols/credentials/messages/credential_issue.py deleted file mode 100644 index d3b6675df2..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/credential_issue.py +++ /dev/null @@ -1,43 +0,0 @@ -"""A credential content message.""" - -from marshmallow import fields - -from ....messaging.agent_message import AgentMessage, AgentMessageSchema - -from ..message_types import CREDENTIAL_ISSUE, PROTOCOL_PACKAGE - -HANDLER_CLASS = ( - f"{PROTOCOL_PACKAGE}.handlers.credential_issue_handler.CredentialIssueHandler" -) - - -class CredentialIssue(AgentMessage): - """Class representing a credential.""" - - class Meta: - """Credential metadata.""" - - handler_class = HANDLER_CLASS - schema_class = "CredentialIssueSchema" - message_type = CREDENTIAL_ISSUE - - def __init__(self, *, issue: str = None, **kwargs): - """ - Initialize credential object. - - Args: - issue (str): Credential issue json string - """ - super(CredentialIssue, self).__init__(**kwargs) - self.issue = issue - - -class CredentialIssueSchema(AgentMessageSchema): - """Credential schema.""" - - class Meta: - """Credential schema metadata.""" - - model_class = CredentialIssue - - issue = fields.Str(required=True) diff --git a/aries_cloudagent/protocols/credentials/messages/credential_offer.py b/aries_cloudagent/protocols/credentials/messages/credential_offer.py deleted file mode 100644 index a546485757..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/credential_offer.py +++ /dev/null @@ -1,55 +0,0 @@ -"""A credential offer content message.""" - -from marshmallow import fields - -from ....messaging.agent_message import AgentMessage, AgentMessageSchema - -from ..message_types import CREDENTIAL_OFFER, PROTOCOL_PACKAGE - - -HANDLER_CLASS = ( - f"{PROTOCOL_PACKAGE}.handlers.credential_offer_handler.CredentialOfferHandler" -) - - -class CredentialOffer(AgentMessage): - """Class representing a credential offer.""" - - class Meta: - """CredentialOffer metadata.""" - - handler_class = HANDLER_CLASS - schema_class = "CredentialOfferSchema" - message_type = CREDENTIAL_OFFER - - def __init__( - self, - *, - offer_json: str = None, - credential_preview: dict = None, - comment: str = None, - **kwargs, - ): - """ - Initialize credential offer object. - - Args: - offer_json: Credential offer json - """ - super(CredentialOffer, self).__init__(**kwargs) - self.offer_json = offer_json - self.credential_preview = credential_preview - self.comment = comment - - -class CredentialOfferSchema(AgentMessageSchema): - """Credential offer schema.""" - - class Meta: - """Credential offer schema metadata.""" - - model_class = CredentialOffer - - offer_json = fields.Str(required=True) - credential_preview = fields.Dict(required=False) - comment = fields.Str(required=False) diff --git a/aries_cloudagent/protocols/credentials/messages/credential_request.py b/aries_cloudagent/protocols/credentials/messages/credential_request.py deleted file mode 100644 index 37e508c44c..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/credential_request.py +++ /dev/null @@ -1,48 +0,0 @@ -"""A credential request content message.""" - -from marshmallow import fields - -from ....messaging.agent_message import AgentMessage, AgentMessageSchema - -from ..message_types import CREDENTIAL_REQUEST, PROTOCOL_PACKAGE - -HANDLER_CLASS = ( - f"{PROTOCOL_PACKAGE}.handlers." - "credential_request_handler.CredentialRequestHandler" -) - - -class CredentialRequest(AgentMessage): - """Class representing a credential request.""" - - class Meta: - """CredentialRequest metadata.""" - - handler_class = HANDLER_CLASS - schema_class = "CredentialRequestSchema" - message_type = CREDENTIAL_REQUEST - - def __init__(self, *, request: str = None, comment: str = None, **kwargs): - """ - Initialize credential request object. - - Args: - offer_json: Credential offer json string - credential_request_json: Credential request json string - - """ - super(CredentialRequest, self).__init__(**kwargs) - self.request = request - self.comment = comment - - -class CredentialRequestSchema(AgentMessageSchema): - """Credential request schema.""" - - class Meta: - """Credential request schema metadata.""" - - model_class = CredentialRequest - - request = fields.Str(required=True) - comment = fields.Str(required=False) diff --git a/aries_cloudagent/protocols/credentials/messages/credential_stored.py b/aries_cloudagent/protocols/credentials/messages/credential_stored.py deleted file mode 100644 index 6e047a10d8..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/credential_stored.py +++ /dev/null @@ -1,33 +0,0 @@ -"""A credential stored message.""" - -from ....messaging.agent_message import AgentMessage, AgentMessageSchema - -from ..message_types import CREDENTIAL_STORED, PROTOCOL_PACKAGE - -HANDLER_CLASS = ( - f"{PROTOCOL_PACKAGE}.handlers.credential_stored_handler.CredentialStoredHandler" -) - - -class CredentialStored(AgentMessage): - """Class representing a credential stored message.""" - - class Meta: - """Credential metadata.""" - - handler_class = HANDLER_CLASS - schema_class = "CredentialStoredSchema" - message_type = CREDENTIAL_STORED - - def __init__(self, **kwargs): - """Initialize credential object.""" - super(CredentialStored, self).__init__(**kwargs) - - -class CredentialStoredSchema(AgentMessageSchema): - """Credential stored schema.""" - - class Meta: - """Schema metadata.""" - - model_class = CredentialStored diff --git a/aries_cloudagent/protocols/credentials/messages/tests/__init__.py b/aries_cloudagent/protocols/credentials/messages/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/credentials/messages/tests/test_credential.py b/aries_cloudagent/protocols/credentials/messages/tests/test_credential.py deleted file mode 100644 index 90e7d05355..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/tests/test_credential.py +++ /dev/null @@ -1,64 +0,0 @@ -# from ..credential import Credential -# from ....message_types import MessageTypes -# -# from unittest import mock, TestCase -# -# -# class TestCredential(TestCase): -# credential_json = "credential_json" -# revocation_registry_id = "revocation_registry_id" -# -# def test_init(self): -# credential = Credential( -# credential_json=self.credential_json, -# revocation_registry_id=self.revocation_registry_id, -# ) -# assert credential.credential_json == self.credential_json -# assert credential.revocation_registry_id == self.revocation_registry_id -# -# def test_type(self): -# credential = Credential( -# credential_json=self.credential_json, -# revocation_registry_id=self.revocation_registry_id, -# ) -# -# assert credential._type == MessageTypes.CREDENTIAL.value -# -# @mock.patch( -# "aries_cloudagent.messaging.credentials.messages." -# + "credential.CredentialSchema.load" -# ) -# def test_deserialize(self, mock_credential_schema_load): -# obj = {"obj": "obj"} -# -# credential = Credential.deserialize(obj) -# mock_credential_schema_load.assert_called_once_with(obj) -# -# assert credential is mock_credential_schema_load.return_value -# -# @mock.patch( -# "aries_cloudagent.messaging.credentials.messages." -# + "credential.CredentialSchema.dump" -# ) -# def test_serialize(self, mock_credential_schema_dump): -# credential = Credential( -# credential_json=self.credential_json, -# revocation_registry_id=self.revocation_registry_id, -# ) -# -# credential_dict = credential.serialize() -# mock_credential_schema_dump.assert_called_once_with(credential) -# -# assert credential_dict is mock_credential_schema_dump.return_value -# -# -# class TestCredentialSchema(TestCase): -# credential = Credential( -# credential_json="credential_json", -# revocation_registry_id="revocation_registry_id", -# ) -# -# def test_make_model(self): -# data = self.credential.serialize() -# model_instance = Credential.deserialize(data) -# assert isinstance(model_instance, Credential) diff --git a/aries_cloudagent/protocols/credentials/messages/tests/test_credential_offer.py b/aries_cloudagent/protocols/credentials/messages/tests/test_credential_offer.py deleted file mode 100644 index aca73fb840..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/tests/test_credential_offer.py +++ /dev/null @@ -1,63 +0,0 @@ -# from ..credential_offer import CredentialOffer -# from ....message_types import MessageTypes -# -# from unittest import mock, TestCase -# -# -# class TestCredentialOffer(TestCase): -# """Credential offer tests""" -# -# offer_json = "offer_json" -# -# def test_init(self): -# """Test initializer""" -# credential_offer = CredentialOffer(offer_json=self.offer_json) -# assert credential_offer.offer_json == self.offer_json -# -# def test_type(self): -# """Test type""" -# credential_offer = CredentialOffer(offer_json=self.offer_json) -# -# assert credential_offer._type == MessageTypes.CREDENTIAL_OFFER.value -# -# @mock.patch( -# "aries_cloudagent.messaging.credentials.messages." -# + "credential_offer.CredentialOfferSchema.load" -# ) -# def test_deserialize(self, mock_credential_offer_schema_load): -# """ -# Test deserialize -# """ -# obj = {"obj": "obj"} -# -# credential_offer = CredentialOffer.deserialize(obj) -# mock_credential_offer_schema_load.assert_called_once_with(obj) -# -# assert credential_offer is mock_credential_offer_schema_load.return_value -# -# @mock.patch( -# "aries_cloudagent.messaging.credentials.messages." -# + "credential_offer.CredentialOfferSchema.dump" -# ) -# def test_serialize(self, mock_credential_offer_schema_dump): -# """ -# Test serialization. -# """ -# credential_offer = CredentialOffer(offer_json=self.offer_json) -# -# credential_offer_dict = credential_offer.serialize() -# mock_credential_offer_schema_dump.assert_called_once_with(credential_offer) -# -# assert credential_offer_dict is mock_credential_offer_schema_dump.return_value -# -# -# class TestCredentialOfferSchema(TestCase): -# """Test credential cred offer schema""" -# -# credential_offer = CredentialOffer(offer_json="offer_json") -# -# def test_make_model(self): -# """Test making model.""" -# data = self.credential_offer.serialize() -# model_instance = CredentialOffer.deserialize(data) -# assert isinstance(model_instance, CredentialOffer) diff --git a/aries_cloudagent/protocols/credentials/messages/tests/test_credential_request.py b/aries_cloudagent/protocols/credentials/messages/tests/test_credential_request.py deleted file mode 100644 index 38ffe60454..0000000000 --- a/aries_cloudagent/protocols/credentials/messages/tests/test_credential_request.py +++ /dev/null @@ -1,87 +0,0 @@ -# from ..credential_request import CredentialRequest -# from ....message_types import MessageTypes -# -# from unittest import mock, TestCase -# -# -# class TestCredentialRequest(TestCase): -# """Test credential request.""" -# -# offer_json = "offer_json" -# credential_request_json = "credential_request_json" -# credential_values_json = "credential_values_json" -# -# def test_init(self): -# """Test intializer.""" -# credential_request = CredentialRequest( -# offer_json=self.offer_json, -# credential_request_json=self.credential_request_json, -# credential_values_json=self.credential_values_json, -# ) -# assert credential_request.offer_json == self.offer_json -# assert ( -# credential_request.credential_request_json == self.credential_request_json -# ) -# assert credential_request.credential_values_json == self.credential_values_json -# -# def test_type(self): -# """Test type""" -# credential_request = CredentialRequest( -# offer_json=self.offer_json, -# credential_request_json=self.credential_request_json, -# credential_values_json=self.credential_values_json, -# ) -# -# assert credential_request._type == MessageTypes.CREDENTIAL_REQUEST.value -# -# @mock.patch( -# "aries_cloudagent.messaging.credentials.messages." -# + "credential_request.CredentialRequestSchema.load" -# ) -# def test_deserialize(self, mock_credential_request_schema_load): -# """ -# Test deserialization. -# """ -# obj = {"obj": "obj"} -# -# credential_request = CredentialRequest.deserialize(obj) -# mock_credential_request_schema_load.assert_called_once_with(obj) -# -# assert credential_request is mock_credential_request_schema_load.return_value -# -# @mock.patch( -# "aries_cloudagent.messaging.credentials.messages." -# + "credential_request.CredentialRequestSchema.dump" -# ) -# def test_serialize(self, mock_credential_request_schema_dump): -# """ -# Test serialization -# """ -# credential_request = CredentialRequest( -# offer_json=self.offer_json, -# credential_request_json=self.credential_request_json, -# credential_values_json=self.credential_values_json, -# ) -# -# credential_request_dict = credential_request.serialize() -# mock_credential_request_schema_dump.assert_called_once_with(credential_request) -# -# assert ( -# credential_request_dict is mock_credential_request_schema_dump.return_value -# ) -# -# -# class TestCredentialRequestSchema(TestCase): -# """Test credential request schema.""" -# -# credential_request = CredentialRequest( -# offer_json="offer_json", -# credential_request_json="credential_request_json", -# credential_values_json="credential_values_json", -# ) -# -# def test_make_model(self): -# """Test make model.""" -# data = self.credential_request.serialize() -# model_instance = CredentialRequest.deserialize(data) -# assert isinstance(model_instance, CredentialRequest) diff --git a/aries_cloudagent/protocols/credentials/models/__init__.py b/aries_cloudagent/protocols/credentials/models/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/credentials/models/credential_exchange.py b/aries_cloudagent/protocols/credentials/models/credential_exchange.py deleted file mode 100644 index fe3671e051..0000000000 --- a/aries_cloudagent/protocols/credentials/models/credential_exchange.py +++ /dev/null @@ -1,167 +0,0 @@ -"""Handle credential exchange information interface with non-secrets storage.""" - -from marshmallow import fields - -from ....config.injection_context import InjectionContext -from ....messaging.models.base_record import BaseRecord, BaseRecordSchema - - -class CredentialExchange(BaseRecord): - """Represents a credential exchange.""" - - class Meta: - """CredentialExchange metadata.""" - - schema_class = "CredentialExchangeSchema" - - RECORD_TYPE = "credential_exchange" - RECORD_ID_NAME = "credential_exchange_id" - WEBHOOK_TOPIC = "credentials" - LOG_STATE_FLAG = "debug.credentials" - TAG_NAMES = {"thread_id"} - - INITIATOR_SELF = "self" - INITIATOR_EXTERNAL = "external" - - STATE_OFFER_SENT = "offer_sent" - STATE_OFFER_RECEIVED = "offer_received" - STATE_REQUEST_SENT = "request_sent" - STATE_REQUEST_RECEIVED = "request_received" - STATE_ISSUED = "issued" - STATE_CREDENTIAL_RECEIVED = "credential_received" - STATE_STORED = "stored" - - def __init__( - self, - *, - credential_exchange_id: str = None, - connection_id: str = None, - thread_id: str = None, - parent_thread_id: str = None, - initiator: str = None, - state: str = None, - credential_definition_id: str = None, - schema_id: str = None, - credential_offer: dict = None, - credential_request: dict = None, - credential_request_metadata: dict = None, - credential_id: str = None, - raw_credential: dict = None, - credential: dict = None, - credential_values: dict = None, - auto_issue: bool = False, - error_msg: str = None, - **kwargs, - ): - """Initialize a new CredentialExchange.""" - super().__init__(credential_exchange_id, state, **kwargs) - self.connection_id = connection_id - self.thread_id = thread_id - self.parent_thread_id = parent_thread_id - self.initiator = initiator - self.state = state - self.credential_definition_id = credential_definition_id - self.schema_id = schema_id - self.credential_offer = credential_offer - self.credential_request = credential_request - self.credential_request_metadata = credential_request_metadata - self.credential_id = credential_id - self.credential = credential - self.raw_credential = raw_credential - self.credential_values = credential_values - self.auto_issue = auto_issue - self.error_msg = error_msg - - @property - def credential_exchange_id(self) -> str: - """Accessor for the ID associated with this exchange.""" - return self._id - - @property - def record_value(self) -> dict: - """Accessor to for the JSON record value props for this credential exchange.""" - return { - prop: getattr(self, prop) - for prop in ( - "connection_id", - "initiator", - "credential_offer", - "credential_request", - "credential_request_metadata", - "error_msg", - "auto_issue", - "credential_values", - "credential", - "raw_credential", - "parent_thread_id", - "credential_definition_id", - "schema_id", - "credential_id", - "state", - ) - } - - @classmethod - async def retrieve_by_thread_and_initiator( - cls, context: InjectionContext, thread_id: str, initiator: str - ) -> "CredentialExchange": - """Retrieve a credential exchange record by thread ID and inititator.""" - cache_key = f"credential_exchange_tidx::{thread_id}::{initiator}" - record_id = await cls.get_cached_key(context, cache_key) - if record_id: - record = await cls.retrieve_by_id(context, record_id) - else: - record = await cls.retrieve_by_tag_filter( - context, {"thread_id": thread_id}, {"initiator": initiator} - ) - await cls.set_cached_key(context, cache_key, record.credential_exchange_id) - return record - - async def post_save( - self, - context: InjectionContext, - new_record: bool, - last_state: str, - webhook: bool = None, - ): - """Perform post-save actions. - - Args: - context: The injection context to use - new_record: Flag indicating if the record was just created - last_state: The previous state value - webhook: Adjust whether the webhook is called - """ - await super(CredentialExchange, self).post_save( - context, new_record, last_state, webhook - ) - if self.thread_id and self.initiator: - cache_key = f"credential_exchange_tidx::{self.thread_id}::{self.initiator}" - await self.set_cached_key(context, cache_key, self.credential_exchange_id) - - -class CredentialExchangeSchema(BaseRecordSchema): - """Schema to allow serialization/deserialization of credential exchange records.""" - - class Meta: - """CredentialExchangeSchema metadata.""" - - model_class = CredentialExchange - - credential_exchange_id = fields.Str(required=False) - connection_id = fields.Str(required=False) - thread_id = fields.Str(required=False) - parent_thread_id = fields.Str(required=False) - initiator = fields.Str(required=False) - state = fields.Str(required=False) - credential_definition_id = fields.Str(required=False) - schema_id = fields.Str(required=False) - credential_offer = fields.Dict(required=False) - credential_request = fields.Dict(required=False) - credential_request_metadata = fields.Dict(required=False) - credential_id = fields.Str(required=False) - credential = fields.Dict(required=False) - raw_credential = fields.Dict(required=False) - auto_issue = fields.Bool(required=False) - credential_values = fields.Dict(required=False) - error_msg = fields.Str(required=False) diff --git a/aries_cloudagent/protocols/credentials/routes.py b/aries_cloudagent/protocols/credentials/routes.py deleted file mode 100644 index 468cb948ed..0000000000 --- a/aries_cloudagent/protocols/credentials/routes.py +++ /dev/null @@ -1,631 +0,0 @@ -"""Credential handling admin routes.""" - -import json -from json.decoder import JSONDecodeError - -from aiohttp import web -from aiohttp_apispec import docs, request_schema, response_schema -from marshmallow import fields, Schema - -from ...connections.models.connection_record import ConnectionRecord -from ...holder.base import BaseHolder -from ...messaging.valid import INDY_CRED_DEF_ID, INDY_REV_REG_ID, INDY_SCHEMA_ID -from ...storage.error import StorageNotFoundError -from ...wallet.error import WalletNotFoundError - -from ..problem_report.message import ProblemReport - -from .manager import CredentialManager -from .models.credential_exchange import CredentialExchange, CredentialExchangeSchema - - -class CredentialSendRequestSchema(Schema): - """Request schema for sending a credential offer admin message.""" - - connection_id = fields.Str(required=True) - credential_definition_id = fields.Str(required=True) - credential_values = fields.Dict(required=False) - - -class CredentialSendResultSchema(Schema): - """Result schema for sending a credential offer admin message.""" - - credential_id = fields.Str() - - -class CredentialOfferRequestSchema(Schema): - """Request schema for sending a credential offer admin message.""" - - connection_id = fields.Str(required=True) - credential_definition_id = fields.Str(required=True) - - -class CredentialOfferResultSchema(Schema): - """Result schema for sending a credential offer admin message.""" - - credential_id = fields.Str() - - -class CredentialRequestResultSchema(Schema): - """Result schema for sending a credential request admin message.""" - - credential_id = fields.Str() - - -class CredentialIssueRequestSchema(Schema): - """Request schema for sending a credential issue admin message.""" - - credential_values = fields.Dict(required=True) - - -class CredentialIssueResultSchema(Schema): - """Result schema for sending a credential issue admin message.""" - - credential_id = fields.Str() - - -class CredentialExchangeListSchema(Schema): - """Result schema for a credential exchange query.""" - - results = fields.List(fields.Nested(CredentialExchangeSchema())) - - -class CredentialStoreRequestSchema(Schema): - """Request schema for sending a credential store admin message.""" - - credential_id = fields.Str(required=False) - - -class RawEncCredAttrSchema(Schema): - """Credential attribute schema.""" - - raw = fields.Str(description="Raw value", example="Alex") - encoded = fields.Str( - description="(Numeric string) encoded value", - example="412821674062189604125602903860586582569826459817431467861859655321", - ) - - -class RevRegSchema(Schema): - """Revocation registry schema.""" - - accum = fields.Str( - description="Revocation registry accumulator state", - example="21 136D54EA439FC26F03DB4b812 21 123DE9F624B86823A00D ...", - ) - - -class WitnessSchema(Schema): - """Witness schema.""" - - omega = fields.Str( - description="Revocation registry witness omega state", - example="21 129EA8716C921058BB91826FD 21 8F19B91313862FE916C0 ...", - ) - - -class CredentialSchema(Schema): - """Result schema for a credential query.""" - - schema_id = fields.Str(description="Schema identifier", **INDY_SCHEMA_ID) - cred_def_id = fields.Str( - description="Credential definition identifier", **INDY_CRED_DEF_ID - ) - rev_reg_id = fields.Str( - description="Revocation registry identifier", **INDY_REV_REG_ID - ) - values = fields.Dict( - keys=fields.Str(description="Attribute name"), - values=fields.Nested(RawEncCredAttrSchema), - description="Attribute names mapped to their raw and encoded values", - ) - signature = fields.Dict(description="Digital signature") - signature_correctness_proof = fields.Dict(description="Signature correctness proof") - rev_reg = fields.Nested(RevRegSchema) - witness = fields.Nested(WitnessSchema) - - -class CredentialListSchema(Schema): - """Result schema for a credential query.""" - - results = fields.List(fields.Nested(CredentialSchema())) - - -class CredentialProblemReportRequestSchema(Schema): - """Request schema for sending a problem report.""" - - explain_ltxt = fields.Str(required=True) - - -@docs(tags=["credentials"], summary="Fetch a credential from wallet by id") -@response_schema(CredentialSchema(), 200) -async def credentials_get(request: web.BaseRequest): - """ - Request handler for retrieving a credential. - - Args: - request: aiohttp request object - - Returns: - The credential response - - """ - context = request.app["request_context"] - - credential_id = request.match_info["id"] - - holder: BaseHolder = await context.inject(BaseHolder) - try: - credential = await holder.get_credential(credential_id) - except WalletNotFoundError: - raise web.HTTPNotFound() - - return web.json_response(json.loads(credential)) - - -@docs(tags=["credentials"], summary="Remove a credential from the wallet by id") -async def credentials_remove(request: web.BaseRequest): - """ - Request handler for searching connection records. - - Args: - request: aiohttp request object - - Returns: - The connection list response - - """ - context = request.app["request_context"] - - credential_id = request.match_info["id"] - - holder: BaseHolder = await context.inject(BaseHolder) - try: - await holder.delete_credential(credential_id) - except WalletNotFoundError: - raise web.HTTPNotFound() - - return web.json_response({}) - - -@docs( - tags=["credentials"], - parameters=[ - { - "name": "start", - "in": "query", - "schema": {"type": "string"}, - "required": False, - }, - { - "name": "count", - "in": "query", - "schema": {"type": "string"}, - "required": False, - }, - {"name": "wql", "in": "query", "schema": {"type": "string"}, "required": False}, - ], - summary="Fetch credentials from wallet", -) -@response_schema(CredentialListSchema(), 200) -async def credentials_list(request: web.BaseRequest): - """ - Request handler for searching credential records. - - Args: - request: aiohttp request object - - Returns: - The credential list response - - """ - context = request.app["request_context"] - - start = request.query.get("start") - count = request.query.get("count") - - # url encoded json wql - encoded_wql = request.query.get("wql") or "{}" - wql = json.loads(encoded_wql) - - # defaults - start = int(start) if isinstance(start, str) else 0 - count = int(count) if isinstance(count, str) else 10 - - holder: BaseHolder = await context.inject(BaseHolder) - credentials = await holder.get_credentials(start, count, wql) - - return web.json_response({"results": credentials}) - - -@docs( - tags=["credential_exchange *DEPRECATED*"], - summary="Fetch all credential exchange records", -) -@response_schema(CredentialExchangeListSchema(), 200) -async def credential_exchange_list(request: web.BaseRequest): - """ - Request handler for searching credential exchange records. - - Args: - request: aiohttp request object - - Returns: - The credential exchange list response - - """ - context = request.app["request_context"] - tag_filter = {} - if "thread_id" in request.query and request.query["thread_id"] != "": - tag_filter["thread_id"] = request.query["thread_id"] - post_filter = {} - for param_name in ( - "connection_id", - "initiator", - "state", - "credential_definition_id", - "schema_id", - ): - if param_name in request.query and request.query[param_name] != "": - post_filter[param_name] = request.query[param_name] - records = await CredentialExchange.query(context, tag_filter, post_filter) - return web.json_response({"results": [record.serialize() for record in records]}) - - -@docs( - tags=["credential_exchange *DEPRECATED*"], - summary="Fetch a single credential exchange record", -) -@response_schema(CredentialExchangeSchema(), 200) -async def credential_exchange_retrieve(request: web.BaseRequest): - """ - Request handler for fetching a single credential exchange record. - - Args: - request: aiohttp request object - - Returns: - The credential exchange record response - - """ - context = request.app["request_context"] - credential_exchange_id = request.match_info["id"] - try: - record = await CredentialExchange.retrieve_by_id( - context, credential_exchange_id - ) - except StorageNotFoundError: - raise web.HTTPNotFound() - return web.json_response(record.serialize()) - - -@docs( - tags=["credential_exchange *DEPRECATED*"], - summary="Sends a credential and automates the entire flow", -) -@request_schema(CredentialSendRequestSchema()) -@response_schema(CredentialSendResultSchema(), 200) -async def credential_exchange_send(request: web.BaseRequest): - """ - Request handler for sending a credential. - - Args: - request: aiohttp request object - - Returns: - The credential offer details. - - """ - - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - body = await request.json() - - connection_id = body.get("connection_id") - credential_definition_id = body.get("credential_definition_id") - credential_values = body.get("credential_values") - - credential_manager = CredentialManager(context) - - try: - connection_record = await ConnectionRecord.retrieve_by_id( - context, connection_id - ) - except StorageNotFoundError: - raise web.HTTPBadRequest() - - if not connection_record.is_ready: - raise web.HTTPForbidden() - - ( - credential_exchange_record, - credential_offer_message, - ) = await credential_manager.create_offer( - credential_definition_id, connection_id, True, credential_values - ) - - await outbound_handler(credential_offer_message, connection_id=connection_id) - return web.json_response(credential_exchange_record.serialize()) - - -@docs(tags=["credential_exchange *DEPRECATED*"], summary="Sends a credential offer") -@request_schema(CredentialOfferRequestSchema()) -@response_schema(CredentialOfferResultSchema(), 200) -async def credential_exchange_send_offer(request: web.BaseRequest): - """ - Request handler for sending a credential offer. - - Args: - request: aiohttp request object - - Returns: - The credential offer details. - - """ - - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - body = await request.json() - - connection_id = body.get("connection_id") - credential_definition_id = body.get("credential_definition_id") - - credential_manager = CredentialManager(context) - - try: - connection_record = await ConnectionRecord.retrieve_by_id( - context, connection_id - ) - except StorageNotFoundError: - raise web.HTTPBadRequest() - - if not connection_record.is_ready: - raise web.HTTPForbidden() - - ( - credential_exchange_record, - credential_offer_message, - ) = await credential_manager.create_offer(credential_definition_id, connection_id) - - await outbound_handler(credential_offer_message, connection_id=connection_id) - return web.json_response(credential_exchange_record.serialize()) - - -@docs(tags=["credential_exchange *DEPRECATED*"], summary="Sends a credential request") -@response_schema(CredentialRequestResultSchema(), 200) -async def credential_exchange_send_request(request: web.BaseRequest): - """ - Request handler for sending a credential request. - - Args: - request: aiohttp request object - - Returns: - The credential request details. - - """ - - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - credential_exchange_id = request.match_info["id"] - credential_exchange_record = await CredentialExchange.retrieve_by_id( - context, credential_exchange_id - ) - connection_id = credential_exchange_record.connection_id - - assert credential_exchange_record.state == CredentialExchange.STATE_OFFER_RECEIVED - - credential_manager = CredentialManager(context) - - try: - connection_record = await ConnectionRecord.retrieve_by_id( - context, connection_id - ) - except StorageNotFoundError: - raise web.HTTPBadRequest() - - if not connection_record.is_ready: - raise web.HTTPForbidden() - - ( - credential_exchange_record, - credential_request_message, - ) = await credential_manager.create_request( - credential_exchange_record, connection_record - ) - - await outbound_handler(credential_request_message, connection_id=connection_id) - return web.json_response(credential_exchange_record.serialize()) - - -@docs(tags=["credential_exchange *DEPRECATED*"], summary="Sends a credential") -@request_schema(CredentialIssueRequestSchema()) -@response_schema(CredentialIssueResultSchema(), 200) -async def credential_exchange_issue(request: web.BaseRequest): - """ - Request handler for sending a credential. - - Args: - request: aiohttp request object - - Returns: - The credential details. - - """ - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - body = await request.json() - credential_values = body["credential_values"] - - credential_exchange_id = request.match_info["id"] - credential_exchange_record = await CredentialExchange.retrieve_by_id( - context, credential_exchange_id - ) - connection_id = credential_exchange_record.connection_id - - assert credential_exchange_record.state == CredentialExchange.STATE_REQUEST_RECEIVED - - credential_manager = CredentialManager(context) - try: - connection_record = await ConnectionRecord.retrieve_by_id( - context, connection_id - ) - except StorageNotFoundError: - raise web.HTTPBadRequest() - - if not connection_record.is_ready: - raise web.HTTPForbidden() - - credential_exchange_record.credential_values = credential_values - ( - credential_exchange_record, - credential_issue_message, - ) = await credential_manager.issue_credential(credential_exchange_record) - - await outbound_handler(credential_issue_message, connection_id=connection_id) - return web.json_response(credential_exchange_record.serialize()) - - -@docs(tags=["credential_exchange *DEPRECATED*"], summary="Stores a received credential") -@request_schema(CredentialStoreRequestSchema()) -@response_schema(CredentialRequestResultSchema(), 200) -async def credential_exchange_store(request: web.BaseRequest): - """ - Request handler for storing a credential request. - - Args: - request: aiohttp request object - - Returns: - The credential request details. - - """ - - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - try: - body = await request.json() or {} - credential_id = body.get("credential_id") - except JSONDecodeError: - credential_id = None - - credential_exchange_id = request.match_info["id"] - credential_exchange_record = await CredentialExchange.retrieve_by_id( - context, credential_exchange_id - ) - connection_id = credential_exchange_record.connection_id - - assert ( - credential_exchange_record.state == CredentialExchange.STATE_CREDENTIAL_RECEIVED - ) - - credential_manager = CredentialManager(context) - - try: - connection_record = await ConnectionRecord.retrieve_by_id( - context, connection_id - ) - except StorageNotFoundError: - raise web.HTTPBadRequest() - - if not connection_record.is_ready: - raise web.HTTPForbidden() - - ( - credential_exchange_record, - credential_stored_message, - ) = await credential_manager.store_credential( - credential_exchange_record, credential_id - ) - - await outbound_handler(credential_stored_message, connection_id=connection_id) - return web.json_response(credential_exchange_record.serialize()) - - -@docs( - tags=["credential_exchange *DEPRECATED*"], - summary="Send a problem report for credential exchange", -) -@request_schema(CredentialProblemReportRequestSchema()) -async def credential_exchange_problem_report(request: web.BaseRequest): - """ - Request handler for sending a problem report. - - Args: - request: aiohttp request object - """ - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - body = await request.json() - - try: - credential_exchange_id = request.match_info["id"] - credential_exchange_record = await CredentialExchange.retrieve_by_id( - context, credential_exchange_id - ) - except StorageNotFoundError: - raise web.HTTPNotFound() - - error_result = ProblemReport(explain_ltxt=body["explain_ltxt"]) - error_result.assign_thread_id(credential_exchange_record.thread_id) - - await outbound_handler( - error_result, connection_id=credential_exchange_record.connection_id - ) - return web.json_response({}) - - -@docs( - tags=["credential_exchange *DEPRECATED*"], - summary="Remove an existing credential exchange record", -) -async def credential_exchange_remove(request: web.BaseRequest): - """ - Request handler for removing a credential exchange record. - - Args: - request: aiohttp request object - """ - context = request.app["request_context"] - credential_exchange_id = request.match_info["id"] - try: - credential_exchange_record = await CredentialExchange.retrieve_by_id( - context, credential_exchange_id - ) - except StorageNotFoundError: - raise web.HTTPNotFound() - await credential_exchange_record.delete_record(context) - return web.json_response({}) - - -async def register(app: web.Application): - """Register routes.""" - - app.add_routes( - [ - web.get("/credential/{id}", credentials_get), - web.post("/credential/{id}/remove", credentials_remove), - web.get("/credentials", credentials_list), - web.get("/credential_exchange", credential_exchange_list), - web.get("/credential_exchange/{id}", credential_exchange_retrieve), - web.post("/credential_exchange/send", credential_exchange_send), - web.post("/credential_exchange/send-offer", credential_exchange_send_offer), - web.post( - "/credential_exchange/{id}/send-request", - credential_exchange_send_request, - ), - web.post("/credential_exchange/{id}/issue", credential_exchange_issue), - web.post("/credential_exchange/{id}/store", credential_exchange_store), - web.post( - "/credential_exchange/{id}/problem_report", - credential_exchange_problem_report, - ), - web.post("/credential_exchange/{id}/remove", credential_exchange_remove), - ] - ) diff --git a/aries_cloudagent/protocols/credentials/tests/__init__.py b/aries_cloudagent/protocols/credentials/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/credentials/tests/test_routes.py b/aries_cloudagent/protocols/credentials/tests/test_routes.py deleted file mode 100644 index 3f0259a921..0000000000 --- a/aries_cloudagent/protocols/credentials/tests/test_routes.py +++ /dev/null @@ -1,595 +0,0 @@ -from asynctest import TestCase as AsyncTestCase -from asynctest import mock as async_mock - -from .. import routes as test_module - -from ....storage.error import StorageNotFoundError - - -class TestCredentialRoutes(AsyncTestCase): - async def test_credential_exchange_send(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_credential_manager, async_mock.patch.object( - test_module.web, "json_response" - ) as mock_response: - - mock_cred_ex_record = async_mock.MagicMock() - - # mock_credential_manager.return_value.create_offer = async_mock.MagicMock() - - mock_credential_manager.return_value.create_offer.return_value = ( - mock_cred_ex_record, - async_mock.MagicMock(), - ) - - await test_module.credential_exchange_send(mock) - - mock_response.assert_called_once_with( - mock_credential_manager.return_value.create_offer.return_value[ - 0 - ].serialize.return_value - ) - - async def test_credential_exchange_send_no_conn_record(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_credential_manager: - - # Emulate storage not found (bad connection id) - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock( - side_effect=StorageNotFoundError - ) - - mock_credential_manager.return_value.create_offer = async_mock.MagicMock() - - mock_credential_manager.return_value.create_offer.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.credential_exchange_send(mock) - - async def test_credential_exchange_send_not_ready(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_credential_manager: - - # Emulate connection not ready - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock() - mock_connection_record.retrieve_by_id.return_value.is_ready = False - - mock_credential_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_credential_manager.return_value.create_offer.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.credential_exchange_send(mock) - - async def test_credential_exchange_send_offer(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module.web, "json_response" - ) as mock_response: - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_cred_ex_record = async_mock.MagicMock() - - mock_connection_manager.return_value.create_offer.return_value = ( - mock_cred_ex_record, - async_mock.MagicMock(), - ) - - await test_module.credential_exchange_send_offer(mock) - - mock_response.assert_called_once_with( - mock_cred_ex_record.serialize.return_value - ) - - async def test_credential_exchange_send_offer_no_conn_record(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager: - - # Emulate storage not found (bad connection id) - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock( - side_effect=StorageNotFoundError - ) - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_connection_manager.return_value.create_offer.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.credential_exchange_send_offer(mock) - - async def test_credential_exchange_send_offer_not_ready(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager: - - # Emulate connection not ready - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock() - mock_connection_record.retrieve_by_id.return_value.is_ready = False - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_connection_manager.return_value.create_offer.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.credential_exchange_send_offer(mock) - - async def test_credential_exchange_send_request(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex, async_mock.patch.object( - test_module.web, "json_response" - ) as mock_response: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_OFFER_RECEIVED - ) - - mock_cred_ex_record = async_mock.MagicMock() - - mock_connection_manager.return_value.create_request.return_value = ( - mock_cred_ex_record, - async_mock.MagicMock(), - ) - - await test_module.credential_exchange_send_request(mock) - - mock_response.assert_called_once_with( - mock_cred_ex_record.serialize.return_value - ) - - async def test_credential_exchange_send_request_no_conn_record(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_OFFER_RECEIVED - ) - - # Emulate storage not found (bad connection id) - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock( - side_effect=StorageNotFoundError - ) - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_connection_manager.return_value.create_offer.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.credential_exchange_send_request(mock) - - async def test_credential_exchange_send_request_not_ready(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_OFFER_RECEIVED - ) - - # Emulate connection not ready - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock() - mock_connection_record.retrieve_by_id.return_value.is_ready = False - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_connection_manager.return_value.create_offer.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.credential_exchange_send_request(mock) - - async def test_credential_exchange_store(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex, async_mock.patch.object( - test_module.web, "json_response" - ) as mock_response: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_CREDENTIAL_RECEIVED - ) - - mock_cred_ex_record = async_mock.MagicMock() - - mock_connection_manager.return_value.store_credential.return_value = ( - mock_cred_ex_record, - async_mock.MagicMock(), - ) - - await test_module.credential_exchange_store(mock) - - mock_response.assert_called_once_with( - mock_cred_ex_record.serialize.return_value - ) - - async def test_credential_exchange_store_no_conn_record(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_CREDENTIAL_RECEIVED - ) - - # Emulate storage not found (bad connection id) - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock( - side_effect=StorageNotFoundError - ) - - mock_connection_manager.return_value.store_credential.return_value = ( - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.credential_exchange_store(mock) - - async def test_credential_exchange_store_not_ready(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_CREDENTIAL_RECEIVED - ) - - # Emulate connection not ready - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock() - mock_connection_record.retrieve_by_id.return_value.is_ready = False - - mock_connection_manager.return_value.store_credential.return_value = ( - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.credential_exchange_store(mock) - - async def test_credential_exchange_issue(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex, async_mock.patch.object( - test_module.web, "json_response" - ) as mock_response: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_REQUEST_RECEIVED - ) - - mock_cred_ex_record = async_mock.MagicMock() - - mock_connection_manager.return_value.issue_credential.return_value = ( - mock_cred_ex_record, - async_mock.MagicMock(), - ) - - await test_module.credential_exchange_issue(mock) - - mock_response.assert_called_once_with( - mock_cred_ex_record.serialize.return_value - ) - - async def test_credential_exchange_issue_no_conn_record(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_REQUEST_RECEIVED - ) - - # Emulate storage not found (bad connection id) - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock( - side_effect=StorageNotFoundError - ) - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_connection_manager.return_value.issue_credential.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPBadRequest): - await test_module.credential_exchange_issue(mock) - - async def test_credential_exchange_issue_not_ready(self): - mock = async_mock.MagicMock() - mock.json = async_mock.CoroutineMock() - - mock.app = { - "outbound_message_router": async_mock.CoroutineMock(), - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - mock_cred_ex.retrieve_by_id.return_value.state = ( - mock_cred_ex.STATE_REQUEST_RECEIVED - ) - - # Emulate connection not ready - mock_connection_record.retrieve_by_id = async_mock.CoroutineMock() - mock_connection_record.retrieve_by_id.return_value.is_ready = False - - mock_connection_manager.return_value.create_offer = ( - async_mock.CoroutineMock() - ) - - mock_connection_manager.return_value.issue_credential.return_value = ( - async_mock.MagicMock(), - async_mock.MagicMock(), - ) - - with self.assertRaises(test_module.web.HTTPForbidden): - await test_module.credential_exchange_issue(mock) - - async def test_credential_exchange_problem_report(self): - mock_request = async_mock.MagicMock() - mock_request.json = async_mock.CoroutineMock() - - mock_outbound = async_mock.CoroutineMock() - - mock_request.app = { - "outbound_message_router": mock_outbound, - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex, async_mock.patch.object( - test_module, "ProblemReport", autospec=True - ) as mock_prob_report, async_mock.patch.object( - test_module.web, "json_response" - ) as mock_response: - - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock() - - await test_module.credential_exchange_problem_report(mock_request) - - mock_response.assert_called_once_with({}) - mock_outbound.assert_called_once_with( - mock_prob_report.return_value, - connection_id=mock_cred_ex.retrieve_by_id.return_value.connection_id, - ) - - async def test_credential_exchange_problem_report_no_cred_record(self): - - mock_request = async_mock.MagicMock() - mock_request.json = async_mock.CoroutineMock() - - mock_outbound = async_mock.CoroutineMock() - - mock_request.app = { - "outbound_message_router": mock_outbound, - "request_context": "context", - } - - with async_mock.patch.object( - test_module, "ConnectionRecord", autospec=True - ) as mock_connection_record, async_mock.patch.object( - test_module, "CredentialManager", autospec=True - ) as mock_connection_manager, async_mock.patch.object( - test_module, "CredentialExchange", autospec=True - ) as mock_cred_ex, async_mock.patch.object( - test_module, "ProblemReport", autospec=True - ) as mock_prob_report: - - # Emulate storage not found (bad connection id) - mock_cred_ex.retrieve_by_id = async_mock.CoroutineMock( - side_effect=StorageNotFoundError - ) - - with self.assertRaises(test_module.web.HTTPNotFound): - await test_module.credential_exchange_problem_report(mock_request) diff --git a/aries_cloudagent/protocols/presentations/__init__.py b/aries_cloudagent/protocols/presentations/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/presentations/handlers/__init__.py b/aries_cloudagent/protocols/presentations/handlers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/presentations/handlers/credential_presentation_handler.py b/aries_cloudagent/protocols/presentations/handlers/credential_presentation_handler.py deleted file mode 100644 index ed9a6bb843..0000000000 --- a/aries_cloudagent/protocols/presentations/handlers/credential_presentation_handler.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Basic message handler.""" - -import json - -from ....messaging.base_handler import BaseHandler, BaseResponder, RequestContext - -from ..manager import PresentationManager -from ..messages.credential_presentation import CredentialPresentation - - -class CredentialPresentationHandler(BaseHandler): - """Message handler class for credential presentations.""" - - async def handle(self, context: RequestContext, responder: BaseResponder): - """ - Message handler logic for credential presentations. - - Args: - context: request context - responder: responder callback - """ - self._logger.debug( - f"CredentialPresentationHandler called with context {context}" - ) - assert isinstance(context.message, CredentialPresentation) - self._logger.info( - f"Received credential presentation: {context.message.presentation}" - ) - - presentation_manager = PresentationManager(context) - - presentation_exchange_record = await presentation_manager.receive_presentation( - json.loads(context.message.presentation), context.message._thread_id - ) - - if context.settings.get("debug.auto_verify_presentation"): - await presentation_manager.verify_presentation(presentation_exchange_record) diff --git a/aries_cloudagent/protocols/presentations/handlers/presentation_request_handler.py b/aries_cloudagent/protocols/presentations/handlers/presentation_request_handler.py deleted file mode 100644 index 68ea41f80f..0000000000 --- a/aries_cloudagent/protocols/presentations/handlers/presentation_request_handler.py +++ /dev/null @@ -1,100 +0,0 @@ -"""Basic message handler.""" - -import json - -from ....holder.base import BaseHolder -from ....messaging.base_handler import BaseHandler, BaseResponder, RequestContext - -from ..manager import PresentationManager -from ..messages.presentation_request import PresentationRequest - - -class PresentationRequestHandler(BaseHandler): - """Message handler class for presentation requests.""" - - async def handle(self, context: RequestContext, responder: BaseResponder): - """ - Message handler logic for presentation requests. - - Args: - context: request context - responder: responder callback - """ - self._logger.debug(f"PresentationRequestHandler called with context {context}") - - assert isinstance(context.message, PresentationRequest) - - self._logger.info("Received presentation request: %s", context.message.request) - - presentation_manager = PresentationManager(context) - - presentation_exchange_record = await presentation_manager.receive_request( - context.message, context.connection_record.connection_id - ) - - # If auto_respond_presentation_request is set, try to build a presentation - # This will fail and bail out if there isn't exactly one credential returned - # for each requested attribute and predicate. All credential data will be - # revealed. - if context.settings.get("debug.auto_respond_presentation_request"): - holder: BaseHolder = await context.inject(BaseHolder) - credentials_for_presentation = { - "self_attested_attributes": {}, - "requested_attributes": {}, - "requested_predicates": {}, - } - - presentation_request = json.loads(context.message.request) - - for referent in presentation_request["requested_attributes"]: - ( - credentials - ) = await holder.get_credentials_for_presentation_request_by_referent( - presentation_request, (referent,), 0, 2, {} - ) - if len(credentials) != 1: - self._logger.warning( - f"Could not automatically construct presentation for" - + f" presentation request {presentation_request['name']}" - + f":{presentation_request['version']} because referent " - + f"{referent} did not produce exactly one credential result." - + f" {len(credentials)} credentials were returned from the " - + f"wallet." - ) - return - - credentials_for_presentation["requested_attributes"][referent] = { - "cred_id": credentials[0]["cred_info"]["referent"], - "revealed": True, - } - - for referent in presentation_request["requested_predicates"]: - ( - credentials - ) = await holder.get_credentials_for_presentation_request_by_referent( - presentation_request, (referent,), 0, 2, {} - ) - if len(credentials) != 1: - self._logger.warning( - f"Could not automatically construct presentation for" - + f" presentation request {presentation_request['name']}" - + f":{presentation_request['version']} because referent " - + f"{referent} did not produce exactly one credential result." - + f" {len(credentials)} credentials were returned from the " - + f"wallet." - ) - return - - credentials_for_presentation["requested_predicates"][referent] = { - "cred_id": credentials[0]["cred_info"]["referent"], - "revealed": True, - } - - ( - presentation_exchange_record, - presentation_message, - ) = await presentation_manager.create_presentation( - presentation_exchange_record, credentials_for_presentation - ) - - await responder.send_reply(presentation_message) diff --git a/aries_cloudagent/protocols/presentations/manager.py b/aries_cloudagent/protocols/presentations/manager.py deleted file mode 100644 index e5e990565a..0000000000 --- a/aries_cloudagent/protocols/presentations/manager.py +++ /dev/null @@ -1,285 +0,0 @@ -"""Classes to manage presentations.""" - -import json -import logging -from uuid import uuid4 - -from ...config.injection_context import InjectionContext -from ...core.error import BaseError -from ...holder.base import BaseHolder -from ...ledger.base import BaseLedger -from ...verifier.base import BaseVerifier -from ...indy.util import generate_pr_nonce - -from .models.presentation_exchange import PresentationExchange -from .messages.presentation_request import PresentationRequest -from .messages.credential_presentation import CredentialPresentation - - -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 credential - """ - self._context = context - self._logger = logging.getLogger(__name__) - - @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_request( - self, - name: str, - version: str, - requested_attributes: list, - requested_predicates: list, - connection_id: str, - ): - """Create a proof request.""" - - presentation_request = { - "name": name, - "version": version, - "nonce": await generate_pr_nonce(), - "requested_attributes": {}, - "requested_predicates": {}, - } - - for requested_attribute in requested_attributes: - presentation_request["requested_attributes"][ - str(uuid4()) - ] = requested_attribute - - for requested_predicates in requested_predicates: - presentation_request["requested_predicates"][ - str(uuid4()) - ] = requested_predicates - - presentation_request_message = PresentationRequest( - request=json.dumps(presentation_request) - ) - - presentation_exchange = PresentationExchange( - connection_id=connection_id, - initiator=PresentationExchange.INITIATOR_SELF, - state=PresentationExchange.STATE_REQUEST_SENT, - presentation_request=presentation_request, - thread_id=presentation_request_message._thread_id, - ) - - await presentation_exchange.save( - self.context, reason="Create presentation request" - ) - - return presentation_exchange, presentation_request_message - - async def receive_request( - self, presentation_request_message: PresentationRequest, connection_id: str - ): - """ - Receive a presentation request. - - Args: - presentation_request_message: Presentation message to receive - """ - - presentation_exchange = PresentationExchange( - connection_id=connection_id, - thread_id=presentation_request_message._thread_id, - initiator=PresentationExchange.INITIATOR_EXTERNAL, - state=PresentationExchange.STATE_REQUEST_RECEIVED, - presentation_request=json.loads(presentation_request_message.request), - ) - - await presentation_exchange.save( - self.context, reason="Receive presentation request" - ) - - return presentation_exchange - - async def create_presentation( - self, - presentation_exchange_record: PresentationExchange, - requested_credentials: dict, - ): - """ - Receive a presentation request. - - Args: - presentation_exchange_record: Record to update - requested_credentials: Indy formatted requested_credentials - - i.e., - - :: - - { - "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" - } - } - } - - """ - - # Get all credential ids for this presentation - credential_ids = [] - - requested_attributes = requested_credentials["requested_attributes"] - for presentation_referent in requested_attributes: - credential_id = requested_attributes[presentation_referent]["cred_id"] - credential_ids.append(credential_id) - - requested_predicates = requested_credentials["requested_predicates"] - for presentation_referent in requested_predicates: - credential_id = requested_predicates[presentation_referent]["cred_id"] - credential_ids.append(credential_id) - - # Get all schema and credential definition ids in use - # TODO: Cache this!!! - schema_ids = [] - credential_definition_ids = [] - holder: BaseHolder = await self.context.inject(BaseHolder) - for credential_id in credential_ids: - credential = json.loads(await holder.get_credential(credential_id)) - schema_id = credential["schema_id"] - credential_definition_id = credential["cred_def_id"] - schema_ids.append(schema_id) - credential_definition_ids.append(credential_definition_id) - - schemas = {} - credential_definitions = {} - - ledger: BaseLedger = await self.context.inject(BaseLedger) - async with ledger: - - # Build schemas for anoncreds - for schema_id in schema_ids: - schema = await ledger.get_schema(schema_id) - schemas[schema_id] = schema - - # Build credential_definitions for anoncreds - for credential_definition_id in credential_definition_ids: - (credential_definition) = await ledger.get_credential_definition( - credential_definition_id - ) - credential_definitions[credential_definition_id] = credential_definition - - holder: BaseHolder = await self.context.inject(BaseHolder) - presentation_json = await holder.create_presentation( - presentation_exchange_record.presentation_request, - requested_credentials, - schemas, - credential_definitions, - ) - - presentation_message = CredentialPresentation(presentation=presentation_json) - - # TODO: Find a more elegant way to do this - presentation_message._thread = {"thid": presentation_exchange_record.thread_id} - - # save presentation exchange state - presentation_exchange_record.state = ( - PresentationExchange.STATE_PRESENTATION_SENT - ) - presentation_exchange_record.presentation = json.loads(presentation_json) - await presentation_exchange_record.save( - self.context, - reason="Create presentation", - log_params={"requested_credentials": requested_credentials}, - ) - - return presentation_exchange_record, presentation_message - - async def receive_presentation(self, presentation: dict, thread_id: str): - """Receive a presentation request.""" - ( - presentation_exchange_record - ) = await PresentationExchange.retrieve_by_tag_filter( - self.context, {"thread_id": thread_id}, {"initiator": "self"} - ) - - presentation_exchange_record.presentation = presentation - presentation_exchange_record.state = ( - PresentationExchange.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: PresentationExchange - ): - """Verify a presentation request.""" - - presentation_request = presentation_exchange_record.presentation_request - presentation = presentation_exchange_record.presentation - - schema_ids = [] - credential_definition_ids = [] - - identifiers = presentation["identifiers"] - for identifier in identifiers: - schema_ids.append(identifier["schema_id"]) - credential_definition_ids.append(identifier["cred_def_id"]) - - schemas = {} - credential_definitions = {} - - ledger: BaseLedger = await self.context.inject(BaseLedger) - async with ledger: - - # Build schemas for anoncreds - for schema_id in schema_ids: - schema = await ledger.get_schema(schema_id) - schemas[schema_id] = schema - - # Build credential_definitions for anoncreds - for credential_definition_id in credential_definition_ids: - (credential_definition) = await ledger.get_credential_definition( - credential_definition_id - ) - credential_definitions[credential_definition_id] = credential_definition - - verifier: BaseVerifier = await self.context.inject(BaseVerifier) - verified = await verifier.verify_presentation( - presentation_request, presentation, schemas, credential_definitions - ) - - presentation_exchange_record.verified = "true" if verified else "false" - presentation_exchange_record.state = PresentationExchange.STATE_VERIFIED - - await presentation_exchange_record.save( - self.context, reason="Verify presentation" - ) - - return presentation_exchange_record diff --git a/aries_cloudagent/protocols/presentations/message_types.py b/aries_cloudagent/protocols/presentations/message_types.py deleted file mode 100644 index f327c9c193..0000000000 --- a/aries_cloudagent/protocols/presentations/message_types.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Message type identifiers for presentations.""" - -PROTOCOL_URI = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-presentation/0.1" - -PRESENTATION_REQUEST = f"{PROTOCOL_URI}/presentation-request" -CREDENTIAL_PRESENTATION = f"{PROTOCOL_URI}/credential-presentation" - -NEW_PROTOCOL_URI = "https://didcomm.org/credential-presentation/0.1" - -NEW_PRESENTATION_REQUEST = f"{NEW_PROTOCOL_URI}/presentation-request" -NEW_CREDENTIAL_PRESENTATION = f"{NEW_PROTOCOL_URI}/credential-presentation" - -PROTOCOL_PACKAGE = "aries_cloudagent.protocols.presentations" - -MESSAGE_TYPES = { - PRESENTATION_REQUEST: ( - f"{PROTOCOL_PACKAGE}.messages.presentation_request.PresentationRequest" - ), - CREDENTIAL_PRESENTATION: ( - f"{PROTOCOL_PACKAGE}.messages.credential_presentation.CredentialPresentation" - ), - NEW_PRESENTATION_REQUEST: ( - f"{PROTOCOL_PACKAGE}.messages.presentation_request.PresentationRequest" - ), - NEW_CREDENTIAL_PRESENTATION: ( - f"{PROTOCOL_PACKAGE}.messages.credential_presentation.CredentialPresentation" - ), -} diff --git a/aries_cloudagent/protocols/presentations/messages/__init__.py b/aries_cloudagent/protocols/presentations/messages/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/presentations/messages/credential_presentation.py b/aries_cloudagent/protocols/presentations/messages/credential_presentation.py deleted file mode 100644 index 33d6fb2081..0000000000 --- a/aries_cloudagent/protocols/presentations/messages/credential_presentation.py +++ /dev/null @@ -1,48 +0,0 @@ -"""A credential presentation message.""" - -from marshmallow import fields - -from ....messaging.agent_message import AgentMessage, AgentMessageSchema - -from ..message_types import CREDENTIAL_PRESENTATION, PROTOCOL_PACKAGE - - -HANDLER_CLASS = ( - f"{PROTOCOL_PACKAGE}.handlers." - "credential_presentation_handler.CredentialPresentationHandler" -) - - -class CredentialPresentation(AgentMessage): - """Class representing a credential presentation.""" - - class Meta: - """CredentialPresentation metadata.""" - - handler_class = HANDLER_CLASS - schema_class = "CredentialPresentationSchema" - message_type = CREDENTIAL_PRESENTATION - - def __init__(self, presentation: str = None, comment: str = None, **kwargs): - """ - Initialize credential presentation object. - - Args: - presentation: Credential presentation json string - comment: Comment - """ - super(CredentialPresentation, self).__init__(**kwargs) - self.presentation = presentation - self.comment = comment - - -class CredentialPresentationSchema(AgentMessageSchema): - """CredentialPresentation schema.""" - - class Meta: - """CredentialPresentationSchema metadata.""" - - model_class = CredentialPresentation - - presentation = fields.Str(required=True) - comment = fields.Str(required=False) diff --git a/aries_cloudagent/protocols/presentations/messages/presentation_request.py b/aries_cloudagent/protocols/presentations/messages/presentation_request.py deleted file mode 100644 index 7f96fef469..0000000000 --- a/aries_cloudagent/protocols/presentations/messages/presentation_request.py +++ /dev/null @@ -1,46 +0,0 @@ -"""A presentation request content message.""" - -from marshmallow import fields - -from ....messaging.agent_message import AgentMessage, AgentMessageSchema - -from ..message_types import PRESENTATION_REQUEST, PROTOCOL_PACKAGE - -HANDLER_CLASS = ( - f"{PROTOCOL_PACKAGE}.handlers." - "presentation_request_handler.PresentationRequestHandler" -) - - -class PresentationRequest(AgentMessage): - """Class representing a presentation request.""" - - class Meta: - """PresentationRequest metadata.""" - - handler_class = HANDLER_CLASS - message_type = PRESENTATION_REQUEST - schema_class = "PresentationRequestSchema" - - def __init__(self, request: str = None, comment: str = None, **kwargs): - """ - Initialize presentation request object. - - Args: - request: Presentation request json string - """ - super(PresentationRequest, self).__init__(**kwargs) - self.request = request - self.comment = comment - - -class PresentationRequestSchema(AgentMessageSchema): - """PresentationRequest schema.""" - - class Meta: - """PresentationRequestSchema metadata.""" - - model_class = PresentationRequest - - request = fields.Str(required=True) - comment = fields.Str(required=False) diff --git a/aries_cloudagent/protocols/presentations/models/__init__.py b/aries_cloudagent/protocols/presentations/models/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/aries_cloudagent/protocols/presentations/models/presentation_exchange.py b/aries_cloudagent/protocols/presentations/models/presentation_exchange.py deleted file mode 100644 index 1a3a89f5dd..0000000000 --- a/aries_cloudagent/protocols/presentations/models/presentation_exchange.py +++ /dev/null @@ -1,94 +0,0 @@ -"""Handle presentation exchange information interface with non-secrets storage.""" - -from marshmallow import fields - -from ....messaging.models.base_record import BaseRecord, BaseRecordSchema - - -class PresentationExchange(BaseRecord): - """Represents a presentation exchange.""" - - class Meta: - """PresentationExchange metadata.""" - - schema_class = "PresentationExchangeSchema" - - RECORD_TYPE = "presentation_exchange" - RECORD_ID_NAME = "presentation_exchange_id" - WEBHOOK_TOPIC = "presentations" - LOG_STATE_FLAG = "debug.presentations" - TAG_NAMES = {"thread_id"} - - INITIATOR_SELF = "self" - INITIATOR_EXTERNAL = "external" - - STATE_REQUEST_SENT = "request_sent" - STATE_REQUEST_RECEIVED = "request_received" - STATE_PRESENTATION_SENT = "presentation_sent" - STATE_PRESENTATION_RECEIVED = "presentation_received" - STATE_VERIFIED = "verified" - - def __init__( - self, - *, - presentation_exchange_id: str = None, - connection_id: str = None, - thread_id: str = None, - initiator: str = None, - state: str = None, - presentation_request: dict = None, - presentation: dict = None, - verified: str = None, - error_msg: str = None, - **kwargs - ): - """Initialize a new PresentationExchange.""" - super().__init__(presentation_exchange_id, state, **kwargs) - self.connection_id = connection_id - self.thread_id = thread_id - self.initiator = initiator - self.state = state - self.presentation_request = presentation_request - self.presentation = presentation - self.verified = verified - self.error_msg = error_msg - - @property - def presentation_exchange_id(self) -> str: - """Accessor for the ID associated with this exchange.""" - return self._id - - @property - def record_value(self) -> dict: - """Accessor for JSON record value generated for this presentation exchange.""" - return { - prop: getattr(self, prop) - for prop in ( - "connection_id", - "initiator", - "presentation_request", - "presentation", - "error_msg", - "verified", - "state", - ) - } - - -class PresentationExchangeSchema(BaseRecordSchema): - """Schema for serialization/deserialization of presentation exchange records.""" - - class Meta: - """PresentationExchangeSchema metadata.""" - - model_class = PresentationExchange - - presentation_exchange_id = fields.Str(required=False) - connection_id = fields.Str(required=False) - thread_id = fields.Str(required=False) - initiator = fields.Str(required=False) - state = fields.Str(required=False) - presentation_request = fields.Dict(required=False) - presentation = fields.Dict(required=False) - verified = fields.Str(required=False) - error_msg = fields.Str(required=False) diff --git a/aries_cloudagent/protocols/presentations/routes.py b/aries_cloudagent/protocols/presentations/routes.py deleted file mode 100644 index 7254ad2e4b..0000000000 --- a/aries_cloudagent/protocols/presentations/routes.py +++ /dev/null @@ -1,426 +0,0 @@ -"""Admin routes for presentations.""" - -import json - -from aiohttp import web -from aiohttp_apispec import docs, request_schema, response_schema -from marshmallow import fields, Schema - -from ...holder.base import BaseHolder -from ...storage.error import StorageNotFoundError - -from .manager import PresentationManager -from .models.presentation_exchange import ( - PresentationExchange, - PresentationExchangeSchema, -) - - -class PresentationExchangeListSchema(Schema): - """Result schema for a presentation exchange query.""" - - results = fields.List(fields.Nested(PresentationExchangeSchema())) - - -class PresentationRequestRequestSchema(Schema): - """Request schema for sending a proof request.""" - - class RequestedAttribute(Schema): - """RequestedAttribute model.""" - - name = fields.Str(required=True) - restrictions = fields.List(fields.Dict(), required=False) - - class RequestedPredicate(Schema): - """RequestedPredicate model.""" - - name = fields.Str(required=True) - p_type = fields.Str(required=True) - p_value = fields.Str(required=True) - restrictions = fields.List(fields.Dict(), required=False) - - connection_id = fields.Str(required=True) - name = fields.String(required=True) - version = fields.String(required=True) - requested_attributes = fields.Nested(RequestedAttribute, many=True) - requested_predicates = fields.Nested(RequestedPredicate, many=True) - - -class SendPresentationRequestSchema(Schema): - """Request schema for sending a presentation.""" - - self_attested_attributes = fields.Dict(required=True) - requested_attributes = fields.Dict(required=True) - requested_predicates = fields.Dict(required=True) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Fetch all presentation exchange records", -) -@response_schema(PresentationExchangeListSchema(), 200) -async def presentation_exchange_list(request: web.BaseRequest): - """ - Request handler for searching presentation exchange records. - - Args: - request: aiohttp request object - - Returns: - The presentation exchange list response - - """ - context = request.app["request_context"] - tag_filter = {} - if "thread_id" in request.query and request.query["thread_id"] != "": - tag_filter["thread_id"] = request.query["thread_id"] - post_filter = {} - for param_name in ( - "connection_id", - "initiator", - "state", - ): - if param_name in request.query and request.query[param_name] != "": - post_filter[param_name] = request.query[param_name] - records = await PresentationExchange.query(context, tag_filter, post_filter) - return web.json_response({"results": [record.serialize() for record in records]}) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Fetch a single presentation exchange record", -) -@response_schema(PresentationExchangeSchema(), 200) -async def presentation_exchange_retrieve(request: web.BaseRequest): - """ - Request handler for fetching a single presentation exchange record. - - Args: - request: aiohttp request object - - Returns: - The presentation exchange record response - - """ - context = request.app["request_context"] - presentation_exchange_id = request.match_info["id"] - try: - record = await PresentationExchange.retrieve_by_id( - context, presentation_exchange_id - ) - except StorageNotFoundError: - raise web.HTTPNotFound() - return web.json_response(record.serialize()) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - parameters=[ - { - "name": "start", - "in": "query", - "schema": {"type": "string"}, - "required": False, - }, - { - "name": "count", - "in": "query", - "schema": {"type": "string"}, - "required": False, - }, - { - "name": "extra_query", - "in": "query", - "schema": {"type": "string"}, - "required": False, - }, - ], - summary="Fetch credentials for a presentation request from wallet", -) -# @response_schema(ConnectionListSchema(), 200) -async def presentation_exchange_credentials_list(request: web.BaseRequest): - """ - Request handler for searching applicable credential records. - - Args: - request: aiohttp request object - - Returns: - The credential list response - - """ - context = request.app["request_context"] - - presentation_exchange_id = request.match_info["id"] - presentation_referents = request.match_info.get("referent").split(",") - - try: - presentation_exchange_record = await PresentationExchange.retrieve_by_id( - context, presentation_exchange_id - ) - except StorageNotFoundError: - raise web.HTTPNotFound() - - start = request.query.get("start") - count = request.query.get("count") - - # url encoded json extra_query - encoded_extra_query = request.query.get("extra_query") or "{}" - extra_query = json.loads(encoded_extra_query) - - # defaults - start = int(start) if isinstance(start, str) else 0 - count = int(count) if isinstance(count, str) else 10 - - holder: BaseHolder = await context.inject(BaseHolder) - credentials = await holder.get_credentials_for_presentation_request_by_referent( - presentation_exchange_record.presentation_request, - presentation_referents, - start, - count, - extra_query, - ) - - presentation_exchange_record.log_state( - context, - "Retrieved presentation credentials", - { - "presentation_exchange_id": presentation_exchange_id, - "referents": presentation_referents, - "extra_query": extra_query, - "credentials": credentials, - }, - ) - - return web.json_response(credentials) - - -async def _create_request_helper(context, spec): - """Create a presentation request.""" - connection_id = spec.get("connection_id") - name = spec.get("name") - version = spec.get("version") - requested_attributes = spec.get("requested_attributes") - requested_predicates = spec.get("requested_predicates") - - presentation_manager = PresentationManager(context) - - ( - presentation_exchange_record, - presentation_request_message, - ) = await presentation_manager.create_request( - name, version, requested_attributes, requested_predicates, connection_id - ) - return presentation_exchange_record, presentation_request_message - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Creates a presentation request", -) -@request_schema(PresentationRequestRequestSchema()) -async def presentation_exchange_create_request(request: web.BaseRequest): - """ - Request handler for creating a presentation request. - - Args: - request: aiohttp request object - - Returns: - The presentation exchange details. - - """ - - context = request.app["request_context"] - - body = await request.json() - - ( - presentation_exchange_record, - presentation_request_message, - ) = await _create_request_helper(context, body) - - return web.json_response(presentation_exchange_record.serialize()) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Creates and sends a presentation request", -) -@request_schema(PresentationRequestRequestSchema()) -async def presentation_exchange_send_request(request: web.BaseRequest): - """ - Request handler for creating and sending a presentation request. - - Args: - request: aiohttp request object - - Returns: - The presentation exchange details. - - """ - - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - - body = await request.json() - - ( - presentation_exchange_record, - presentation_request_message, - ) = await _create_request_helper(context, body) - - await outbound_handler( - presentation_request_message, - connection_id=presentation_exchange_record.connection_id, - ) - - return web.json_response(presentation_exchange_record.serialize()) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Sends a credential presentation", -) -@request_schema(SendPresentationRequestSchema()) -@response_schema(PresentationExchangeSchema()) -async def presentation_exchange_send_credential_presentation(request: web.BaseRequest): - """ - Request handler for sending a credential presentation. - - Args: - request: aiohttp request object - - Returns: - The presentation exchange details. - - """ - - context = request.app["request_context"] - outbound_handler = request.app["outbound_message_router"] - presentation_exchange_id = request.match_info["id"] - - body = await request.json() - - presentation_exchange_record = await PresentationExchange.retrieve_by_id( - context, presentation_exchange_id - ) - connection_id = presentation_exchange_record.connection_id - - assert ( - presentation_exchange_record.state - == presentation_exchange_record.STATE_REQUEST_RECEIVED - ) - - presentation_manager = PresentationManager(context) - - ( - presentation_exchange_record, - presentation_message, - ) = await presentation_manager.create_presentation( - presentation_exchange_record, body - ) - - await outbound_handler(presentation_message, connection_id=connection_id) - return web.json_response(presentation_exchange_record.serialize()) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Verify a received credential presentation", -) -@response_schema(PresentationExchangeSchema()) -async def presentation_exchange_verify_credential_presentation( - request: web.BaseRequest, -): - """ - Request handler for verifying a presentation request. - - Args: - request: aiohttp request object - - Returns: - The presentation exchange details. - - """ - - context = request.app["request_context"] - presentation_exchange_id = request.match_info["id"] - - presentation_exchange_record = await PresentationExchange.retrieve_by_id( - context, presentation_exchange_id - ) - - assert ( - presentation_exchange_record.state - == presentation_exchange_record.STATE_PRESENTATION_RECEIVED - ) - - presentation_manager = PresentationManager(context) - - presentation_exchange_record = await presentation_manager.verify_presentation( - presentation_exchange_record - ) - - return web.json_response(presentation_exchange_record.serialize()) - - -@docs( - tags=["presentation_exchange *DEPRECATED*"], - summary="Remove an existing presentation exchange record", -) -async def presentation_exchange_remove(request: web.BaseRequest): - """ - Request handler for removing a presentation exchange record. - - Args: - request: aiohttp request object - """ - context = request.app["request_context"] - try: - presentation_exchange_id = request.match_info["id"] - presentation_exchange_record = await PresentationExchange.retrieve_by_id( - context, presentation_exchange_id - ) - except StorageNotFoundError: - raise web.HTTPNotFound() - await presentation_exchange_record.delete_record(context) - return web.json_response({}) - - -async def register(app: web.Application): - """Register routes.""" - - app.add_routes( - [ - web.get("/presentation_exchange", presentation_exchange_list), - web.get("/presentation_exchange/{id}", presentation_exchange_retrieve), - web.get( - "/presentation_exchange/{id}/credentials", - presentation_exchange_credentials_list, - ), - web.get( - "/presentation_exchange/{id}/credentials/{referent}", - presentation_exchange_credentials_list, - ), - web.post( - "/presentation_exchange/create_request", - presentation_exchange_create_request, - ), - web.post( - "/presentation_exchange/send_request", - presentation_exchange_send_request, - ), - web.post( - "/presentation_exchange/{id}/send_presentation", - presentation_exchange_send_credential_presentation, - ), - web.post( - "/presentation_exchange/{id}/verify_presentation", - presentation_exchange_verify_credential_presentation, - ), - web.post( - "/presentation_exchange/{id}/remove", presentation_exchange_remove - ), - ] - )