diff --git a/.changeset/loud-kiwis-bake.md b/.changeset/loud-kiwis-bake.md new file mode 100644 index 0000000000..c83046f163 --- /dev/null +++ b/.changeset/loud-kiwis-bake.md @@ -0,0 +1,7 @@ +--- +'@credo-ts/didcomm': minor +--- + +Now using did:peer:4 by default when creating DID Exchange Requests as response to an Out of Band invitation. + +It is possible to return to previous behaviour by manually setting `peerNumAlgoForDidExchangeRequests` option in DIDComm Connections module config. diff --git a/packages/core/tests/oob.test.ts b/packages/core/tests/oob.test.ts index 46356ff7f6..563cfdff81 100644 --- a/packages/core/tests/oob.test.ts +++ b/packages/core/tests/oob.test.ts @@ -766,8 +766,9 @@ describe('out of band', () => { expect(faberAliceConnection?.state).toBe(DidExchangeState.Completed) // Use the invitation did from the first connection to create the second connection + // (first connection's did matches the one used in invitation, since no rotation has been done (multiUse=false)) const outOfBandRecord2 = await faberAgent.modules.oob.createInvitation({ - invitationDid: outOfBandRecord1.outOfBandInvitation.invitationDids[0], + invitationDid: faberAliceConnection.did, }) let { connectionRecord: aliceFaberConnection2 } = await aliceAgent.modules.oob.receiveInvitation( diff --git a/packages/didcomm/src/modules/connections/ConnectionsModuleConfig.ts b/packages/didcomm/src/modules/connections/ConnectionsModuleConfig.ts index 0ea97be5dd..463a4fcce5 100644 --- a/packages/didcomm/src/modules/connections/ConnectionsModuleConfig.ts +++ b/packages/didcomm/src/modules/connections/ConnectionsModuleConfig.ts @@ -58,7 +58,7 @@ export class ConnectionsModuleConfig { /** See {@link ConnectionsModuleConfigOptions.peerNumAlgoForDidExchangeRequests} */ public get peerNumAlgoForDidExchangeRequests() { - return this.#peerNumAlgoForDidExchangeRequests ?? PeerDidNumAlgo.GenesisDoc + return this.#peerNumAlgoForDidExchangeRequests ?? PeerDidNumAlgo.ShortFormAndLongForm } /** See {@link ConnectionsModuleConfigOptions.peerNumAlgoForDidExchangeRequests} */ diff --git a/packages/didcomm/src/modules/connections/DidExchangeProtocol.ts b/packages/didcomm/src/modules/connections/DidExchangeProtocol.ts index ef73da90b4..ee943c5d14 100644 --- a/packages/didcomm/src/modules/connections/DidExchangeProtocol.ts +++ b/packages/didcomm/src/modules/connections/DidExchangeProtocol.ts @@ -31,6 +31,8 @@ import { tryParseDid, didKeyToInstanceOfKey, DidRepository, + didKeyToVerkey, + parseDid, } from '@credo-ts/core' import { Attachment, AttachmentData } from '../../decorators/attachment/Attachment' @@ -284,32 +286,33 @@ export class DidExchangeProtocol { const didDocument = await createPeerDidFromServices(agentContext, services, numAlgo) const message = new DidExchangeResponseMessage({ did: didDocument.id, threadId }) + // DID Rotate attachment should be signed with invitation keys + const invitationRecipientKeys = outOfBandRecord.outOfBandInvitation + .getInlineServices() + .map((s) => s.recipientKeys) + .reduce((acc, curr) => acc.concat(curr), []) + + // Consider also pure-DID services, used when DID Exchange is started with an implicit invitation or a public DID + for (const did of outOfBandRecord.outOfBandInvitation.getDidServices()) { + invitationRecipientKeys.push( + ...(await getDidDocumentForCreatedDid(agentContext, parseDid(did).did)).recipientKeys.map( + (key) => key.publicKeyBase58 + ) + ) + } + if (numAlgo === PeerDidNumAlgo.GenesisDoc) { message.didDoc = await this.createSignedAttachment( agentContext, didDocument.toJSON(), - Array.from( - new Set( - services - .map((s) => s.recipientKeys) - .reduce((acc, curr) => acc.concat(curr), []) - .map((key) => key.publicKeyBase58) - ) - ) + Array.from(new Set(invitationRecipientKeys.map(didKeyToVerkey))) ) } else { // We assume any other case is a resolvable did (e.g. did:peer:2 or did:peer:4) message.didRotate = await this.createSignedAttachment( agentContext, didDocument.id, - Array.from( - new Set( - services - .map((s) => s.recipientKeys) - .reduce((acc, curr) => acc.concat(curr), []) - .map((key) => key.publicKeyBase58) - ) - ) + Array.from(new Set(invitationRecipientKeys.map(didKeyToVerkey))) ) } @@ -462,6 +465,7 @@ export class DidExchangeProtocol { data: string | Record, verkeys: string[] ) { + this.logger.debug(`Creating signed attachment with keys ${JSON.stringify(verkeys)}`) const signedAttach = new Attachment({ mimeType: typeof data === 'string' ? undefined : 'application/json', data: new AttachmentData({ diff --git a/packages/didcomm/src/modules/connections/services/helpers.ts b/packages/didcomm/src/modules/connections/services/helpers.ts index b4e9886e67..4ded401273 100644 --- a/packages/didcomm/src/modules/connections/services/helpers.ts +++ b/packages/didcomm/src/modules/connections/services/helpers.ts @@ -132,12 +132,14 @@ export function routingToServices(routing: Routing): ResolvedDidCommService[] { } export async function getDidDocumentForCreatedDid(agentContext: AgentContext, did: string) { + // Ensure that the DID has been created by us const didRecord = await agentContext.dependencyManager.resolve(DidRepository).findCreatedDid(agentContext, did) - - if (!didRecord?.didDocument) { - throw new CredoError(`Could not get DidDocument for created did ${did}`) + if (!didRecord) { + throw new CredoError(`Could not find created did ${did}`) } - return didRecord.didDocument + + const didsApi = agentContext.dependencyManager.resolve(DidsApi) + return await didsApi.resolveDidDocument(did) } /** diff --git a/packages/didcomm/src/modules/oob/OutOfBandApi.ts b/packages/didcomm/src/modules/oob/OutOfBandApi.ts index 883f23a6e5..2f13d7a004 100644 --- a/packages/didcomm/src/modules/oob/OutOfBandApi.ts +++ b/packages/didcomm/src/modules/oob/OutOfBandApi.ts @@ -396,7 +396,7 @@ export class OutOfBandApi { const invitation = new OutOfBandInvitation({ id: config.did, - label: config.label ?? '', + label: config.alias ?? '', services: [config.did], handshakeProtocols, }) diff --git a/packages/didcomm/src/modules/oob/__tests__/implicit.test.ts b/packages/didcomm/src/modules/oob/__tests__/implicit.test.ts index 9aa8b01c08..6f48bc297f 100644 --- a/packages/didcomm/src/modules/oob/__tests__/implicit.test.ts +++ b/packages/didcomm/src/modules/oob/__tests__/implicit.test.ts @@ -46,8 +46,8 @@ const aliceAgentOptions = getInMemoryAgentOptions( ) describe('out of band implicit', () => { - let faberAgent: Agent - let aliceAgent: Agent + let faberAgent: Agent + let aliceAgent: Agent beforeAll(async () => { faberAgent = new Agent(faberAgentOptions) @@ -80,7 +80,7 @@ describe('out of band implicit', () => { let { connectionRecord: aliceFaberConnection } = await aliceAgent.modules.oob.receiveImplicitInvitation({ did: inMemoryDid, alias: 'Faber public', - label: 'Alice', + label: 'Custom Alice', handshakeProtocols: [HandshakeProtocol.DidExchange], }) @@ -96,8 +96,8 @@ describe('out of band implicit', () => { expect(aliceFaberConnection).toBeConnectedWith(faberAliceConnection) expect(faberAliceConnection).toBeConnectedWith(aliceFaberConnection) - expect(faberAliceConnection.theirLabel).toBe('Alice') - expect(aliceFaberConnection.alias).toBe('Faber public') + expect(faberAliceConnection.theirLabel).toBe('Custom Alice') + expect(aliceFaberConnection.theirLabel).toBe('Faber public') expect(aliceFaberConnection.invitationDid).toBe(inMemoryDid) // It is possible for an agent to check if it has already a connection to a certain public entity @@ -112,7 +112,6 @@ describe('out of band implicit', () => { let { connectionRecord: aliceFaberConnection } = await aliceAgent.modules.oob.receiveImplicitInvitation({ did: serviceUrl, alias: 'Faber public', - label: 'Alice', handshakeProtocols: [HandshakeProtocol.DidExchange], }) @@ -128,8 +127,8 @@ describe('out of band implicit', () => { expect(aliceFaberConnection).toBeConnectedWith(faberAliceConnection) expect(faberAliceConnection).toBeConnectedWith(aliceFaberConnection) - expect(faberAliceConnection.theirLabel).toBe('Alice') - expect(aliceFaberConnection.alias).toBe('Faber public') + expect(faberAliceConnection.theirLabel).toBe(aliceAgent.config.label) + expect(aliceFaberConnection.theirLabel).toBe('Faber public') expect(aliceFaberConnection.invitationDid).toBe(serviceUrl) // It is possible for an agent to check if it has already a connection to a certain public entity @@ -142,7 +141,6 @@ describe('out of band implicit', () => { let { connectionRecord: aliceFaberConnection } = await aliceAgent.modules.oob.receiveImplicitInvitation({ did: inMemoryDid, alias: 'Faber public', - label: 'Alice', handshakeProtocols: [HandshakeProtocol.Connections], }) @@ -158,8 +156,8 @@ describe('out of band implicit', () => { expect(aliceFaberConnection).toBeConnectedWith(faberAliceConnection) expect(faberAliceConnection).toBeConnectedWith(aliceFaberConnection) - expect(faberAliceConnection.theirLabel).toBe('Alice') - expect(aliceFaberConnection.alias).toBe('Faber public') + expect(faberAliceConnection.theirLabel).toBe(aliceAgent.config.label) + expect(aliceFaberConnection.theirLabel).toBe('Faber public') expect(aliceFaberConnection.invitationDid).toBe(inMemoryDid) // It is possible for an agent to check if it has already a connection to a certain public entity @@ -171,7 +169,6 @@ describe('out of band implicit', () => { aliceAgent.modules.oob.receiveImplicitInvitation({ did: 'did:sov:ZSEqSci581BDZCFPa29ScB', alias: 'Faber public', - label: 'Alice', handshakeProtocols: [HandshakeProtocol.DidExchange], }) ).rejects.toThrow(/Unable to resolve did/) @@ -183,7 +180,6 @@ describe('out of band implicit', () => { let { connectionRecord: aliceFaberConnection } = await aliceAgent.modules.oob.receiveImplicitInvitation({ did: inMemoryDid, alias: 'Faber public', - label: 'Alice', handshakeProtocols: [HandshakeProtocol.Connections], }) @@ -199,8 +195,8 @@ describe('out of band implicit', () => { expect(aliceFaberConnection).toBeConnectedWith(faberAliceConnection) expect(faberAliceConnection).toBeConnectedWith(aliceFaberConnection) - expect(faberAliceConnection.theirLabel).toBe('Alice') - expect(aliceFaberConnection.alias).toBe('Faber public') + expect(faberAliceConnection.theirLabel).toBe(aliceAgent.config.label) + expect(aliceFaberConnection.theirLabel).toBe('Faber public') expect(aliceFaberConnection.invitationDid).toBe(inMemoryDid) // Repeat implicit invitation procedure @@ -224,7 +220,7 @@ describe('out of band implicit', () => { expect(aliceFaberNewConnection).toBeConnectedWith(faberAliceNewConnection) expect(faberAliceNewConnection).toBeConnectedWith(aliceFaberNewConnection) expect(faberAliceNewConnection.theirLabel).toBe('Alice New') - expect(aliceFaberNewConnection.alias).toBe('Faber public New') + expect(aliceFaberNewConnection.theirLabel).toBe('Faber public New') expect(aliceFaberNewConnection.invitationDid).toBe(inMemoryDid) // Both connections will be associated to the same invitation did