Skip to content

Commit bb55f8e

Browse files
Support ADA RFC 005 Data Agreement Termination protcol
Signed-off-by: George J Padayatti <[email protected]>
1 parent 311edbc commit bb55f8e

12 files changed

+1182
-14
lines changed

mydata_did/patched_protocols/issue_credential/v1_0/routes.py

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
from aries_cloudagent.wallet.error import WalletError
3434
from aries_cloudagent.utils.outofband import serialize_outofband
3535
from aries_cloudagent.utils.tracing import trace_event, get_timer, AdminAPIMessageTracingSchema
36+
from aries_cloudagent.wallet.indy import IndyWallet
37+
from aries_cloudagent.wallet.base import BaseWallet
3638

3739
from aries_cloudagent.protocols.problem_report.v1_0 import internal_error
3840
from aries_cloudagent.protocols.problem_report.v1_0.message import ProblemReport
@@ -57,7 +59,9 @@
5759
from ....v1_0.models.data_agreement_negotiation_offer_model import DataAgreementNegotiationOfferBody, DataAgreementNegotiationOfferBodySchema
5860
from ....v1_0.manager import ADAManager, ADAManagerError
5961
from ....v1_0.models.data_agreement_negotiation_offer_model import DataAgreementNegotiationOfferBody, DataAgreementNegotiationOfferBodySchema
60-
62+
from ....v1_0.models.data_agreement_instance_model import DataAgreementInstance, DataAgreementInstanceSchema
63+
from ....v1_0.utils.did.mydata_did import DIDMyData
64+
from ....v1_0.utils.wallet.key_type import KeyType
6165

6266
class V10CredentialExchangeListQueryStringSchema(OpenAPISchema):
6367
"""Parameters and validators for credential exchange list query."""
@@ -1613,6 +1617,96 @@ async def send_data_agreement_negotiation_problem_report(request: web.BaseReques
16131617
return web.json_response({})
16141618

16151619

1620+
@docs(
1621+
tags=["issue-credential"], summary="Send data agreement termination message."
1622+
)
1623+
@match_info_schema(CredExIdMatchInfoSchema())
1624+
@response_schema(V10CredentialExchangeSchema(), 200)
1625+
async def send_data_agreement_termination_message(request: web.BaseRequest):
1626+
"""
1627+
Request handler for sending data agreement termination message.
1628+
1629+
Args:
1630+
request: aiohttp request object
1631+
1632+
"""
1633+
1634+
# Initialize request context
1635+
context = request.app["request_context"]
1636+
1637+
# Initialize outbound handler
1638+
outbound_handler = request.app["outbound_message_router"]
1639+
1640+
# Path parameters
1641+
credential_exchange_id = request.match_info["cred_ex_id"]
1642+
1643+
cred_ex_record = None
1644+
try:
1645+
# Fetch credential exchange record
1646+
cred_ex_record: V10CredentialExchange = await V10CredentialExchange.retrieve_by_id(
1647+
context, credential_exchange_id
1648+
)
1649+
except StorageNotFoundError as err:
1650+
raise web.HTTPNotFound(reason=err.roll_up) from err
1651+
1652+
if not cred_ex_record.data_agreement:
1653+
raise web.HTTPBadRequest(reason=f"Data agreement is not available.")
1654+
1655+
if not cred_ex_record.data_agreement_status == V10CredentialExchange.DATA_AGREEMENT_ACCEPT:
1656+
raise web.HTTPBadRequest(
1657+
reason=f"Data agreement must be in accept state to terminate it."
1658+
)
1659+
1660+
# Send data agreement terminate message
1661+
1662+
data_agreement_instance: DataAgreementInstance = DataAgreementInstanceSchema().load(
1663+
cred_ex_record.data_agreement
1664+
)
1665+
1666+
# Initialize ADA manager
1667+
ada_manager = ADAManager(context)
1668+
1669+
connection_record = None
1670+
connection_id = cred_ex_record.connection_id
1671+
try:
1672+
connection_record = await ConnectionRecord.retrieve_by_id(
1673+
context, connection_id
1674+
)
1675+
if not connection_record.is_ready:
1676+
raise web.HTTPForbidden(
1677+
reason=f"Connection {connection_id} not ready")
1678+
1679+
# Fetch wallet from context
1680+
wallet: IndyWallet = await context.inject(BaseWallet)
1681+
1682+
pairwise_local_did_record = await wallet.get_local_did(connection_record.my_did)
1683+
principle_did = DIDMyData.from_public_key_b58(
1684+
pairwise_local_did_record.verkey, key_type=KeyType.ED25519)
1685+
1686+
if data_agreement_instance.principle_did != principle_did.did:
1687+
raise web.HTTPBadRequest(
1688+
reason=f"Only the principle can terminate the data agreement."
1689+
)
1690+
1691+
1692+
(data_agreement_instance, data_agreement_terminate_message) = await ada_manager.construct_data_agreement_termination_terminate_message(
1693+
data_agreement_instance=data_agreement_instance,
1694+
connection_record=connection_record,
1695+
)
1696+
1697+
# Update credential exchange record with data agreement
1698+
cred_ex_record.data_agreement = data_agreement_instance.serialize()
1699+
cred_ex_record.data_agreement_status = V10CredentialExchange.DATA_AGREEMENT_TERMINATE
1700+
1701+
await cred_ex_record.save(context)
1702+
1703+
await outbound_handler(data_agreement_terminate_message, connection_id=cred_ex_record.connection_id)
1704+
1705+
except (ADAManagerError,StorageError) as err:
1706+
raise web.HTTPBadRequest(reason=err.roll_up) from err
1707+
1708+
return web.json_response(cred_ex_record.serialize())
1709+
16161710
async def register(app: web.Application):
16171711
"""Register routes."""
16181712

@@ -1668,6 +1762,11 @@ async def register(app: web.Application):
16681762
send_data_agreement_negotiation_problem_report,
16691763
),
16701764

1765+
web.post(
1766+
"/issue-credential/records/{cred_ex_id}/data-agreement-termination/terminate",
1767+
send_data_agreement_termination_message,
1768+
),
1769+
16711770
]
16721771
)
16731772

mydata_did/patched_protocols/present_proof/v1_0/routes.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
request_schema,
1111
response_schema,
1212
)
13+
from aries_cloudagent.wallet.base import BaseWallet
14+
from aries_cloudagent.wallet.indy import IndyWallet
1315
from marshmallow import fields, validate, validates_schema
1416
from marshmallow.exceptions import ValidationError
1517

@@ -57,7 +59,10 @@
5759
from ....v1_0.models.data_agreement_negotiation_offer_model import DataAgreementNegotiationOfferBody, DataAgreementNegotiationOfferBodySchema
5860
from ....v1_0.manager import ADAManager, ADAManagerError
5961
from ....v1_0.models.data_agreement_negotiation_offer_model import DataAgreementNegotiationOfferBody, DataAgreementNegotiationOfferBodySchema
62+
from ....v1_0.models.data_agreement_instance_model import DataAgreementInstance, DataAgreementInstanceSchema
6063
from ....patched_protocols.issue_credential.v1_0.routes import SendDataAgreementNegotiationProblemReportRequestSchema
64+
from ....v1_0.utils.did.mydata_did import DIDMyData
65+
from ....v1_0.utils.wallet.key_type import KeyType
6166

6267
class V10PresentationExchangeListQueryStringSchema(OpenAPISchema):
6368
"""Parameters and validators for presentation exchange list query."""
@@ -1437,6 +1442,97 @@ async def send_data_agreement_negotiation_problem_report(request: web.BaseReques
14371442

14381443
return web.json_response({})
14391444

1445+
1446+
@docs(
1447+
tags=["present-proof"], summary="Send data agreement termination message."
1448+
)
1449+
@match_info_schema(PresExIdMatchInfoSchema())
1450+
@response_schema(V10PresentationExchangeSchema(), 200)
1451+
async def send_data_agreement_termination_message(request: web.BaseRequest):
1452+
"""
1453+
Request handler for sending data agreement termination message.
1454+
1455+
Args:
1456+
request: aiohttp request object
1457+
1458+
"""
1459+
1460+
# Initialize request context
1461+
context = request.app["request_context"]
1462+
1463+
# Initialize outbound handler
1464+
outbound_handler = request.app["outbound_message_router"]
1465+
1466+
# Path parameters
1467+
presentation_exchange_id = request.match_info["pres_ex_id"]
1468+
1469+
pres_ex_record = None
1470+
try:
1471+
# Fetch presentation exchange record
1472+
pres_ex_record: V10PresentationExchange = await V10PresentationExchange.retrieve_by_id(
1473+
context, presentation_exchange_id
1474+
)
1475+
except StorageNotFoundError as err:
1476+
raise web.HTTPNotFound(reason=err.roll_up) from err
1477+
1478+
if not pres_ex_record.data_agreement:
1479+
raise web.HTTPBadRequest(reason=f"Data agreement is not available.")
1480+
1481+
if not pres_ex_record.data_agreement_status == V10PresentationExchange.DATA_AGREEMENT_ACCEPT:
1482+
raise web.HTTPBadRequest(
1483+
reason=f"Data agreement must be in accept state to terminate it."
1484+
)
1485+
1486+
# Send data agreement terminate message
1487+
1488+
data_agreement_instance: DataAgreementInstance = DataAgreementInstanceSchema().load(
1489+
pres_ex_record.data_agreement
1490+
)
1491+
1492+
# Initialize ADA manager
1493+
ada_manager = ADAManager(context)
1494+
1495+
connection_record = None
1496+
connection_id = pres_ex_record.connection_id
1497+
try:
1498+
connection_record = await ConnectionRecord.retrieve_by_id(
1499+
context, connection_id
1500+
)
1501+
if not connection_record.is_ready:
1502+
raise web.HTTPForbidden(
1503+
reason=f"Connection {connection_id} not ready")
1504+
1505+
# Fetch wallet from context
1506+
wallet: IndyWallet = await context.inject(BaseWallet)
1507+
1508+
pairwise_local_did_record = await wallet.get_local_did(connection_record.my_did)
1509+
principle_did = DIDMyData.from_public_key_b58(
1510+
pairwise_local_did_record.verkey, key_type=KeyType.ED25519)
1511+
1512+
if data_agreement_instance.principle_did != principle_did.did:
1513+
raise web.HTTPBadRequest(
1514+
reason=f"Only the principle can terminate the data agreement."
1515+
)
1516+
1517+
1518+
(data_agreement_instance, data_agreement_terminate_message) = await ada_manager.construct_data_agreement_termination_terminate_message(
1519+
data_agreement_instance=data_agreement_instance,
1520+
connection_record=connection_record,
1521+
)
1522+
1523+
# Update presentation exchange record with data agreement
1524+
pres_ex_record.data_agreement = data_agreement_instance.serialize()
1525+
pres_ex_record.data_agreement_status = V10PresentationExchange.DATA_AGREEMENT_TERMINATE
1526+
1527+
await pres_ex_record.save(context)
1528+
1529+
await outbound_handler(data_agreement_terminate_message, connection_id=pres_ex_record.connection_id)
1530+
1531+
except (ADAManagerError,StorageError) as err:
1532+
raise web.HTTPBadRequest(reason=err.roll_up) from err
1533+
1534+
return web.json_response(pres_ex_record.serialize())
1535+
14401536
async def register(app: web.Application):
14411537
"""Register routes."""
14421538

@@ -1495,6 +1591,10 @@ async def register(app: web.Application):
14951591
"/present-proof/records/{pres_ex_id}/data-agreement-negotiation/problem-report",
14961592
send_data_agreement_negotiation_problem_report,
14971593
),
1594+
web.post(
1595+
"/present-proof/records/{pres_ex_id}/data-agreement-termination/terminate",
1596+
send_data_agreement_termination_message,
1597+
),
14981598
]
14991599
)
15001600

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Presentation ack message handler."""
2+
import json
3+
4+
from aries_cloudagent.messaging.base_handler import (
5+
BaseHandler,
6+
BaseResponder,
7+
HandlerException,
8+
RequestContext,
9+
)
10+
11+
from ..messages.data_agreement_terminate_ack import DataAgreementTerminationAck
12+
13+
14+
class DataAgreementTerminationAckHandler(BaseHandler):
15+
"""Message handler class for data agreement terminate acks."""
16+
17+
async def handle(self, context: RequestContext, responder: BaseResponder):
18+
"""
19+
Message handler logic for data agreement terminate acks.
20+
21+
Args:
22+
context: request context
23+
responder: responder callback
24+
"""
25+
26+
self._logger.debug("DataAgreementTerminationAckHandler called with context %s", context)
27+
28+
assert isinstance(context.message, DataAgreementTerminationAck)
29+
30+
self._logger.info(
31+
"Received data agreement terminate ack message: %s",
32+
json.dumps(context.message.serialize(), indent=4),
33+
)

0 commit comments

Comments
 (0)