Skip to content

Commit

Permalink
feat: credentials api decline offer report (#1800)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra authored Mar 27, 2024
1 parent 5992c57 commit 15c62a8
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 15 deletions.
50 changes: 36 additions & 14 deletions packages/core/src/modules/credentials/CredentialsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
SendCredentialProblemReportOptions,
DeleteCredentialOptions,
SendRevocationNotificationOptions,
DeclineCredentialOfferOptions,
} from './CredentialsApiOptions'
import type { CredentialProtocol } from './protocol/CredentialProtocol'
import type { CredentialFormatsFromProtocols } from './protocol/CredentialProtocolOptions'
Expand Down Expand Up @@ -48,7 +49,7 @@ export interface CredentialsApi<CPs extends CredentialProtocol[]> {
// Offer Credential Methods
offerCredential(options: OfferCredentialOptions<CPs>): Promise<CredentialExchangeRecord>
acceptOffer(options: AcceptCredentialOfferOptions<CPs>): Promise<CredentialExchangeRecord>
declineOffer(credentialRecordId: string): Promise<CredentialExchangeRecord>
declineOffer(credentialRecordId: string, options?: DeclineCredentialOfferOptions): Promise<CredentialExchangeRecord>
negotiateOffer(options: NegotiateCredentialOfferOptions<CPs>): Promise<CredentialExchangeRecord>

// Request Credential Methods
Expand Down Expand Up @@ -324,12 +325,22 @@ export class CredentialsApi<CPs extends CredentialProtocol[]> implements Credent
return credentialRecord
}

public async declineOffer(credentialRecordId: string): Promise<CredentialExchangeRecord> {
public async declineOffer(
credentialRecordId: string,
options?: DeclineCredentialOfferOptions
): Promise<CredentialExchangeRecord> {
const credentialRecord = await this.getById(credentialRecordId)
credentialRecord.assertState(CredentialState.OfferReceived)

// with version we can get the Service
const protocol = this.getProtocol(credentialRecord.protocolVersion)
if (options?.sendProblemReport) {
await this.sendProblemReport({
credentialRecordId,
description: options.problemReportDescription ?? 'Offer declined',
})
}

await protocol.updateState(this.agentContext, credentialRecord, CredentialState.Declined)

return credentialRecord
Expand Down Expand Up @@ -532,29 +543,40 @@ export class CredentialsApi<CPs extends CredentialProtocol[]> implements Credent
/**
* Send problem report message for a credential record
* @param credentialRecordId The id of the credential record for which to send problem report
* @param message message to send
* @returns credential record associated with the credential problem report message
*/
public async sendProblemReport(options: SendCredentialProblemReportOptions) {
const credentialRecord = await this.getById(options.credentialRecordId)
if (!credentialRecord.connectionId) {
throw new CredoError(`No connectionId found for credential record '${credentialRecord.id}'.`)
}
const connectionRecord = await this.connectionService.getById(this.agentContext, credentialRecord.connectionId)

const protocol = this.getProtocol(credentialRecord.protocolVersion)
const { message } = await protocol.createProblemReport(this.agentContext, {

const offerMessage = await protocol.findOfferMessage(this.agentContext, credentialRecord.id)

const { message: problemReport } = await protocol.createProblemReport(this.agentContext, {
description: options.description,
credentialRecord,
})
message.setThread({
threadId: credentialRecord.threadId,
parentThreadId: credentialRecord.parentThreadId,
})

// Use connection if present
const connectionRecord = credentialRecord.connectionId
? await this.connectionService.getById(this.agentContext, credentialRecord.connectionId)
: undefined
connectionRecord?.assertReady()

// If there's no connection (so connection-less, we require the state to be offer received)
if (!connectionRecord) {
credentialRecord.assertState(CredentialState.OfferReceived)

if (!offerMessage) {
throw new CredoError(`No offer message found for credential record with id '${credentialRecord.id}'`)
}
}

const outboundMessageContext = await getOutboundMessageContext(this.agentContext, {
message,
associatedRecord: credentialRecord,
message: problemReport,
connectionRecord,
associatedRecord: credentialRecord,
lastReceivedMessage: offerMessage ?? undefined,
})
await this.messageSender.sendMessage(outboundMessageContext)

Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/modules/credentials/CredentialsApiOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,25 @@ export interface SendCredentialProblemReportOptions {
credentialRecordId: string
description: string
}

/**
* Interface for CredentialsApi.declineOffer. Decline a received credential offer and optionally send a problem-report message to Issuer.
*/
export interface DeclineCredentialOfferOptions {
// TODO: in next major release, move the id to this object as well
// for consistency with the proofs api
// credentialRecordId: string

/**
* Whether to send a problem-report message to the issuer as part
* of declining the credential offer
*/
sendProblemReport?: boolean

/**
* Description to include in the problem-report message
* Only used if `sendProblemReport` is set to `true`.
* @default "Offer declined"
*/
problemReportDescription?: string
}
5 changes: 4 additions & 1 deletion packages/core/src/modules/proofs/ProofsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,10 @@ export class ProofsApi<PPs extends ProofProtocol[]> implements ProofsApi<PPs> {

const protocol = this.getProtocol(proofRecord.protocolVersion)
if (options.sendProblemReport) {
await this.sendProblemReport({ proofRecordId: options.proofRecordId, description: 'Request declined' })
await this.sendProblemReport({
proofRecordId: options.proofRecordId,
description: options.problemReportDescription ?? 'Request declined',
})
}

await protocol.updateState(this.agentContext, proofRecord, ProofState.Declined)
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/modules/proofs/ProofsApiOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,5 +179,17 @@ export interface SendProofProblemReportOptions {
*/
export interface DeclineProofRequestOptions {
proofRecordId: string

/**
* Whether to send a problem-report message to the verifier as part
* of declining the proof request
*/
sendProblemReport?: boolean

/**
* Description to include in the problem-report message
* Only used if `sendProblemReport` is set to `true`.
* @default "Request declined"
*/
problemReportDescription?: string
}

0 comments on commit 15c62a8

Please sign in to comment.