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

feat(proofs): proof negotiation #1131

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 96 additions & 1 deletion packages/core/src/modules/proofs/ProofsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import type {
ProposeProofOptions,
RequestProofOptions,
ProofServiceMap,
NegotiateRequestOptions,
NegotiateProposalOptions,
} from './ProofsApiOptions'
import type { ProofFormat } from './formats/ProofFormat'
import type { IndyProofFormat } from './formats/indy/IndyProofFormat'
Expand All @@ -28,6 +30,7 @@ import type {
FormatRetrievedCredentialOptions,
DeleteProofOptions,
GetFormatDataReturn,
CreateProposalAsResponseOptions,
} from './models/ProofServiceOptions'
import type { ProofExchangeRecord } from './repository/ProofExchangeRecord'

Expand Down Expand Up @@ -57,11 +60,13 @@ export interface ProofsApi<PFs extends ProofFormat[], PSs extends ProofService<P
// Proposal methods
proposeProof(options: ProposeProofOptions<PFs, PSs>): Promise<ProofExchangeRecord>
acceptProposal(options: AcceptProofProposalOptions): Promise<ProofExchangeRecord>
negotiateProposal(options: NegotiateProposalOptions<PFs>): Promise<ProofExchangeRecord>

// Request methods
requestProof(options: RequestProofOptions<PFs, PSs>): Promise<ProofExchangeRecord>
acceptRequest(options: AcceptProofPresentationOptions<PFs>): Promise<ProofExchangeRecord>
declineRequest(proofRecordId: string): Promise<ProofExchangeRecord>
negotiateRequest(options: NegotiateRequestOptions<PFs>): Promise<ProofExchangeRecord>

// Present
acceptPresentation(proofRecordId: string): Promise<ProofExchangeRecord>
Expand Down Expand Up @@ -204,13 +209,14 @@ export class ProofsApi<
*/
public async acceptProposal(options: AcceptProofProposalOptions): Promise<ProofExchangeRecord> {
const { proofRecordId } = options

const proofRecord = await this.getById(proofRecordId)

const service = this.getService(proofRecord.protocolVersion)

if (!proofRecord.connectionId) {
throw new AriesFrameworkError(
`No connectionId found for credential record '${proofRecord.id}'. Connection-less issuance does not support presentation proposal or negotiation.`
`No connectionId found for proof record '${proofRecord.id}'. Connection-less issuance does not support presentation proposal or negotiation.`
)
}

Expand Down Expand Up @@ -248,6 +254,50 @@ export class ProofsApi<
return proofRecord
}

/**
* Answer with a new presentation request in response to received presentation proposal message
* to the connection associated with the proof record.
*
* @param options multiple properties like proof record id, proof formats to accept requested credentials object
* specifying which credentials to use for the proof
* @returns Proof record associated with the sent request message
*/
public async negotiateProposal(options: NegotiateProposalOptions<PFs>): Promise<ProofExchangeRecord> {
const { proofRecordId } = options

const proofRecord = await this.getById(proofRecordId)

const service = this.getService(proofRecord.protocolVersion)

if (!proofRecord.connectionId) {
throw new AriesFrameworkError(
`No connectionId found for proof record '${proofRecord.id}'. Connection-less issuance does not support negotiation.`
)
}

const connection = await this.connectionService.getById(this.agentContext, proofRecord.connectionId)

// Assert
connection.assertReady()

const requestOptions: CreateRequestAsResponseOptions<PFs> = {
proofRecord,
proofFormats: options.proofFormats,
autoAcceptProof: options.autoAcceptProof,
comment: options.comment,
}
const { message } = await service.createRequestAsResponse(this.agentContext, requestOptions)

const outboundMessageContext = new OutboundMessageContext(message, {
agentContext: this.agentContext,
connection,
associatedRecord: proofRecord,
})
await this.messageSender.sendMessage(outboundMessageContext)

return proofRecord
}

/**
* Initiate a new presentation exchange as verifier by sending a presentation request message
* to the connection with the specified connection id
Expand Down Expand Up @@ -398,6 +448,51 @@ export class ProofsApi<
return proofRecord
}

/**
* Answer with a new presentation proposal in response to received presentation request message
* to the connection associated with the proof record.
*
* @param options multiple properties like proof record id, proof format (indy/ presentation exchange)
* to include in the message
* @returns Proof record associated with the sent proposal message
*/
public async negotiateRequest(options: NegotiateRequestOptions<PFs>): Promise<ProofExchangeRecord> {
const { proofRecordId } = options
const proofRecord = await this.getById(proofRecordId)

const service = this.getService(proofRecord.protocolVersion)

if (!proofRecord.connectionId) {
throw new AriesFrameworkError(
`No connectionId found for proof record '${proofRecord.id}'. Connection-less issuance does not support presentation proposal or negotiation.`
)
}

const connection = await this.connectionService.getById(this.agentContext, proofRecord.connectionId)

// Assert
connection.assertReady()

const proposalOptions: CreateProposalAsResponseOptions<PFs> = {
proofRecord,
proofFormats: options.proofFormats,
autoAcceptProof: options.autoAcceptProof,
goalCode: options.goalCode,
comment: options.comment,
}

const { message } = await service.createProposalAsResponse(this.agentContext, proposalOptions)

const outboundMessageContext = new OutboundMessageContext(message, {
agentContext: this.agentContext,
connection,
associatedRecord: proofRecord,
})
await this.messageSender.sendMessage(outboundMessageContext)

return proofRecord
}

/**
* Accept a presentation as prover (by sending a presentation acknowledgement message) to the connection
* associated with the proof record.
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/modules/proofs/ProofsApiOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ export interface ProposeProofOptions<
autoAcceptProof?: AutoAcceptProof
parentThreadId?: string
}

export interface NegotiateRequestOptions<PFs extends ProofFormat[] = ProofFormat[]> {
proofRecordId: string
proofFormats: ProofFormatPayload<PFs, 'createProposalAsResponse'>
comment?: string
goalCode?: string
autoAcceptProof?: AutoAcceptProof
}

export interface AcceptProofPresentationOptions<PFs extends ProofFormat[] = ProofFormat[]> {
proofRecordId: string
comment?: string
Expand All @@ -68,6 +77,14 @@ export interface RequestProofOptions<
parentThreadId?: string
}

export interface NegotiateProposalOptions<PFs extends ProofFormat[] = ProofFormat[]> {
proofRecordId: string
proofFormats: ProofFormatPayload<PFs, 'createRequestAsResponse'>
comment?: string
autoAcceptProof?: AutoAcceptProof
parentThreadId?: string
}

export interface CreateProofRequestOptions<
PFs extends ProofFormat[] = ProofFormat[],
PSs extends ProofService[] = ProofService[]
Expand Down
Loading