UNPKG

@veramo/did-comm

Version:

Veramo messaging plugin implementing DIDComm v2.

222 lines 8.83 kB
import { AbstractMessageHandler } from '@veramo/message-handler'; import Debug from 'debug'; import { v4 } from 'uuid'; import { DIDCommMessageMediaType } from '../types/message-types.js'; import { asArray } from '@veramo/utils'; const debug = Debug('veramo:did-comm:coordinate-mediation-message-handler'); /** * @beta This API may change without a BREAKING CHANGE notice. */ export const MEDIATE_REQUEST_MESSAGE_TYPE = 'https://didcomm.org/coordinate-mediation/2.0/mediate-request'; /** * @beta This API may change without a BREAKING CHANGE notice. */ export const MEDIATE_GRANT_MESSAGE_TYPE = 'https://didcomm.org/coordinate-mediation/2.0/mediate-grant'; /** * @beta This API may change without a BREAKING CHANGE notice. */ export const MEDIATE_DENY_MESSAGE_TYPE = 'https://didcomm.org/coordinate-mediation/2.0/mediate-deny'; /** * @beta This API may change without a BREAKING CHANGE notice. */ export const STATUS_REQUEST_MESSAGE_TYPE = 'https://didcomm.org/messagepickup/3.0/status-request'; /** * @beta This API may change without a BREAKING CHANGE notice. */ export const DELIVERY_REQUEST_MESSAGE_TYPE = 'https://didcomm.org/messagepickup/3.0/delivery-request'; /** * @beta This API may change without a BREAKING CHANGE notice. */ export function createMediateRequestMessage(recipientDidUrl, mediatorDidUrl) { return { type: MEDIATE_REQUEST_MESSAGE_TYPE, from: recipientDidUrl, to: [mediatorDidUrl], id: v4(), return_route: 'all', created_time: (new Date()).toISOString(), body: {}, }; } /** * @beta This API may change without a BREAKING CHANGE notice. */ export function createMediateGrantMessage(recipientDidUrl, mediatorDidUrl, thid) { return { type: MEDIATE_GRANT_MESSAGE_TYPE, from: mediatorDidUrl, to: [recipientDidUrl], id: v4(), thid: thid, created_time: (new Date()).toISOString(), body: { routing_did: [mediatorDidUrl], }, }; } /** * @beta This API may change without a BREAKING CHANGE notice. */ export function createStatusRequestMessage(recipientDidUrl, mediatorDidUrl) { return { id: v4(), type: STATUS_REQUEST_MESSAGE_TYPE, to: [mediatorDidUrl], from: recipientDidUrl, return_route: 'all', body: {}, }; } /** * @beta This API may change without a BREAKING CHANGE notice. */ export function createDeliveryRequestMessage(recipientDidUrl, mediatorDidUrl) { return { id: v4(), type: DELIVERY_REQUEST_MESSAGE_TYPE, to: [mediatorDidUrl], from: recipientDidUrl, return_route: 'all', body: { limit: 2 }, }; } /** * A plugin for the {@link @veramo/message-handler#MessageHandler} that handles Mediator Coordinator messages for the mediator role. * @beta This API may change without a BREAKING CHANGE notice. */ export class CoordinateMediationMediatorMessageHandler extends AbstractMessageHandler { constructor() { super(); } /** * Handles a Mediator Coordinator messages for the mediator role * https://didcomm.org/mediator-coordination/2.0/ */ async handle(message, context) { if (message.type === MEDIATE_REQUEST_MESSAGE_TYPE) { debug('MediateRequest Message Received'); try { const { from, to, returnRoute } = message; if (!from) { throw new Error('invalid_argument: MediateRequest received without `from` set'); } if (!to) { throw new Error('invalid_argument: MediateRequest received without `to` set'); } if (returnRoute === 'all') { // Grant requests to all recipients // TODO: Come up with another method for approving and rejecting recipients const response = createMediateGrantMessage(from, to, message.id); const packedResponse = await context.agent.packDIDCommMessage({ message: response, packing: 'authcrypt', }); const returnResponse = { id: response.id, message: packedResponse.message, contentType: DIDCommMessageMediaType.ENCRYPTED, }; message.addMetaData({ type: 'ReturnRouteResponse', value: JSON.stringify(returnResponse) }); // Save message to track recipients await context.agent.dataStoreSaveMessage({ message: { type: response.type, from: response.from, to: asArray(response.to)[0], id: response.id, threadId: response.thid, data: response.body, createdAt: response.created_time }, }); } } catch (ex) { debug(ex); } return message; } return super.handle(message, context); } } /** * A plugin for the {@link @veramo/message-handler#MessageHandler} that handles Mediator Coordinator messages for the recipient role. * @beta This API may change without a BREAKING CHANGE notice. */ export class CoordinateMediationRecipientMessageHandler extends AbstractMessageHandler { constructor() { super(); } /** * Handles a Mediator Coordinator messages for the recipient role * https://didcomm.org/mediator-coordination/2.0/ */ async handle(message, context) { if (message.type === MEDIATE_GRANT_MESSAGE_TYPE) { debug('MediateGrant Message Received'); try { const { from, to, data, threadId } = message; if (!from) { throw new Error('invalid_argument: MediateGrant received without `from` set'); } if (!to) { throw new Error('invalid_argument: MediateGrant received without `to` set'); } if (!threadId) { throw new Error('invalid_argument: MediateGrant received without `thid` set'); } if (!data.routing_did || data.routing_did.length === 0) { throw new Error('invalid_argument: MediateGrant received with invalid routing_did'); } // If mediate request was previously sent, add service to DID document const prevRequestMsg = await context.agent.dataStoreGetMessage({ id: threadId }); if (prevRequestMsg.from === to && prevRequestMsg.to === from) { const service = { id: 'didcomm-mediator', type: 'DIDCommMessaging', serviceEndpoint: [ { uri: data.routing_did[0], }, ], }; await context.agent.didManagerAddService({ did: to, service: service, }); message.addMetaData({ type: 'DIDCommMessagingServiceAdded', value: JSON.stringify(service) }); } } catch (ex) { debug(ex); } return message; } else if (message.type === MEDIATE_DENY_MESSAGE_TYPE) { debug('MediateDeny Message Received'); try { const { from, to } = message; if (!from) { throw new Error('invalid_argument: MediateGrant received without `from` set'); } if (!to) { throw new Error('invalid_argument: MediateGrant received without `to` set'); } // Delete service if it exists const did = await context.agent.didManagerGet({ did: to, }); const existingService = did.services.find((s) => s.serviceEndpoint === from || (Array.isArray(s.serviceEndpoint) && s.serviceEndpoint.includes(from))); if (existingService) { await context.agent.didManagerRemoveService({ did: to, id: existingService.id }); } } catch (ex) { debug(ex); } } return super.handle(message, context); } } //# sourceMappingURL=coordinate-mediation-message-handler.js.map