@veramo/did-comm
Version:
Veramo messaging plugin implementing DIDComm v2.
222 lines • 8.83 kB
JavaScript
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