diff --git a/packages/core/src/modules/credentials/CredentialResponseCoordinator.ts b/packages/core/src/modules/credentials/CredentialResponseCoordinator.ts deleted file mode 100644 index 4bb3ce4ebb..0000000000 --- a/packages/core/src/modules/credentials/CredentialResponseCoordinator.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { scoped, Lifecycle } from 'tsyringe' - -import { AgentConfig } from '../../agent/AgentConfig' -import { DidCommMessageRepository } from '../../storage' - -import { AutoAcceptCredential } from './CredentialAutoAcceptType' - -/** - * This class handles all the automation with all the messages in the issue credential protocol - * Every function returns `true` if it should automate the flow and `false` if not - */ -@scoped(Lifecycle.ContainerScoped) -export class CredentialResponseCoordinator { - private agentConfig: AgentConfig - private didCommMessageRepository: DidCommMessageRepository - - public constructor(agentConfig: AgentConfig, didCommMessageRepository: DidCommMessageRepository) { - this.agentConfig = agentConfig - this.didCommMessageRepository = didCommMessageRepository - } - - /** - * Returns the credential auto accept config based on priority: - * - The record config takes first priority - * - Otherwise the agent config - * - Otherwise {@link AutoAcceptCredential.Never} is returned - */ - public static composeAutoAccept( - recordConfig: AutoAcceptCredential | undefined, - agentConfig: AutoAcceptCredential | undefined - ) { - return recordConfig ?? agentConfig ?? AutoAcceptCredential.Never - } -} diff --git a/packages/core/src/modules/credentials/CredentialServiceOptions.ts b/packages/core/src/modules/credentials/CredentialServiceOptions.ts index e9af147adc..03934636c1 100644 --- a/packages/core/src/modules/credentials/CredentialServiceOptions.ts +++ b/packages/core/src/modules/credentials/CredentialServiceOptions.ts @@ -48,7 +48,6 @@ export interface ServiceAcceptOfferOptions extends AcceptOfferOptions { export interface ServiceOfferCredentialOptions extends OfferCredentialOptions { connectionId?: string attachId?: string - // offerAttachment?: Attachment } export interface ServiceAcceptProposalOptions extends AcceptProposalOptions { @@ -71,6 +70,7 @@ export interface ServiceRequestCredentialOptions extends RequestCredentialOption attachId?: string offerAttachment?: Attachment requestAttachment?: Attachment + holderDid?: string } export interface ServiceAcceptCredentialOptions { diff --git a/packages/core/src/modules/credentials/CredentialsModule.ts b/packages/core/src/modules/credentials/CredentialsModule.ts index 2e4bbef562..020bf810d7 100644 --- a/packages/core/src/modules/credentials/CredentialsModule.ts +++ b/packages/core/src/modules/credentials/CredentialsModule.ts @@ -241,8 +241,9 @@ export class CredentialsModule implements CredentialsModule { const requestOptions: RequestCredentialOptions = { comment: options.comment, autoAcceptCredential: options.autoAcceptCredential, + holderDid: connection.did, } - const { message, credentialRecord } = await service.createRequest(record, requestOptions, connection.did) + const { message, credentialRecord } = await service.createRequest(record, requestOptions) await this.didCommMessageRepo.saveAgentMessage({ agentMessage: message, @@ -272,12 +273,9 @@ export class CredentialsModule implements CredentialsModule { const requestOptions: RequestCredentialOptions = { comment: options.comment, autoAcceptCredential: options.autoAcceptCredential, + holderDid: ourService.recipientKeys[0], } - const { message, credentialRecord } = await service.createRequest( - record, - requestOptions, - ourService.recipientKeys[0] - ) + const { message, credentialRecord } = await service.createRequest(record, requestOptions) // Set and save ~service decorator to record (to remember our verkey) message.service = ourService @@ -349,6 +347,9 @@ export class CredentialsModule implements CredentialsModule { if (!options.connectionId) { throw new AriesFrameworkError('Missing connectionId on offerCredential') } + if (!options.protocolVersion) { + throw new AriesFrameworkError('Missing protocol version in offerCredential') + } const connection = await this.connectionService.getById(options.connectionId) const service = this.getService(options.protocolVersion) diff --git a/packages/core/src/modules/credentials/CredentialsModuleOptions.ts b/packages/core/src/modules/credentials/CredentialsModuleOptions.ts index 751bef079d..85f01f8f45 100644 --- a/packages/core/src/modules/credentials/CredentialsModuleOptions.ts +++ b/packages/core/src/modules/credentials/CredentialsModuleOptions.ts @@ -26,8 +26,6 @@ interface ProposeCredentialOptions extends BaseOptions { } interface AcceptProposalOptions extends BaseOptions { - connectionId?: string - protocolVersion: CredentialProtocolVersion credentialRecordId: string credentialFormats: FormatServiceAcceptProposeCredentialFormats } @@ -57,6 +55,7 @@ interface NegotiateOfferOptions extends ProposeCredentialOptions { interface RequestCredentialOptions extends BaseOptions { connectionId?: string credentialFormats?: FormatServiceRequestCredentialFormats + holderDid?: string } interface AcceptRequestOptions extends BaseOptions { diff --git a/packages/core/src/modules/credentials/__tests__/V1CredentialService.cred.test.ts b/packages/core/src/modules/credentials/__tests__/V1CredentialService.cred.test.ts index 7a4b9cfccc..19fbf1c612 100644 --- a/packages/core/src/modules/credentials/__tests__/V1CredentialService.cred.test.ts +++ b/packages/core/src/modules/credentials/__tests__/V1CredentialService.cred.test.ts @@ -292,8 +292,8 @@ describe('CredentialService', () => { // mock offer so that the request works // when - const options: RequestCredentialOptions = {} - await credentialService.createRequest(credentialRecord, options, 'holderDid') + const options: RequestCredentialOptions = { holderDid: 'holderDid' } + await credentialService.createRequest(credentialRecord, options) // then expect(repositoryUpdateSpy).toHaveBeenCalledTimes(1) @@ -310,14 +310,11 @@ describe('CredentialService', () => { const options: RequestCredentialOptions = { connectionId: credentialRecord.connectionId, comment: 'credential request comment', + holderDid: 'holderDid', } // when - const { message: credentialRequest } = await credentialService.createRequest( - credentialRecord, - options, - 'holderDid' - ) + const { message: credentialRequest } = await credentialService.createRequest(credentialRecord, options) // then expect(credentialRequest.toJSON()).toMatchObject({ @@ -345,7 +342,7 @@ describe('CredentialService', () => { await Promise.all( invalidCredentialStates.map(async (state) => { await expect( - credentialService.createRequest(mockCredentialRecord({ state }), {}, 'holderDid') + credentialService.createRequest(mockCredentialRecord({ state }), { holderDid: 'holderDid' }) ).rejects.toThrowError(`Credential record is in invalid state ${state}. Valid states are: ${validState}.`) }) ) diff --git a/packages/core/src/modules/credentials/__tests__/V2CredentialService.cred.test.ts b/packages/core/src/modules/credentials/__tests__/V2CredentialService.cred.test.ts index 1a2bbb56e9..f30af9db6b 100644 --- a/packages/core/src/modules/credentials/__tests__/V2CredentialService.cred.test.ts +++ b/packages/core/src/modules/credentials/__tests__/V2CredentialService.cred.test.ts @@ -293,11 +293,12 @@ describe('CredentialService', () => { const requestOptions: RequestCredentialOptions = { credentialFormats: v2CredentialRequest, + holderDid: 'holderDid', } // when - await credentialService.createRequest(credentialRecord, requestOptions, 'holderDid') + await credentialService.createRequest(credentialRecord, requestOptions) // then expect(repositoryUpdateSpy).toHaveBeenCalledTimes(1) @@ -314,13 +315,10 @@ describe('CredentialService', () => { const options: RequestCredentialOptions = { connectionId: credentialRecord.connectionId, comment: 'credential request comment', + holderDid: 'holderDid', } // when - const { message: credentialRequest } = await credentialService.createRequest( - credentialRecord, - options, - 'holderDid' - ) + const { message: credentialRequest } = await credentialService.createRequest(credentialRecord, options) // then expect(credentialRequest.toJSON()).toMatchObject({ @@ -348,7 +346,7 @@ describe('CredentialService', () => { await Promise.all( invalidCredentialStates.map(async (state) => { await expect( - credentialService.createRequest(mockCredentialRecord({ state }), {}, 'mockDid') + credentialService.createRequest(mockCredentialRecord({ state }), { holderDid: 'mockDid' }) ).rejects.toThrowError(`Credential record is in invalid state ${state}. Valid states are: ${validState}.`) }) ) diff --git a/packages/core/src/modules/credentials/composeAutoAccept.ts b/packages/core/src/modules/credentials/composeAutoAccept.ts new file mode 100644 index 0000000000..0b3becddaf --- /dev/null +++ b/packages/core/src/modules/credentials/composeAutoAccept.ts @@ -0,0 +1,15 @@ +/** + * Returns the credential auto accept config based on priority: + * - The record config takes first priority + * - Otherwise the agent config + * - Otherwise {@link AutoAcceptCredential.Never} is returned + */ + +import { AutoAcceptCredential } from './CredentialAutoAcceptType' + +export function composeAutoAccept( + recordConfig: AutoAcceptCredential | undefined, + agentConfig: AutoAcceptCredential | undefined +) { + return recordConfig ?? agentConfig ?? AutoAcceptCredential.Never +} diff --git a/packages/core/src/modules/credentials/formats/indy/IndyCredentialFormatService.ts b/packages/core/src/modules/credentials/formats/indy/IndyCredentialFormatService.ts index e9c8879d07..43b1eb46a9 100644 --- a/packages/core/src/modules/credentials/formats/indy/IndyCredentialFormatService.ts +++ b/packages/core/src/modules/credentials/formats/indy/IndyCredentialFormatService.ts @@ -19,7 +19,6 @@ import type { V1CredentialPreview } from '../../protocol/v1/V1CredentialPreview' import type { CredentialExchangeRecord } from '../../repository/CredentialExchangeRecord' import type { FormatServiceCredentialAttachmentFormats, - CredentialFormatSpec, HandlerAutoAcceptOptions, FormatServiceOfferAttachmentFormats, FormatServiceProposeAttachmentFormats, @@ -38,15 +37,16 @@ import { uuid } from '../../../../utils/uuid' import { IndyHolderService, IndyIssuerService } from '../../../indy' import { IndyLedgerService } from '../../../ledger' import { AutoAcceptCredential } from '../../CredentialAutoAcceptType' -import { CredentialResponseCoordinator } from '../../CredentialResponseCoordinator' import { CredentialUtils } from '../../CredentialUtils' import { CredentialFormatType } from '../../CredentialsModuleOptions' +import { composeAutoAccept } from '../../composeAutoAccept' import { CredentialProblemReportError, CredentialProblemReportReason } from '../../errors' import { V2CredentialPreview } from '../../protocol/v2/V2CredentialPreview' import { CredentialMetadataKeys } from '../../repository/CredentialMetadataTypes' import { CredentialRepository } from '../../repository/CredentialRepository' import { CredentialFormatService } from '../CredentialFormatService' import { CredPropose } from '../models/CredPropose' +import { CredentialFormatSpec } from '../models/CredentialFormatServiceOptions' @scoped(Lifecycle.ContainerScoped) export class IndyCredentialFormatService extends CredentialFormatService { @@ -85,6 +85,7 @@ export class IndyCredentialFormatService extends CredentialFormatService { attachId: this.generateId(), format: 'hlindy/cred-filter@v2.0', } + if (!options.credentialFormats.indy?.payload) { throw new AriesFrameworkError('Missing payload in createProposal') } @@ -111,26 +112,25 @@ export class IndyCredentialFormatService extends CredentialFormatService { options: ServiceAcceptProposalOptions, credentialRecord: CredentialExchangeRecord ): Promise { - let credPropose = options.proposalAttachment?.getDataAsJson() - credPropose = JsonTransformer.fromJSON(credPropose, CredPropose) - - if (!credPropose) { + const credProposalJson = options.proposalAttachment?.getDataAsJson() + if (!credProposalJson) { throw new AriesFrameworkError('Missing indy credential proposal data payload') } - await MessageValidator.validate(credPropose) + const credProposal = JsonTransformer.fromJSON(credProposalJson, CredPropose) + await MessageValidator.validate(credProposal) - if (credPropose.credentialDefinitionId) { + if (credProposal.credentialDefinitionId) { options.credentialFormats = { indy: { - credentialDefinitionId: credPropose?.credentialDefinitionId, + credentialDefinitionId: credProposal?.credentialDefinitionId, attributes: [], }, } } credentialRecord.metadata.set(CredentialMetadataKeys.IndyCredential, { - schemaId: credPropose.schemaId, - credentialDefinitionId: credPropose.credentialDefinitionId, + schemaId: credProposal.schemaId, + credentialDefinitionId: credProposal.credentialDefinitionId, }) } @@ -143,10 +143,10 @@ export class IndyCredentialFormatService extends CredentialFormatService { * */ public async createOffer(options: ServiceOfferCredentialOptions): Promise { - const formats: CredentialFormatSpec = { + const formats = new CredentialFormatSpec({ attachId: this.generateId(), format: 'hlindy/cred-abstract@v2.0', - } + }) const offer = await this.createCredentialOffer(options) let preview: V2CredentialPreview | undefined @@ -195,24 +195,29 @@ export class IndyCredentialFormatService extends CredentialFormatService { */ public async createRequest( options: ServiceRequestCredentialOptions, - credentialRecord: CredentialExchangeRecord, - holderDid: string + credentialRecord: CredentialExchangeRecord ): Promise { if (!options.offerAttachment) { throw new AriesFrameworkError( `Missing attachment from offer message, credential record id = ${credentialRecord.id}` ) } + + if (!options.holderDid) { + throw new AriesFrameworkError( + `Missing holder DID from offer message, credential record id = ${credentialRecord.id}` + ) + } const offer = options.offerAttachment.getDataAsJson() const credDef = await this.getCredentialDefinition(offer) - const { credReq, credReqMetadata } = await this.createIndyCredentialRequest(offer, credDef, holderDid) + const { credReq, credReqMetadata } = await this.createIndyCredentialRequest(offer, credDef, options.holderDid) credentialRecord.metadata.set(CredentialMetadataKeys.IndyRequest, credReqMetadata) - const formats: CredentialFormatSpec = { + const formats = new CredentialFormatSpec({ attachId: this.generateId(), format: 'hlindy/cred-req@v2.0', - } + }) const attachmentId = options.attachId ?? formats.attachId const requestAttach: Attachment = this.getFormatData(credReq, attachmentId) @@ -375,10 +380,10 @@ export class IndyCredentialFormatService extends CredentialFormatService { credentialValues: CredentialUtils.convertAttributesToValues(credentialAttributes), }) - const formats: CredentialFormatSpec = { + const formats = new CredentialFormatSpec({ attachId: this.generateId(), format: 'hlindy/cred-abstract@v2.0', - } + }) const attachmentId = options.attachId ? options.attachId : formats.attachId const issueAttachment = this.getFormatData(credential, attachmentId) @@ -439,7 +444,7 @@ export class IndyCredentialFormatService extends CredentialFormatService { */ public shouldAutoRespondToProposal(handlerOptions: HandlerAutoAcceptOptions): boolean { - const autoAccept = CredentialResponseCoordinator.composeAutoAccept( + const autoAccept = composeAutoAccept( handlerOptions.credentialRecord.autoAcceptCredential, handlerOptions.autoAcceptType ) @@ -463,10 +468,7 @@ export class IndyCredentialFormatService extends CredentialFormatService { */ public shouldAutoRespondToRequest(options: HandlerAutoAcceptOptions): boolean { - const autoAccept = CredentialResponseCoordinator.composeAutoAccept( - options.credentialRecord.autoAcceptCredential, - options.autoAcceptType - ) + const autoAccept = composeAutoAccept(options.credentialRecord.autoAcceptCredential, options.autoAcceptType) if (!options.requestAttachment) { throw new AriesFrameworkError(`Missing Request Attachment for Credential Record ${options.credentialRecord.id}`) @@ -489,10 +491,7 @@ export class IndyCredentialFormatService extends CredentialFormatService { */ public shouldAutoRespondToCredential(options: HandlerAutoAcceptOptions): boolean { - const autoAccept = CredentialResponseCoordinator.composeAutoAccept( - options.credentialRecord.autoAcceptCredential, - options.autoAcceptType - ) + const autoAccept = composeAutoAccept(options.credentialRecord.autoAcceptCredential, options.autoAcceptType) if (autoAccept === AutoAcceptCredential.ContentApproved) { if (options.credentialAttachment) { diff --git a/packages/core/src/modules/credentials/formats/models/CredentialFormatServiceOptions.ts b/packages/core/src/modules/credentials/formats/models/CredentialFormatServiceOptions.ts index 3172fa9236..ba33947d50 100644 --- a/packages/core/src/modules/credentials/formats/models/CredentialFormatServiceOptions.ts +++ b/packages/core/src/modules/credentials/formats/models/CredentialFormatServiceOptions.ts @@ -41,6 +41,12 @@ export interface IndyIssueCredentialFormat { } export class CredentialFormatSpec { + public constructor(options: { attachId: string; format: string }) { + if (options) { + this.attachId = options.attachId + this.format = options.format + } + } @Expose({ name: 'attach_id' }) @IsString() public attachId!: string diff --git a/packages/core/src/modules/credentials/index.ts b/packages/core/src/modules/credentials/index.ts index d7b5b67b3a..cc03bc3420 100644 --- a/packages/core/src/modules/credentials/index.ts +++ b/packages/core/src/modules/credentials/index.ts @@ -7,4 +7,3 @@ export * from './CredentialState' export * from './CredentialEvents' export * from './CredentialAutoAcceptType' export * from './CredentialProtocolVersion' -export * from './CredentialResponseCoordinator' diff --git a/packages/core/src/modules/credentials/protocol/v1/V1CredentialService.ts b/packages/core/src/modules/credentials/protocol/v1/V1CredentialService.ts index bcf68b4109..73db3181dc 100644 --- a/packages/core/src/modules/credentials/protocol/v1/V1CredentialService.ts +++ b/packages/core/src/modules/credentials/protocol/v1/V1CredentialService.ts @@ -40,9 +40,9 @@ import { MediationRecipientService } from '../../../routing' import { AutoAcceptCredential } from '../../CredentialAutoAcceptType' import { CredentialEventTypes } from '../../CredentialEvents' import { CredentialProtocolVersion } from '../../CredentialProtocolVersion' -import { CredentialResponseCoordinator } from '../../CredentialResponseCoordinator' import { CredentialState } from '../../CredentialState' import { CredentialUtils } from '../../CredentialUtils' +import { composeAutoAccept } from '../../composeAutoAccept' import { CredentialProblemReportError, CredentialProblemReportReason } from '../../errors' import { IndyCredentialFormatService } from '../../formats/indy/IndyCredentialFormatService' import { CredentialRepository, CredentialMetadataKeys, CredentialExchangeRecord } from '../../repository' @@ -111,18 +111,23 @@ export class V1CredentialService extends CredentialService { ): Promise> { const connection = await this.connectionService.getById(proposal.connectionId) connection.assertReady() - + if (!proposal.credentialFormats.indy || Object.keys(proposal.credentialFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } let credentialProposal: V1CredentialPreview | undefined const credPropose = proposal.credentialFormats.indy?.payload + if (!credPropose) { + throw new AriesFrameworkError('Missing credPropose data payload in createProposal') + } if (proposal.credentialFormats.indy?.attributes) { credentialProposal = new V1CredentialPreview({ attributes: proposal.credentialFormats.indy?.attributes }) } const config: CredentialProposeOptions = { credentialProposal: credentialProposal, - credentialDefinitionId: credPropose?.credentialDefinitionId, + credentialDefinitionId: credPropose.credentialDefinitionId, linkedAttachments: proposal.credentialFormats.indy?.linkedAttachments, schemaId: credPropose?.schemaId, } @@ -186,6 +191,9 @@ export class V1CredentialService extends CredentialService { options: AcceptProposalOptions, credentialRecord: CredentialExchangeRecord ): Promise> { + if (!options.credentialFormats.indy || Object.keys(options.credentialFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } const proposalCredentialMessage = await this.didCommMessageRepository.findAgentMessage({ associatedRecordId: credentialRecord.id, messageClass: V1ProposeCredentialMessage, @@ -238,6 +246,9 @@ export class V1CredentialService extends CredentialService { `No connectionId found for credential record '${credentialRecord.id}'. Connection-less issuance does not support negotiation.` ) } + if (!credentialOptions.credentialFormats.indy || Object.keys(credentialOptions.credentialFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } const credentialProposalMessage = await this.didCommMessageRepository.findAgentMessage({ associatedRecordId: credentialRecord.id, @@ -449,6 +460,10 @@ export class V1CredentialService extends CredentialService { `No connectionId found for credential record '${credentialRecord.id}'. Connection-less issuance does not support negotiation.` ) } + if (!credentialOptions.credentialFormats.indy || Object.keys(credentialOptions.credentialFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + if (!credentialOptions.credentialFormats.indy?.attributes) { throw new AriesFrameworkError('Missing attributes in V1 Negotiate Offer Options') } @@ -492,6 +507,10 @@ export class V1CredentialService extends CredentialService { if (!credentialOptions.connectionId) { throw new AriesFrameworkError('Connection id missing from offer credential options') } + if (!credentialOptions.credentialFormats.indy || Object.keys(credentialOptions.credentialFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + const connection = await this.connectionService.getById(credentialOptions.connectionId) if ( @@ -698,6 +717,10 @@ export class V1CredentialService extends CredentialService { public async createOutOfBandOffer( credentialOptions: OfferCredentialOptions ): Promise> { + if (!credentialOptions.credentialFormats.indy || Object.keys(credentialOptions.credentialFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + if (!credentialOptions.credentialFormats.indy?.credentialDefinitionId) { throw new AriesFrameworkError('Missing credential definition id for out of band credential') } @@ -745,8 +768,7 @@ export class V1CredentialService extends CredentialService { */ public async createRequest( record: CredentialExchangeRecord, - options: ServiceRequestCredentialOptions, - holderDid: string + options: ServiceRequestCredentialOptions ): Promise> { // Assert credential record.assertState(CredentialState.OfferReceived) @@ -770,7 +792,7 @@ export class V1CredentialService extends CredentialService { throw new AriesFrameworkError(`Missing data payload in attachment in credential Record ${record.id}`) } options.attachId = INDY_CREDENTIAL_REQUEST_ATTACHMENT_ID - const { attachment: requestAttach } = await this.formatService.createRequest(options, record, holderDid) + const { attachment: requestAttach } = await this.formatService.createRequest(options, record) if (!requestAttach) { throw new AriesFrameworkError(`Failed to create attachment for request; credential record = ${record.id}`) } @@ -1121,7 +1143,7 @@ export class V1CredentialService extends CredentialService { } public async shouldAutoRespondToProposal(handlerOptions: HandlerAutoAcceptOptions): Promise { - const autoAccept = CredentialResponseCoordinator.composeAutoAccept( + const autoAccept = composeAutoAccept( handlerOptions.credentialRecord.autoAcceptCredential, handlerOptions.autoAcceptType ) diff --git a/packages/core/src/modules/credentials/protocol/v1/handlers/V1OfferCredentialHandler.ts b/packages/core/src/modules/credentials/protocol/v1/handlers/V1OfferCredentialHandler.ts index a19b60a03f..0e36bf22ac 100644 --- a/packages/core/src/modules/credentials/protocol/v1/handlers/V1OfferCredentialHandler.ts +++ b/packages/core/src/modules/credentials/protocol/v1/handlers/V1OfferCredentialHandler.ts @@ -64,11 +64,9 @@ export class V1OfferCredentialHandler implements Handler { `Automatically sending request with autoAccept on ${this.agentConfig.autoAcceptCredentials}` ) if (messageContext.connection) { - const { message, credentialRecord } = await this.credentialService.createRequest( - record, - {}, - messageContext.connection.did - ) + const { message, credentialRecord } = await this.credentialService.createRequest(record, { + holderDid: messageContext.connection.did, + }) await this.didCommMessageRepository.saveAgentMessage({ agentMessage: message, role: DidCommMessageRole.Sender, @@ -85,11 +83,9 @@ export class V1OfferCredentialHandler implements Handler { }) const recipientService = offerMessage.service - const { message, credentialRecord } = await this.credentialService.createRequest( - record, - {}, - ourService.recipientKeys[0] - ) + const { message, credentialRecord } = await this.credentialService.createRequest(record, { + holderDid: ourService.recipientKeys[0], + }) // Set and save ~service decorator to record (to remember our verkey) message.service = ourService diff --git a/packages/core/src/modules/credentials/protocol/v2/CredentialMessageBuilder.ts b/packages/core/src/modules/credentials/protocol/v2/CredentialMessageBuilder.ts index 1dce4cb9b8..d5a5246431 100644 --- a/packages/core/src/modules/credentials/protocol/v2/CredentialMessageBuilder.ts +++ b/packages/core/src/modules/credentials/protocol/v2/CredentialMessageBuilder.ts @@ -132,9 +132,6 @@ export class CredentialMessageBuilder { for (const formatService of formatServices) { const { attachment: offersAttach, preview, format } = await formatService.createOffer(options) - if (offersAttach === undefined) { - throw new AriesFrameworkError('offersAttach not initialized for credential offer') - } if (offersAttach) { offersAttachArray.push(offersAttach) } else { diff --git a/packages/core/src/modules/credentials/protocol/v2/V2CredentialService.ts b/packages/core/src/modules/credentials/protocol/v2/V2CredentialService.ts index 9636d8dd39..8010461c08 100644 --- a/packages/core/src/modules/credentials/protocol/v2/V2CredentialService.ts +++ b/packages/core/src/modules/credentials/protocol/v2/V2CredentialService.ts @@ -145,7 +145,6 @@ export class V2CredentialService extends CredentialService { const options: ServiceAcceptProposalOptions = { credentialRecordId: credentialRecord.id, credentialFormats: {}, - protocolVersion: CredentialProtocolVersion.V2, } options.proposalAttachment = format.getAttachment(proposalMessage.formats, proposalMessage.messageAttachment) await format.processProposal(options, credentialRecord) @@ -220,10 +219,9 @@ export class V2CredentialService extends CredentialService { credentialRecord: CredentialExchangeRecord ): Promise> { const options: ServiceOfferCredentialOptions = { - connectionId: proposal.connectionId ?? undefined, - protocolVersion: proposal.protocolVersion, credentialFormats: proposal.credentialFormats, comment: proposal.comment, + protocolVersion: credentialRecord.protocolVersion, } const message = await this.createOfferAsResponse(credentialRecord, options) @@ -256,7 +254,6 @@ export class V2CredentialService extends CredentialService { const options: ServiceAcceptProposalOptions = { credentialRecordId: credentialRecord.id, credentialFormats: {}, - protocolVersion: CredentialProtocolVersion.V2, } for (const formatService of formats) { @@ -430,7 +427,6 @@ export class V2CredentialService extends CredentialService { options = { credentialFormats: acceptProposalOptions.credentialFormats, protocolVersion: CredentialProtocolVersion.V2, - credentialRecordId: acceptProposalOptions.connectionId, comment: acceptProposalOptions.comment, } } else { diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v1credentials-auto-accept.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v1credentials-auto-accept.test.ts index 231f9532ad..0a7ce0a5a3 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v1credentials-auto-accept.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v1credentials-auto-accept.test.ts @@ -213,7 +213,6 @@ describe('credentials', () => { attributes: credentialPreview.attributes, }, }, - protocolVersion: CredentialProtocolVersion.V1, } testLogger.test('Faber sends credential offer to Alice') options.credentialRecordId = faberCredentialExchangeRecord.id diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials-auto-accept.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials-auto-accept.test.ts index 3a7fc9bb7f..eb3b51304d 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials-auto-accept.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials-auto-accept.test.ts @@ -211,7 +211,6 @@ describe('credentials', () => { const options: AcceptProposalOptions = { credentialRecordId: faberCredentialRecord.id, comment: 'V2 Indy Offer', - protocolVersion: CredentialProtocolVersion.V2, credentialFormats: { indy: { attributes: [], diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials.propose-offer.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials.propose-offer.test.ts index 0a2ccd221f..b646fa1662 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials.propose-offer.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2credentials.propose-offer.test.ts @@ -119,7 +119,6 @@ describe('credentials', () => { attributes: credentialPreview.attributes, }, }, - protocolVersion: CredentialProtocolVersion.V2, } testLogger.test('Faber sends credential offer to Alice') @@ -273,7 +272,6 @@ describe('credentials', () => { attributes: credentialPreview.attributes, }, }, - protocolVersion: CredentialProtocolVersion.V2, } testLogger.test('Faber sends credential offer to Alice') await faberAgent.credentials.acceptProposal(options) @@ -670,7 +668,6 @@ describe('credentials', () => { attributes: credentialPreview.attributes, }, }, - protocolVersion: CredentialProtocolVersion.V2, } testLogger.test('Faber sends credential offer to Alice') diff --git a/packages/core/src/modules/credentials/protocol/v2/handlers/V2OfferCredentialHandler.ts b/packages/core/src/modules/credentials/protocol/v2/handlers/V2OfferCredentialHandler.ts index 0e6fee4af7..4472ac40c0 100644 --- a/packages/core/src/modules/credentials/protocol/v2/handlers/V2OfferCredentialHandler.ts +++ b/packages/core/src/modules/credentials/protocol/v2/handlers/V2OfferCredentialHandler.ts @@ -71,11 +71,9 @@ export class V2OfferCredentialHandler implements Handler { ) if (messageContext.connection) { - const { message, credentialRecord } = await this.credentialService.createRequest( - record, - {}, - messageContext.connection.did - ) + const { message, credentialRecord } = await this.credentialService.createRequest(record, { + holderDid: messageContext.connection.did, + }) await this.didCommMessageRepository.saveAgentMessage({ agentMessage: message, role: DidCommMessageRole.Receiver, @@ -91,11 +89,9 @@ export class V2OfferCredentialHandler implements Handler { }) const recipientService = offerMessage.service - const { message, credentialRecord } = await this.credentialService.createRequest( - record, - {}, - ourService.recipientKeys[0] - ) + const { message, credentialRecord } = await this.credentialService.createRequest(record, { + holderDid: ourService.recipientKeys[0], + }) // Set and save ~service decorator to record (to remember our verkey) message.service = ourService diff --git a/packages/core/src/modules/credentials/protocol/v2/messages/V2IssueCredentialMessage.ts b/packages/core/src/modules/credentials/protocol/v2/messages/V2IssueCredentialMessage.ts index 9005fff339..56c6f10eea 100644 --- a/packages/core/src/modules/credentials/protocol/v2/messages/V2IssueCredentialMessage.ts +++ b/packages/core/src/modules/credentials/protocol/v2/messages/V2IssueCredentialMessage.ts @@ -27,7 +27,7 @@ export class V2IssueCredentialMessage extends AgentMessage { @Type(() => CredentialFormatSpec) @ValidateNested() @IsArray() - // @IsInstance(CredentialFormatSpec, { each: true }) -> this causes message validation to fail + @IsInstance(CredentialFormatSpec, { each: true }) public formats!: CredentialFormatSpec[] @IsValidMessageType(V2IssueCredentialMessage.type) diff --git a/packages/core/src/modules/credentials/protocol/v2/messages/V2OfferCredentialMessage.ts b/packages/core/src/modules/credentials/protocol/v2/messages/V2OfferCredentialMessage.ts index d8c19fcdb6..fd8b6ff2d6 100644 --- a/packages/core/src/modules/credentials/protocol/v2/messages/V2OfferCredentialMessage.ts +++ b/packages/core/src/modules/credentials/protocol/v2/messages/V2OfferCredentialMessage.ts @@ -31,7 +31,7 @@ export class V2OfferCredentialMessage extends AgentMessage { @Type(() => CredentialFormatSpec) @ValidateNested() @IsArray() - // @IsInstance(CredentialFormatSpec, { each: true }) -> this causes message validation to fail + @IsInstance(CredentialFormatSpec, { each: true }) public formats!: CredentialFormatSpec[] @IsValidMessageType(V2OfferCredentialMessage.type) diff --git a/packages/core/src/modules/credentials/protocol/v2/messages/V2RequestCredentialMessage.ts b/packages/core/src/modules/credentials/protocol/v2/messages/V2RequestCredentialMessage.ts index f9e080922b..8cd9cb5144 100644 --- a/packages/core/src/modules/credentials/protocol/v2/messages/V2RequestCredentialMessage.ts +++ b/packages/core/src/modules/credentials/protocol/v2/messages/V2RequestCredentialMessage.ts @@ -27,7 +27,7 @@ export class V2RequestCredentialMessage extends AgentMessage { @Type(() => CredentialFormatSpec) @ValidateNested() @IsArray() - // @IsInstance(CredentialFormatSpec, { each: true }) -> this causes message validation to fail + @IsInstance(CredentialFormatSpec, { each: true }) public formats!: CredentialFormatSpec[] @IsValidMessageType(V2RequestCredentialMessage.type) diff --git a/packages/core/src/modules/credentials/repository/CredentialExchangeRecord.ts b/packages/core/src/modules/credentials/repository/CredentialExchangeRecord.ts index dd9da3ec51..6f20476387 100644 --- a/packages/core/src/modules/credentials/repository/CredentialExchangeRecord.ts +++ b/packages/core/src/modules/credentials/repository/CredentialExchangeRecord.ts @@ -47,7 +47,6 @@ export type DefaultCredentialTags = { export interface CredentialRecordBinding { credentialRecordType: CredentialFormatType credentialRecordId: string - credentialId?: string } export class CredentialExchangeRecord extends BaseRecord< @@ -91,24 +90,22 @@ export class CredentialExchangeRecord extends BaseRecord< this.linkedAttachments = props.linkedAttachments this.revocationNotification = props.revocationNotification this.errorMessage = props.errorMessage - this.credentials = props.credentials ?? [] + this.credentials = props.credentials || [] } } public getTags() { const metadata = this.metadata.get(CredentialMetadataKeys.IndyCredential) - let credentialIds: string[] = [] - + let ids: string[] = [] if (this.credentials) { - credentialIds = this.credentials.map((c) => c.credentialRecordId) + ids = this.credentials.map((c) => c.credentialRecordId) } - return { ...this._tags, threadId: this.threadId, connectionId: this.connectionId, state: this.state, - credentialIds: credentialIds, + credentialIds: ids, indyRevocationRegistryId: metadata?.indyRevocationRegistryId, indyCredentialRevocationId: metadata?.indyCredentialRevocationId, } @@ -132,7 +129,7 @@ export class CredentialExchangeRecord extends BaseRecord< }) } - public assertVersion(version: string) { + public assertProtocolVersion(version: string) { if (this.protocolVersion != version) { throw new AriesFrameworkError( `Credential record has invalid protocol version ${this.protocolVersion}. Expected version ${version}` diff --git a/packages/core/src/modules/credentials/services/CredentialService.ts b/packages/core/src/modules/credentials/services/CredentialService.ts index 1bb7df046c..9f68eaba62 100644 --- a/packages/core/src/modules/credentials/services/CredentialService.ts +++ b/packages/core/src/modules/credentials/services/CredentialService.ts @@ -99,8 +99,7 @@ export abstract class CredentialService { // methods for request abstract createRequest( credentialRecord: CredentialExchangeRecord, - options: ServiceRequestCredentialOptions, - holderDid: string + options: ServiceRequestCredentialOptions ): Promise> abstract processAck(messageContext: InboundMessageContext): Promise @@ -169,6 +168,7 @@ export abstract class CredentialService { await this.update(credentialRecord) return credentialRecord } + abstract shouldAutoRespondToProposal(options: HandlerAutoAcceptOptions): Promise abstract shouldAutoRespondToOffer(