Skip to content

Commit 43cca6f

Browse files
sonivijaykVijay Soniswcurran
authored
fixed duplicate present-proof v2 webhook (#3998)
* fixed duplicate present-proof v2 webhook Signed-off-by: Vijay Soni <vijaysoni@sonivijay.com> * fixed sonar issues Signed-off-by: Vijay Soni <vijaysoni@sonivijay.com> * fixed linting err Signed-off-by: Vijay Soni <vijaysoni@sonivijay.com> * fixed test errors Signed-off-by: Vijay Soni <vijaysoni@sonivijay.com> * fixed JSON-LD regression test failure Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * Skipping BBS+ flow when not present Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * explicit key presence check in by_format, comment adjusted Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * added assertion to check 3 keys pres,pres_proposal, pres_request Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * corrected proof_request selection logic Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * corrected proof_request fallback logic Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * indy_present_proof_v2 logic Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * fixed util.py, examples Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> * fixed formatting linting issue Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> --------- Signed-off-by: Vijay Soni <vijaysoni@sonivijay.com> Signed-off-by: Vijay Kumar Soni <vijaysoni@sonivijay.com> Co-authored-by: Vijay Soni <vijaysoni@sonivijay.com> Co-authored-by: Stephen Curran <swcurran@gmail.com>
1 parent bc8e0e8 commit 43cca6f

File tree

9 files changed

+347
-54
lines changed

9 files changed

+347
-54
lines changed

acapy_agent/protocols/present_proof/v2_0/models/pres_exchange.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ async def emit_event(self, session: ProfileSession, payload: Optional[Any] = Non
206206
if not session.profile.settings.get("debug.webhooks"):
207207
payload = V20PresExRecordWebhook(**payload)
208208
payload = payload.__dict__
209+
elif by_format := payload.get("by_format"):
210+
# Issue #3802: remove legacy fields only when represented in by_format
211+
for key in ("pres_proposal", "pres_request", "pres"):
212+
if key in by_format:
213+
payload.pop(key, None)
209214

210215
await session.emit_event(topic, payload)
211216

acapy_agent/protocols/present_proof/v2_0/models/tests/test_record.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
from ......messaging.models.base_record import BaseExchangeRecord, BaseExchangeSchema
55
from ......tests import mock
66
from ......utils.testing import create_test_profile
7-
from ...message_types import ATTACHMENT_FORMAT, PRES_20_PROPOSAL
7+
from ...message_types import ATTACHMENT_FORMAT, PRES_20, PRES_20_PROPOSAL, PRES_20_REQUEST
8+
from ...messages.pres import V20Pres
89
from ...messages.pres_format import V20PresFormat
910
from ...messages.pres_proposal import V20PresProposal
11+
from ...messages.pres_request import V20PresRequest
1012
from .. import pres_exchange as test_module
1113
from ..pres_exchange import V20PresExRecord
1214

@@ -52,6 +54,16 @@
5254
}
5355
},
5456
}
57+
INDY_PROOF = {
58+
"proof": {"proofs": []},
59+
"requested_proof": {
60+
"revealed_attrs": {},
61+
"self_attested_attrs": {},
62+
"unrevealed_attrs": {},
63+
"predicates": {},
64+
},
65+
"identifiers": [],
66+
}
5567

5668

5769
class BasexRecordImpl(BaseExchangeRecord):
@@ -134,3 +146,71 @@ async def test_save_error_state(self):
134146
mock_save.side_effect = test_module.StorageError()
135147
await record.save_error_state(session, reason="testing")
136148
mock_log_exc.assert_called_once()
149+
150+
# BUG #3802: ensure webhook payloads omit legacy pres_* fields when by_format exists
151+
async def test_emit_event_strips_legacy_pres_fields(self):
152+
settings = {
153+
"wallet.type": "askar",
154+
"auto_provision": True,
155+
"wallet.key": "5BngFuBpS4wjFfVFCtPqoix3ZXG2XR8XJ7qosUzMak7R",
156+
"wallet.key_derivation_method": "RAW",
157+
"debug.webhooks": True,
158+
}
159+
self.profile = await create_test_profile(settings=settings)
160+
pres_request = V20PresRequest(
161+
formats=[
162+
V20PresFormat(
163+
attach_id="indy",
164+
format_=ATTACHMENT_FORMAT[PRES_20_REQUEST][
165+
V20PresFormat.Format.INDY.api
166+
],
167+
)
168+
],
169+
request_presentations_attach=[
170+
AttachDecorator.data_base64(mapping=INDY_PROOF_REQ, ident="indy")
171+
],
172+
)
173+
pres_proposal = V20PresProposal(
174+
formats=[
175+
V20PresFormat(
176+
attach_id="indy",
177+
format_=ATTACHMENT_FORMAT[PRES_20_PROPOSAL][
178+
V20PresFormat.Format.INDY.api
179+
],
180+
)
181+
],
182+
proposals_attach=[
183+
AttachDecorator.data_base64(mapping=INDY_PROOF_REQ, ident="indy")
184+
],
185+
)
186+
pres = V20Pres(
187+
formats=[
188+
V20PresFormat(
189+
attach_id="indy",
190+
format_=ATTACHMENT_FORMAT[PRES_20][V20PresFormat.Format.INDY.api],
191+
)
192+
],
193+
presentations_attach=[
194+
AttachDecorator.data_base64(mapping=INDY_PROOF, ident="indy")
195+
],
196+
)
197+
record = V20PresExRecord(
198+
pres_ex_id="pxid",
199+
thread_id="thid",
200+
connection_id="conn_id",
201+
initiator="init",
202+
role="role",
203+
state=V20PresExRecord.STATE_PRESENTATION_RECEIVED,
204+
pres_proposal=pres_proposal,
205+
pres_request=pres_request,
206+
pres=pres,
207+
)
208+
209+
async with self.profile.session() as session:
210+
session.emit_event = mock.CoroutineMock()
211+
await record.emit_event(session)
212+
213+
payload = session.emit_event.call_args.args[1]
214+
assert "by_format" in payload
215+
for key in ("pres", "pres_proposal", "pres_request"):
216+
assert key not in payload and key in payload["by_format"]

scenarios/examples/did_indy_issuance_and_revocation/example.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@
1818
didexchange,
1919
indy_anoncred_credential_artifacts,
2020
indy_issue_credential_v2,
21-
indy_present_proof_v2,
2221
params,
2322
)
2423
from aiohttp import ClientSession
24+
from examples.util import _presentation_request_payload, indy_present_proof_v2
2525

2626
ALICE = getenv("ALICE", "http://alice:3001")
2727
BOB = getenv("BOB", "http://bob:3001")
2828

2929

3030
def summary(presentation: V20PresExRecord) -> str:
3131
"""Summarize a presentation exchange record."""
32-
request = presentation.pres_request
32+
request = _presentation_request_payload(presentation)
3333
return "Summary: " + json.dumps(
3434
{
3535
"state": presentation.state,
3636
"verified": presentation.verified,
37-
"presentation_request": request.dict(by_alias=True) if request else None,
37+
"presentation_request": request,
3838
},
3939
indent=2,
4040
sort_keys=True,

scenarios/examples/json_ld/example.py

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
from uuid import uuid4
1111

1212
from acapy_controller import Controller
13+
from acapy_controller.controller import ControllerError
1314
from acapy_controller.logging import logging_to_stdout, pause_for_input, section
1415
from acapy_controller.models import DIDResult, V20PresExRecord
1516
from acapy_controller.protocols import (
1617
didexchange,
1718
jsonld_issue_credential,
18-
jsonld_present_proof,
1919
params,
2020
)
2121
from aiohttp import ClientSession
22+
from examples.util import jsonld_present_proof_v2
2223

2324
ALICE = getenv("ALICE", "http://alice:3001")
2425
BOB = getenv("BOB", "http://bob:3001")
@@ -159,7 +160,7 @@ async def main():
159160
pause_for_input()
160161

161162
with section("Present example ED25519 credential"):
162-
alice_pres_ex, bob_pres_ex = await jsonld_present_proof(
163+
alice_pres_ex, bob_pres_ex = await jsonld_present_proof_v2(
163164
alice,
164165
bob,
165166
alice_conn.connection_id,
@@ -207,7 +208,7 @@ async def main():
207208
domain="test-degree",
208209
)
209210
with section("Presentation summary", character="-"):
210-
print(presentation_summary(alice_pres_ex.into(V20PresExRecord)))
211+
print(presentation_summary(alice_pres_ex))
211212

212213
pause_for_input()
213214

@@ -241,7 +242,7 @@ async def main():
241242
pause_for_input()
242243

243244
with section("Present example P256 credential"):
244-
alice_pres_ex, bob_pres_ex = await jsonld_present_proof(
245+
alice_pres_ex, bob_pres_ex = await jsonld_present_proof_v2(
245246
alice,
246247
bob,
247248
alice_conn.connection_id,
@@ -294,7 +295,7 @@ async def main():
294295
domain="test-degree",
295296
)
296297
with section("Presentation summary", character="-"):
297-
print(presentation_summary(alice_pres_ex.into(V20PresExRecord)))
298+
print(presentation_summary(alice_pres_ex))
298299

299300
pause_for_input()
300301

@@ -327,7 +328,7 @@ async def main():
327328
pause_for_input()
328329

329330
with section("Present ED25519 quick context credential"):
330-
alice_pres_ex, bob_pres_ex = await jsonld_present_proof(
331+
alice_pres_ex, bob_pres_ex = await jsonld_present_proof_v2(
331332
alice,
332333
bob,
333334
alice_conn.connection_id,
@@ -370,42 +371,46 @@ async def main():
370371
domain="test-degree",
371372
)
372373
with section("Presentation summary", character="-"):
373-
print(presentation_summary(alice_pres_ex.into(V20PresExRecord)))
374+
print(presentation_summary(alice_pres_ex))
374375

375376
pause_for_input()
376377

377378
with section("Issue BBS+ Credential"):
378-
issuer_cred_ex, holder_cred_ex = await jsonld_issue_credential(
379-
alice,
380-
bob,
381-
alice_conn.connection_id,
382-
bob_conn.connection_id,
383-
credential={
384-
"@context": [
385-
"https://www.w3.org/2018/credentials/v1",
386-
{
387-
"ex": "https://example.com/examples#",
388-
"Employment": "ex:Employment",
389-
"dateHired": "ex:dateHired",
390-
"clearance": "ex:clearance",
379+
try:
380+
issuer_cred_ex, holder_cred_ex = await jsonld_issue_credential(
381+
alice,
382+
bob,
383+
alice_conn.connection_id,
384+
bob_conn.connection_id,
385+
credential={
386+
"@context": [
387+
"https://www.w3.org/2018/credentials/v1",
388+
{
389+
"ex": "https://example.com/examples#",
390+
"Employment": "ex:Employment",
391+
"dateHired": "ex:dateHired",
392+
"clearance": "ex:clearance",
393+
},
394+
],
395+
"type": ["VerifiableCredential", "Employment"],
396+
"issuer": bls_alice_did,
397+
"issuanceDate": str(date.today()),
398+
"credentialSubject": {
399+
"id": bls_bob_did,
400+
"dateHired": str(date.today()),
401+
"clearance": 1,
391402
},
392-
],
393-
"type": ["VerifiableCredential", "Employment"],
394-
"issuer": bls_alice_did,
395-
"issuanceDate": str(date.today()),
396-
"credentialSubject": {
397-
"id": bls_bob_did,
398-
"dateHired": str(date.today()),
399-
"clearance": 1,
400403
},
401-
},
402-
options={"proofType": "BbsBlsSignature2020"},
403-
)
404+
options={"proofType": "BbsBlsSignature2020"},
405+
)
406+
except ControllerError as err:
407+
print(f"Skipping BBS+ flow due to runtime capability/error: {err}")
408+
return
404409

405410
pause_for_input()
406411

407412
with section("Present BBS+ Credential with SD"):
408-
alice_pres_ex, bob_pres_ex = await jsonld_present_proof(
413+
alice_pres_ex, bob_pres_ex = await jsonld_present_proof_v2(
409414
alice,
410415
bob,
411416
alice_conn.connection_id,
@@ -447,7 +452,7 @@ async def main():
447452
domain="building-access",
448453
)
449454
with section("Presentation summary", character="-"):
450-
print(presentation_summary(alice_pres_ex.into(V20PresExRecord)))
455+
print(presentation_summary(alice_pres_ex))
451456

452457

453458
if __name__ == "__main__":

scenarios/examples/kanon_issuance_and_presentation/example.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from examples.util import (
2222
CredDefResultAnonCreds,
2323
SchemaResultAnonCreds,
24+
_presentation_request_payload,
2425
anoncreds_issue_credential_v2,
2526
anoncreds_present_proof_v2,
2627
)
@@ -31,12 +32,12 @@
3132

3233
def summary(presentation: V20PresExRecord) -> str:
3334
"""Summarize a presentation exchange record."""
34-
request = presentation.pres_request
35+
request = _presentation_request_payload(presentation)
3536
return "Summary: " + json.dumps(
3637
{
3738
"state": presentation.state,
3839
"verified": presentation.verified,
39-
"presentation_request": request.dict(by_alias=True) if request else None,
40+
"presentation_request": request,
4041
},
4142
indent=2,
4243
sort_keys=True,

scenarios/examples/multitenancy/example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
didexchange,
1515
indy_anoncred_credential_artifacts,
1616
indy_issue_credential_v2,
17-
indy_present_proof_v2,
1817
params,
1918
)
2019
from aiohttp import ClientSession
20+
from examples.util import indy_present_proof_v2
2121

2222
AGENCY = getenv("AGENCY", "http://agency:3001")
2323

scenarios/examples/presenting_revoked_credential/example.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@
1818
didexchange,
1919
indy_anoncred_credential_artifacts,
2020
indy_issue_credential_v2,
21-
indy_present_proof_v2,
2221
params,
2322
)
2423
from aiohttp import ClientSession
24+
from examples.util import _presentation_request_payload, indy_present_proof_v2
2525

2626
ALICE = getenv("ALICE", "http://alice:3001")
2727
BOB = getenv("BOB", "http://bob:3001")
2828

2929

3030
def summary(presentation: V20PresExRecord) -> str:
3131
"""Summarize a presentation exchange record."""
32-
request = presentation.pres_request
32+
request = _presentation_request_payload(presentation)
3333
return "Summary: " + json.dumps(
3434
{
3535
"state": presentation.state,
3636
"verified": presentation.verified,
37-
"presentation_request": request.dict(by_alias=True) if request else None,
37+
"presentation_request": request,
3838
},
3939
indent=2,
4040
sort_keys=True,

scenarios/examples/simple_restart/example.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
indy_anoncred_credential_artifacts,
1515
indy_anoncred_onboard,
1616
indy_issue_credential_v2,
17-
indy_present_proof_v2,
1817
)
19-
from examples.util import wait_until_healthy
18+
from examples.util import indy_present_proof_v2, wait_until_healthy
2019

2120
import docker
2221

0 commit comments

Comments
 (0)