From 82863f326d95025c4c01349a4c14b37e6ff6a1db Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Fri, 8 Jul 2022 09:13:22 +0200 Subject: [PATCH] fix(oob): support legacy prefix in attachments (#931) Signed-off-by: Timo Glastra --- .../core/src/modules/oob/OutOfBandModule.ts | 14 ++++---- .../src/utils/__tests__/messageType.test.ts | 32 +++++++++++++++---- packages/core/src/utils/messageType.ts | 21 ++++++++++-- packages/core/tests/oob.test.ts | 24 ++++++++++++++ 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/packages/core/src/modules/oob/OutOfBandModule.ts b/packages/core/src/modules/oob/OutOfBandModule.ts index 2bb731d97a..b38f77c7b1 100644 --- a/packages/core/src/modules/oob/OutOfBandModule.ts +++ b/packages/core/src/modules/oob/OutOfBandModule.ts @@ -595,9 +595,10 @@ export class OutOfBandModule { private async emitWithConnection(connectionRecord: ConnectionRecord, messages: PlaintextMessage[]) { const supportedMessageTypes = this.dispatcher.supportedMessageTypes - const plaintextMessage = messages.find((message) => - supportedMessageTypes.find((type) => supportsIncomingMessageType(parseMessageType(message['@type']), type)) - ) + const plaintextMessage = messages.find((message) => { + const parsedMessageType = parseMessageType(message['@type']) + return supportedMessageTypes.find((type) => supportsIncomingMessageType(parsedMessageType, type)) + }) if (!plaintextMessage) { throw new AriesFrameworkError('There is no message in requests~attach supported by agent.') @@ -620,9 +621,10 @@ export class OutOfBandModule { } const supportedMessageTypes = this.dispatcher.supportedMessageTypes - const plaintextMessage = messages.find((message) => - supportedMessageTypes.find((type) => supportsIncomingMessageType(parseMessageType(message['@type']), type)) - ) + const plaintextMessage = messages.find((message) => { + const parsedMessageType = parseMessageType(message['@type']) + return supportedMessageTypes.find((type) => supportsIncomingMessageType(parsedMessageType, type)) + }) if (!plaintextMessage) { throw new AriesFrameworkError('There is no message in requests~attach supported by agent.') diff --git a/packages/core/src/utils/__tests__/messageType.test.ts b/packages/core/src/utils/__tests__/messageType.test.ts index 39333d3315..13c818c1c2 100644 --- a/packages/core/src/utils/__tests__/messageType.test.ts +++ b/packages/core/src/utils/__tests__/messageType.test.ts @@ -128,28 +128,46 @@ describe('messageType', () => { const incomingMessageType = parseMessageType('https://didcomm.org/connections/1.0/request') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(true) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(true) }) test('returns true when the document uri, protocol name, major version all match and the minor version is higher than the expected minor version', () => { const incomingMessageType = parseMessageType('https://didcomm.org/connections/1.8/request') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(true) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(true) }) test('returns true when the document uri, protocol name, major version and minor version all match', () => { const incomingMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(true) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(true) + }) + + test('returns true when the protocol name, major version and minor version all match and the incoming message type is using the legacy did sov prefix', () => { + const incomingMessageType = parseMessageType('did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.4/request') + const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') + + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(true) + }) + + test('returns false when the protocol name, major version and minor version all match and the incoming message type is using the legacy did sov prefix but allowLegacyDidSovPrefixMismatch is set to false', () => { + const incomingMessageType = parseMessageType('did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.4/request') + const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') + + expect( + supportsIncomingMessageType(expectedMessageType, incomingMessageType, { + allowLegacyDidSovPrefixMismatch: false, + }) + ).toBe(false) }) test('returns false when the major version does not match', () => { const incomingMessageType = parseMessageType('https://didcomm.org/connections/2.4/request') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(false) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(false) const incomingMessageType2 = parseMessageType('https://didcomm.org/connections/2.0/request') const expectedMessageType2 = parseMessageType('https://didcomm.org/connections/1.4/request') @@ -161,21 +179,21 @@ describe('messageType', () => { const incomingMessageType = parseMessageType('https://didcomm.org/connections/1.4/proposal') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(false) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(false) }) test('returns false when the protocol name does not match', () => { const incomingMessageType = parseMessageType('https://didcomm.org/issue-credential/1.4/request') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(false) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(false) }) test('returns false when the document uri does not match', () => { const incomingMessageType = parseMessageType('https://my-protocol.org/connections/1.4/request') const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') - expect(supportsIncomingMessageType(expectedMessageType, incomingMessageType)).toBe(false) + expect(supportsIncomingMessageType(incomingMessageType, expectedMessageType)).toBe(false) }) }) diff --git a/packages/core/src/utils/messageType.ts b/packages/core/src/utils/messageType.ts index e43c7c4fe4..acac87978e 100644 --- a/packages/core/src/utils/messageType.ts +++ b/packages/core/src/utils/messageType.ts @@ -95,6 +95,10 @@ export function parseMessageType(messageType: string): ParsedMessageType { * - majorVersion * - messageName * + * If allowLegacyDidSovPrefixMismatch is true (default) it will allow for the case where the incoming message type still has the legacy + * did:sov:BzCbsNYhMrjHiqZDTUASHg;spec did prefix, but the expected message type does not. This only works for incoming messages with a prefix + * of did:sov:BzCbsNYhMrjHiqZDTUASHg;spec and the expected message type having a prefix value of https:/didcomm.org + * * @example * const incomingMessageType = parseMessageType('https://didcomm.org/connections/1.0/request') * const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.4/request') @@ -102,12 +106,25 @@ export function parseMessageType(messageType: string): ParsedMessageType { * // Returns true because the incoming message type is equal to the expected message type, except for * // the minor version, which is lower * const isIncomingMessageTypeSupported = supportsIncomingMessageType(incomingMessageType, expectedMessageType) + * + * @example + * const incomingMessageType = parseMessageType('did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/request') + * const expectedMessageType = parseMessageType('https://didcomm.org/connections/1.0/request') + * + * // Returns true because the incoming message type is equal to the expected message type, except for + * // the legacy did sov prefix. + * const isIncomingMessageTypeSupported = supportsIncomingMessageType(incomingMessageType, expectedMessageType) */ export function supportsIncomingMessageType( incomingMessageType: ParsedMessageType, - expectedMessageType: ParsedMessageType + expectedMessageType: ParsedMessageType, + { allowLegacyDidSovPrefixMismatch = true }: { allowLegacyDidSovPrefixMismatch?: boolean } = {} ) { - const documentUriMatches = expectedMessageType.documentUri === incomingMessageType.documentUri + const incomingDocumentUri = allowLegacyDidSovPrefixMismatch + ? replaceLegacyDidSovPrefix(incomingMessageType.documentUri) + : incomingMessageType.documentUri + + const documentUriMatches = expectedMessageType.documentUri === incomingDocumentUri const protocolNameMatches = expectedMessageType.protocolName === incomingMessageType.protocolName const majorVersionMatches = expectedMessageType.protocolMajorVersion === incomingMessageType.protocolMajorVersion const messageNameMatches = expectedMessageType.messageName === incomingMessageType.messageName diff --git a/packages/core/tests/oob.test.ts b/packages/core/tests/oob.test.ts index 78e083f395..b256a4849e 100644 --- a/packages/core/tests/oob.test.ts +++ b/packages/core/tests/oob.test.ts @@ -362,6 +362,30 @@ describe('out of band', () => { expect(aliceCredentialRecord.state).toBe(CredentialState.OfferReceived) }) + test('process credential offer requests with legacy did:sov prefix on message type based on OOB message', async () => { + const { message } = await faberAgent.credentials.createOffer(credentialTemplate) + + // we need to override the message type to use the legacy did:sov prefix + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + message.type = message.type.replace('https://didcomm.org', 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec') + const { outOfBandInvitation } = await faberAgent.oob.createInvitation({ + ...issueCredentialConfig, + messages: [message], + }) + + const urlMessage = outOfBandInvitation.toUrl({ domain: 'http://example.com' }) + + const aliceCredentialRecordPromise = waitForCredentialRecord(aliceAgent, { + state: CredentialState.OfferReceived, + threadId: message.threadId, + }) + await aliceAgent.oob.receiveInvitationFromUrl(urlMessage, receiveInvitationConfig) + + const aliceCredentialRecord = await aliceCredentialRecordPromise + expect(aliceCredentialRecord.state).toBe(CredentialState.OfferReceived) + }) + test('do not process requests when a connection is not ready', async () => { const eventListener = jest.fn() aliceAgent.events.on(AgentEventTypes.AgentMessageReceived, eventListener)