Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: process problem report message #1859

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ export class V1CredentialProtocol
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage,
lastSentMessage,
expectedConnectionId: credentialRecord.connectionId,
})

await this.indyCredentialFormat.processProposal(messageContext.agentContext, {
Expand All @@ -251,6 +252,8 @@ export class V1CredentialProtocol
})
} else {
agentContext.config.logger.debug('Credential record does not exists yet for incoming proposal')
// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

// No credential record exists with thread id
credentialRecord = new CredentialExchangeRecord({
Expand All @@ -261,9 +264,6 @@ export class V1CredentialProtocol
protocolVersion: 'v1',
})

// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

// Save record
await credentialRepository.save(messageContext.agentContext, credentialRecord)
this.emitStateChangedEvent(messageContext.agentContext, credentialRecord, null)
Expand Down Expand Up @@ -532,6 +532,7 @@ export class V1CredentialProtocol
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage,
lastSentMessage,
expectedConnectionId: credentialRecord.connectionId,
})

await this.indyCredentialFormat.processOffer(messageContext.agentContext, {
Expand All @@ -548,6 +549,9 @@ export class V1CredentialProtocol

return credentialRecord
} else {
// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

// No credential record exists with thread id
credentialRecord = new CredentialExchangeRecord({
connectionId: connection?.id,
Expand All @@ -558,9 +562,6 @@ export class V1CredentialProtocol
protocolVersion: 'v1',
})

// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

await this.indyCredentialFormat.processOffer(messageContext.agentContext, {
credentialRecord,
attachment: offerAttachment,
Expand Down Expand Up @@ -767,14 +768,14 @@ export class V1CredentialProtocol
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: proposalMessage ?? undefined,
lastSentMessage: offerMessage ?? undefined,
expectedConnectionId: credentialRecord.connectionId,
})

// This makes sure that the sender of the incoming message is authorized to do so.
if (!credentialRecord.connectionId) {
await connectionService.matchIncomingMessageToRequestMessageInOutOfBandExchange(messageContext, {
expectedConnectionId: credentialRecord.connectionId,
})

credentialRecord.connectionId = connection?.id
}

Expand Down Expand Up @@ -916,6 +917,7 @@ export class V1CredentialProtocol
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: offerCredentialMessage,
lastSentMessage: requestCredentialMessage,
expectedConnectionId: credentialRecord.connectionId,
})

const issueAttachment = issueMessage.getCredentialAttachmentById(INDY_CREDENTIAL_ATTACHMENT_ID)
Expand Down Expand Up @@ -1022,6 +1024,7 @@ export class V1CredentialProtocol
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: requestCredentialMessage,
lastSentMessage: issueCredentialMessage,
expectedConnectionId: credentialRecord.connectionId,
})

// Update record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,6 @@ describe('V1CredentialProtocol', () => {
}
expect(credentialRepository.getSingleByQuery).toHaveBeenNthCalledWith(1, agentContext, {
threadId: 'somethreadid',
connectionId: connection.id,
})
expect(repositoryUpdateSpy).toHaveBeenCalledTimes(1)
const [[, updatedCredentialRecord]] = repositoryUpdateSpy.mock.calls
Expand Down
15 changes: 9 additions & 6 deletions packages/anoncreds/src/protocols/proofs/v1/V1ProofProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage,
lastSentMessage,
expectedConnectionId: proofRecord.connectionId,
})

// Update record
Expand All @@ -209,6 +210,8 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
await this.updateState(agentContext, proofRecord, ProofState.ProposalReceived)
} else {
agentContext.config.logger.debug('Proof record does not exist yet for incoming proposal')
// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

// No proof record exists with thread id
proofRecord = new ProofExchangeRecord({
Expand All @@ -220,9 +223,6 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
protocolVersion: 'v1',
})

// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

await didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, {
agentMessage: proposalMessage,
associatedRecordId: proofRecord.id,
Expand Down Expand Up @@ -456,6 +456,7 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage,
lastSentMessage,
expectedConnectionId: proofRecord.connectionId,
})

await this.indyProofFormat.processRequest(agentContext, {
Expand All @@ -470,6 +471,9 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
})
await this.updateState(agentContext, proofRecord, ProofState.RequestReceived)
} else {
// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

// No proof record exists with thread id
proofRecord = new ProofExchangeRecord({
connectionId: connection?.id,
Expand All @@ -491,9 +495,6 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
role: DidCommMessageRole.Receiver,
})

// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext)

// Save in repository
await proofRepository.save(agentContext, proofRecord)
this.emitStateChangedEvent(agentContext, proofRecord, null)
Expand Down Expand Up @@ -791,6 +792,7 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: proposalMessage,
lastSentMessage: requestMessage,
expectedConnectionId: proofRecord.connectionId,
})

// This makes sure that the sender of the incoming message is authorized to do so.
Expand Down Expand Up @@ -922,6 +924,7 @@ export class V1ProofProtocol extends BaseProofProtocol implements ProofProtocol<
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage,
lastSentMessage,
expectedConnectionId: proofRecord.connectionId,
})

// Update record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ describe('V1ProofProtocol', () => {
}
expect(proofRepository.getSingleByQuery).toHaveBeenNthCalledWith(1, agentContext, {
threadId: 'somethreadid',
connectionId: connection.id,
})
expect(repositoryUpdateSpy).toHaveBeenCalledTimes(1)
const [[, updatedCredentialRecord]] = repositoryUpdateSpy.mock.calls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,35 @@ describe('ConnectionService', () => {
})

describe('assertConnectionOrOutOfBandExchange', () => {
it('should throw an error when a expectedConnectionId is present, but no connection is present in the messageContext', async () => {
expect.assertions(1)

const messageContext = new InboundMessageContext(new AgentMessage(), {
agentContext,
})

await expect(
connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
expectedConnectionId: '123',
})
).rejects.toThrow('Expected incoming message to be from connection 123 but no connection found.')
})

it('should throw an error when a expectedConnectionId is present, but does not match with connection id present in the messageContext', async () => {
expect.assertions(1)

const messageContext = new InboundMessageContext(new AgentMessage(), {
agentContext,
connection: getMockConnection({ state: DidExchangeState.InvitationReceived, id: 'something' }),
})

await expect(
connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
expectedConnectionId: 'something-else',
})
).rejects.toThrow('Expected incoming message to be from connection something-else but connection is something.')
})

it('should not throw an error when a connection record with state complete is present in the messageContext', async () => {
expect.assertions(1)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,13 +459,26 @@ export class ConnectionService {
{
lastSentMessage,
lastReceivedMessage,
expectedConnectionId,
}: {
lastSentMessage?: AgentMessage | null
lastReceivedMessage?: AgentMessage | null
expectedConnectionId?: string
} = {}
) {
const { connection, message } = messageContext

if (expectedConnectionId && !connection) {
throw new CredoError(
`Expected incoming message to be from connection ${expectedConnectionId} but no connection found.`
)
}
if (expectedConnectionId && connection?.id !== expectedConnectionId) {
throw new CredoError(
`Expected incoming message to be from connection ${expectedConnectionId} but connection is ${connection?.id}.`
)
}

// Check if we have a ready connection. Verification is already done somewhere else. Return
if (connection) {
connection.assertReady()
Expand Down Expand Up @@ -559,7 +572,7 @@ export class ConnectionService {
messageContext: InboundMessageContext,
{ expectedConnectionId }: { expectedConnectionId?: string }
) {
if (expectedConnectionId && messageContext.connection?.id === expectedConnectionId) {
if (expectedConnectionId && messageContext.connection?.id !== expectedConnectionId) {
throw new CredoError(
`Expecting incoming message to have connection ${expectedConnectionId}, but incoming connection is ${
messageContext.connection?.id ?? 'undefined'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type { CredentialExchangeRecord } from '../repository'

import { EventEmitter } from '../../../agent/EventEmitter'
import { DidCommMessageRepository } from '../../../storage/didcomm'
import { ConnectionService } from '../../connections'
import { CredentialEventTypes } from '../CredentialEvents'
import { CredentialState } from '../models/CredentialState'
import { CredentialRepository } from '../repository'
Expand Down Expand Up @@ -136,17 +137,30 @@ export abstract class BaseCredentialProtocol<CFs extends CredentialFormatService
public async processProblemReport(
messageContext: InboundMessageContext<ProblemReportMessage>
): Promise<CredentialExchangeRecord> {
const { message: credentialProblemReportMessage, agentContext } = messageContext
const { message: credentialProblemReportMessage, agentContext, connection } = messageContext

const connection = messageContext.assertReadyConnection()
const connectionService = agentContext.dependencyManager.resolve(ConnectionService)

agentContext.config.logger.debug(`Processing problem report with message id ${credentialProblemReportMessage.id}`)

const credentialRecord = await this.getByProperties(agentContext, {
threadId: credentialProblemReportMessage.threadId,
connectionId: connection.id,
})

// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
expectedConnectionId: credentialRecord.connectionId,
})

// This makes sure that the sender of the incoming message is authorized to do so.
if (!credentialRecord?.connectionId) {
await connectionService.matchIncomingMessageToRequestMessageInOutOfBandExchange(messageContext, {
expectedConnectionId: credentialRecord?.connectionId,
})

credentialRecord.connectionId = connection?.id
}

// Update record
credentialRecord.errorMessage = `${credentialProblemReportMessage.description.code}: ${credentialProblemReportMessage.description.en}`
await this.updateState(agentContext, credentialRecord, CredentialState.Abandoned)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export class V2CredentialProtocol<CFs extends CredentialFormatService[] = Creden
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: proposalCredentialMessage ?? undefined,
lastSentMessage: offerCredentialMessage ?? undefined,
expectedConnectionId: credentialRecord.connectionId,
})

await this.credentialFormatCoordinator.processProposal(messageContext.agentContext, {
Expand Down Expand Up @@ -445,6 +446,7 @@ export class V2CredentialProtocol<CFs extends CredentialFormatService[] = Creden
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: offerCredentialMessage ?? undefined,
lastSentMessage: proposeCredentialMessage ?? undefined,
expectedConnectionId: credentialRecord.connectionId,
})

await this.credentialFormatCoordinator.processOffer(messageContext.agentContext, {
Expand Down Expand Up @@ -688,6 +690,7 @@ export class V2CredentialProtocol<CFs extends CredentialFormatService[] = Creden
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: proposalMessage ?? undefined,
lastSentMessage: offerMessage ?? undefined,
expectedConnectionId: credentialRecord.connectionId,
})

// This makes sure that the sender of the incoming message is authorized to do so.
Expand Down Expand Up @@ -833,6 +836,7 @@ export class V2CredentialProtocol<CFs extends CredentialFormatService[] = Creden
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: offerMessage ?? undefined,
lastSentMessage: requestMessage,
expectedConnectionId: credentialRecord.connectionId,
})

const formatServices = this.getFormatServicesFromMessage(credentialMessage.formats)
Expand Down Expand Up @@ -921,6 +925,7 @@ export class V2CredentialProtocol<CFs extends CredentialFormatService[] = Creden
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
lastReceivedMessage: requestMessage,
lastSentMessage: credentialMessage,
expectedConnectionId: credentialRecord.connectionId,
})

// Update record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,6 @@ describe('credentialProtocol', () => {

expect(credentialRepository.getSingleByQuery).toHaveBeenNthCalledWith(1, agentContext, {
threadId: 'somethreadid',
connectionId: '123',
})
expect(credentialRepository.update).toHaveBeenCalled()
expect(returnedCredentialRecord.errorMessage).toBe('issuance-abandoned: Indy error')
Expand Down
18 changes: 17 additions & 1 deletion packages/core/src/modules/proofs/protocol/BaseProofProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type { ProofExchangeRecord } from '../repository'

import { EventEmitter } from '../../../agent/EventEmitter'
import { DidCommMessageRepository } from '../../../storage/didcomm'
import { ConnectionService } from '../../connections'
import { ProofEventTypes } from '../ProofEvents'
import { ProofState } from '../models/ProofState'
import { ProofRepository } from '../repository'
Expand Down Expand Up @@ -112,13 +113,28 @@ export abstract class BaseProofProtocol<PFs extends ProofFormatService[] = Proof
): Promise<ProofExchangeRecord> {
const { message: proofProblemReportMessage, agentContext, connection } = messageContext

const connectionService = agentContext.dependencyManager.resolve(ConnectionService)

agentContext.config.logger.debug(`Processing problem report with message id ${proofProblemReportMessage.id}`)

const proofRecord = await this.getByProperties(agentContext, {
threadId: proofProblemReportMessage.threadId,
connectionId: connection?.id,
})

// Assert
await connectionService.assertConnectionOrOutOfBandExchange(messageContext, {
expectedConnectionId: proofRecord.connectionId,
})

// This makes sure that the sender of the incoming message is authorized to do so.
if (!proofRecord?.connectionId) {
await connectionService.matchIncomingMessageToRequestMessageInOutOfBandExchange(messageContext, {
expectedConnectionId: proofRecord?.connectionId,
})

proofRecord.connectionId = connection?.id
}

// Update record
proofRecord.errorMessage = `${proofProblemReportMessage.description.code}: ${proofProblemReportMessage.description.en}`
await this.updateState(agentContext, proofRecord, ProofState.Abandoned)
Expand Down
Loading
Loading