From 71a1c77c391c159fa483d9ae2c2b05ad20d9800d Mon Sep 17 00:00:00 2001 From: Berend Sliedrecht Date: Tue, 1 Oct 2024 16:12:40 +0200 Subject: [PATCH] feat: send and handle ack message Signed-off-by: Berend Sliedrecht --- example/src/credo/agent.ts | 2 +- example/src/credo/bleRequestProof.ts | 21 +++++--- example/src/credo/bleShareProof.ts | 53 ++++++++++--------- .../src/credo/utils/createBleProofMessage.ts | 2 +- 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/example/src/credo/agent.ts b/example/src/credo/agent.ts index afc2efe..6db49bc 100644 --- a/example/src/credo/agent.ts +++ b/example/src/credo/agent.ts @@ -36,7 +36,7 @@ export const setupAgent = async () => { id: 'react-native-ble-didcomm-agent', key: 'react-native-ble-didcomm-key', }, - logger: new ConsoleLogger(LogLevel.trace), + logger: new ConsoleLogger(LogLevel.off), }, modules: { askar: new AskarModule({ ariesAskar }), diff --git a/example/src/credo/bleRequestProof.ts b/example/src/credo/bleRequestProof.ts index d2b3d4c..e53defc 100644 --- a/example/src/credo/bleRequestProof.ts +++ b/example/src/credo/bleRequestProof.ts @@ -5,6 +5,7 @@ import { } from '@animo-id/react-native-ble-didcomm' import type { AnonCredsProofFormat } from '@credo-ts/anoncreds' import { + JsonTransformer, MessageReceiver, ProofEventTypes, type ProofExchangeRecord, @@ -57,7 +58,7 @@ export const bleRequestProof = async ({ ) const messageListener = startMessageReceiver(agent, peripheral) - await returnWhenProofReceived(proofRecordId, agent) + await returnWhenProofReceived(proofRecordId, agent, peripheral) messageListener.remove() return proofRecordId @@ -140,17 +141,21 @@ const startMessageReceiver = (agent: AppAgent, peripheral: Peripheral) => { }) } -const returnWhenProofReceived = (id: string, agent: AppAgent): Promise => { +const returnWhenProofReceived = (id: string, agent: AppAgent, peripheral: Peripheral): Promise => { return new Promise((resolve, reject) => { - const listener = ({ payload }: ProofStateChangedEvent) => { + const listener = async ({ payload: { proofRecord } }: ProofStateChangedEvent) => { const off = () => agent.events.off(ProofEventTypes.ProofStateChanged, listener) - if (payload.proofRecord.id === id) { - if (payload.proofRecord.state === ProofState.PresentationReceived) { + if (proofRecord.id === id) { + if (proofRecord.state === ProofState.PresentationReceived) { + const pp = agent.proofs.config.proofProtocols.find((x) => x.version === 'v2') + const { message } = await pp.acceptPresentation(agent.context, { proofRecord }) + const serializedMessage = JsonTransformer.serialize(message) + await peripheral.sendMessage(serializedMessage) off() - resolve(payload.proofRecord) - } else if ([ProofState.Abandoned, ProofState.Declined].includes(payload.proofRecord.state)) { + resolve(proofRecord) + } else if ([ProofState.Abandoned, ProofState.Declined].includes(proofRecord.state)) { off() - reject(new Error(`Proof could not be shared because it has been ${payload.proofRecord.state}`)) + reject(new Error(`Proof could not be shared because it has been ${proofRecord.state}`)) } } } diff --git a/example/src/credo/bleShareProof.ts b/example/src/credo/bleShareProof.ts index 329a3b4..518d213 100644 --- a/example/src/credo/bleShareProof.ts +++ b/example/src/credo/bleShareProof.ts @@ -5,6 +5,7 @@ import { } from '@animo-id/react-native-ble-didcomm' import { type Agent, + AutoAcceptProof, JsonTransformer, OutOfBandInvitation, ProofEventTypes, @@ -12,6 +13,7 @@ import { ProofRepository, ProofState, type ProofStateChangedEvent, + V2PresentationAckMessage, } from '@credo-ts/core' import { BleInboundTransport, BleOutboundTransport } from '@credo-ts/transport-ble' import type { AppAgent } from './agent' @@ -48,6 +50,9 @@ export const bleShareProof = async ({ await connectedNotifier(agent, central, onConnected) await shareProof(agent, central, serviceUuid) + + const proofExchangeRecord = await autoRespondToBleProofRequest(agent) + await ackListener(central, proofExchangeRecord.threadId) } catch (e) { if (e instanceof Error) { agent.config.logger.error(e.message, { cause: e }) @@ -133,8 +138,6 @@ const shareProof = async (agent: AppAgent, central: Central, serviceUuid: string const parsedMessage = JsonTransformer.deserialize(message, OutOfBandInvitation) - const responder = autoRespondToBleProofRequest(agent) - const routing = await agent.mediationRecipient.getRouting({ useDefaultMediator: false, }) @@ -143,10 +146,6 @@ const shareProof = async (agent: AppAgent, central: Central, serviceUuid: string routing: { ...routing, endpoints: [`ble://${serviceUuid}`] }, }) - const { id } = await responder - - await waitForSharedProof(id, agent) - receivedMessageListener.remove() resolve() }) @@ -155,6 +154,9 @@ const shareProof = async (agent: AppAgent, central: Central, serviceUuid: string const autoRespondToBleProofRequest = (agent: AppAgent): Promise => { return new Promise((resolve, reject) => { const listener = async ({ payload: { proofRecord } }: ProofStateChangedEvent) => { + console.log(`state: ${proofRecord.state}`) + const off = () => agent.events.off(ProofEventTypes.ProofStateChanged, listener) + if (proofRecord.state === ProofState.RequestReceived) { const formatData = await agent.proofs.getFormatData(proofRecord.id) @@ -163,35 +165,36 @@ const autoRespondToBleProofRequest = (agent: AppAgent): Promise(ProofEventTypes.ProofStateChanged, listener) }) } -const waitForSharedProof = (id: string, agent: AppAgent): Promise => - new Promise((resolve, reject) => { - const listener = ({ payload }: ProofStateChangedEvent) => { - const off = () => agent.events.off(ProofEventTypes.ProofStateChanged, listener) - if (payload.proofRecord.id === id) { - if (payload.proofRecord.state === ProofState.PresentationReceived) { - off() - resolve(payload.proofRecord) - } else if ([ProofState.Abandoned, ProofState.Declined].includes(payload.proofRecord.state)) { - off() - reject(new Error(`Proof could not be shared because it has been ${payload.proofRecord.state}`)) - } +// TODO: we could process the ack message here like is done in credo. +// would be better even to handle the message itself in credo, but it gets quite complex +const ackListener = (central: Central, expectedThreadId: string) => + new Promise((resolve, reject) => { + const listener = central.registerMessageListener(({ message }) => { + if (!message.includes('@type')) reject('received invalid message') + const ackMessage = JsonTransformer.deserialize(message, V2PresentationAckMessage) + if (ackMessage.threadId === expectedThreadId) { + listener.remove() + resolve() + } else { + reject('Received ack message with invalid thread id') + listener.remove() } - } - agent.events.on(ProofEventTypes.ProofStateChanged, listener) + }) }) diff --git a/example/src/credo/utils/createBleProofMessage.ts b/example/src/credo/utils/createBleProofMessage.ts index 49d4e97..6d2eafa 100644 --- a/example/src/credo/utils/createBleProofMessage.ts +++ b/example/src/credo/utils/createBleProofMessage.ts @@ -35,7 +35,7 @@ export const createBleProofRequestMessage = async ( const { proofRecord, message } = await agent.proofs.createRequest({ proofFormats: requestMessage, protocolVersion: 'v2', - autoAcceptProof: AutoAcceptProof.Always, + autoAcceptProof: AutoAcceptProof.Never, }) const routing = await agent.mediationRecipient.getRouting({ useDefaultMediator: false })