Skip to content

Commit

Permalink
feat: auto accept proofs (#367)
Browse files Browse the repository at this point in the history
  • Loading branch information
berendsliedrecht authored Jul 19, 2021
1 parent 3331a3c commit 735d578
Show file tree
Hide file tree
Showing 15 changed files with 636 additions and 159 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ Some features are not yet supported, but are on our roadmap. Check [the roadmap]
- ✅ Present Proof Protocol ([RFC 0037](https://github.com/hyperledger/aries-rfcs/tree/master/features/0037-present-proof/README.md))
- ✅ Connection Protocol ([RFC 0160](https://github.com/hyperledger/aries-rfcs/blob/master/features/0160-connection-protocol/README.md))
- ✅ Basic Message Protocol ([RFC 0095](https://github.com/hyperledger/aries-rfcs/blob/master/features/0095-basic-message/README.md))
- ✅ Mediator Coordination Protocol ([RFC 0211](https://github.com/hyperledger/aries-rfcs/blob/master/features/0211-route-coordination/README.md))
- ✅ Indy Credentials (with `did:sov` support)
- ✅ HTTP Transport
-Mediator Coordination Protocol ([RFC 0211](https://github.com/hyperledger/aries-rfcs/blob/master/features/0211-route-coordination/README.md))
-Auto accept proofs
- 🚧 Revocation of Indy Credentials
- 🚧 Electron
- 🚧 WebSocket Transport
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/agent/AgentConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DID_COMM_TRANSPORT_QUEUE } from '../constants'
import { AriesFrameworkError } from '../error'
import { ConsoleLogger, LogLevel } from '../logger'
import { AutoAcceptCredential } from '../modules/credentials/CredentialAutoAcceptType'
import { AutoAcceptProof } from '../modules/proofs/ProofAutoAcceptType'
import { MediatorPickupStrategy } from '../modules/routing/MediatorPickupStrategy'
import { DidCommMimeType } from '../types'

Expand Down Expand Up @@ -69,6 +70,10 @@ export class AgentConfig {
return this.initConfig.autoAcceptConnections ?? false
}

public get autoAcceptProofs() {
return this.initConfig.autoAcceptProofs ?? AutoAcceptProof.Never
}

public get autoAcceptCredentials() {
return this.initConfig.autoAcceptCredentials ?? AutoAcceptCredential.Never
}
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/modules/proofs/ProofAutoAcceptType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Typing of the state for auto acceptance
*/
export enum AutoAcceptProof {
// Always auto accepts the proof no matter if it changed in subsequent steps
Always = 'always',

// Needs one acceptation and the rest will be automated if nothing changes
ContentApproved = 'contentApproved',

// DEFAULT: Never auto accept a proof
Never = 'never',
}
86 changes: 86 additions & 0 deletions packages/core/src/modules/proofs/ProofResponseCoordinator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { ProofRecord } from './repository'

import { scoped, Lifecycle } from 'tsyringe'

import { AgentConfig } from '../../agent/AgentConfig'

import { AutoAcceptProof } from './ProofAutoAcceptType'

/**
* This class handles all the automation with all the messages in the present proof protocol
* Every function returns `true` if it should automate the flow and `false` if not
*/
@scoped(Lifecycle.ContainerScoped)
export class ProofResponseCoordinator {
private agentConfig: AgentConfig

public constructor(agentConfig: AgentConfig) {
this.agentConfig = agentConfig
}

/**
* Returns the proof auto accept config based on priority:
* - The record config takes first priority
* - Otherwise the agent config
* - Otherwise {@link AutoAcceptProof.Never} is returned
*/
private static composeAutoAccept(
recordConfig: AutoAcceptProof | undefined,
agentConfig: AutoAcceptProof | undefined
) {
return recordConfig ?? agentConfig ?? AutoAcceptProof.Never
}

/**
* Checks whether it should automatically respond to a proposal
*/
public shoudlAutoRespondToProposal(proofRecord: ProofRecord) {
const autoAccept = ProofResponseCoordinator.composeAutoAccept(
proofRecord.autoAcceptProof,
this.agentConfig.autoAcceptProofs
)

if (autoAccept === AutoAcceptProof.Always) {
return true
}
return false
}

/**
* Checks whether it should automatically respond to a request
*/
public shouldAutoRespondToRequest(proofRecord: ProofRecord) {
const autoAccept = ProofResponseCoordinator.composeAutoAccept(
proofRecord.autoAcceptProof,
this.agentConfig.autoAcceptProofs
)

if (
autoAccept === AutoAcceptProof.Always ||
(autoAccept === AutoAcceptProof.ContentApproved && proofRecord.proposalMessage)
) {
return true
}

return false
}

/**
* Checks whether it should automatically respond to a presention of proof
*/
public shouldAutoRespondToPresentation(proofRecord: ProofRecord) {
const autoAccept = ProofResponseCoordinator.composeAutoAccept(
proofRecord.autoAcceptProof,
this.agentConfig.autoAcceptProofs
)

if (
autoAccept === AutoAcceptProof.Always ||
(autoAccept === AutoAcceptProof.ContentApproved && proofRecord.requestMessage)
) {
return true
}

return false
}
}
22 changes: 18 additions & 4 deletions packages/core/src/modules/proofs/ProofsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import type { ProofRecord } from './repository/ProofRecord'

import { Lifecycle, scoped } from 'tsyringe'

import { AgentConfig } from '../../agent/AgentConfig'
import { Dispatcher } from '../../agent/Dispatcher'
import { MessageSender } from '../../agent/MessageSender'
import { createOutboundMessage } from '../../agent/helpers'
import { AriesFrameworkError } from '../../error'
import { ConnectionService } from '../connections/services/ConnectionService'

import { ProofResponseCoordinator } from './ProofResponseCoordinator'
import {
ProposePresentationHandler,
RequestPresentationHandler,
Expand All @@ -24,16 +26,22 @@ export class ProofsModule {
private proofService: ProofService
private connectionService: ConnectionService
private messageSender: MessageSender
private agentConfig: AgentConfig
private proofResponseCoordinator: ProofResponseCoordinator

public constructor(
dispatcher: Dispatcher,
proofService: ProofService,
connectionService: ConnectionService,
messageSender: MessageSender
agentConfig: AgentConfig,
messageSender: MessageSender,
proofResponseCoordinator: ProofResponseCoordinator
) {
this.proofService = proofService
this.connectionService = connectionService
this.messageSender = messageSender
this.agentConfig = agentConfig
this.proofResponseCoordinator = proofResponseCoordinator
this.registerHandlers(dispatcher)
}

Expand Down Expand Up @@ -270,9 +278,15 @@ export class ProofsModule {
}

private registerHandlers(dispatcher: Dispatcher) {
dispatcher.registerHandler(new ProposePresentationHandler(this.proofService))
dispatcher.registerHandler(new RequestPresentationHandler(this.proofService))
dispatcher.registerHandler(new PresentationHandler(this.proofService))
dispatcher.registerHandler(
new ProposePresentationHandler(this.proofService, this.agentConfig, this.proofResponseCoordinator)
)
dispatcher.registerHandler(
new RequestPresentationHandler(this.proofService, this.agentConfig, this.proofResponseCoordinator)
)
dispatcher.registerHandler(
new PresentationHandler(this.proofService, this.agentConfig, this.proofResponseCoordinator)
)
dispatcher.registerHandler(new PresentationAckHandler(this.proofService))
}
}
35 changes: 33 additions & 2 deletions packages/core/src/modules/proofs/handlers/PresentationHandler.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
import type { AgentConfig } from '../../../agent/AgentConfig'
import type { Handler, HandlerInboundMessage } from '../../../agent/Handler'
import type { ProofResponseCoordinator } from '../ProofResponseCoordinator'
import type { ProofRecord } from '../repository'
import type { ProofService } from '../services'

import { createOutboundMessage } from '../../../agent/helpers'
import { PresentationMessage } from '../messages'

export class PresentationHandler implements Handler {
private proofService: ProofService
private agentConfig: AgentConfig
private proofResponseCoordinator: ProofResponseCoordinator
public supportedMessages = [PresentationMessage]

public constructor(proofService: ProofService) {
public constructor(
proofService: ProofService,
agentConfig: AgentConfig,
proofResponseCoordinator: ProofResponseCoordinator
) {
this.proofService = proofService
this.agentConfig = agentConfig
this.proofResponseCoordinator = proofResponseCoordinator
}

public async handle(messageContext: HandlerInboundMessage<PresentationHandler>) {
await this.proofService.processPresentation(messageContext)
const proofRecord = await this.proofService.processPresentation(messageContext)

if (this.proofResponseCoordinator.shouldAutoRespondToPresentation(proofRecord)) {
return await this.createAck(proofRecord, messageContext)
}
}

private async createAck(proofRecord: ProofRecord, messageContext: HandlerInboundMessage<PresentationHandler>) {
this.agentConfig.logger.info(
`Automatically sending acknowledgement with autoAccept on ${this.agentConfig.autoAcceptProofs}`
)

if (!messageContext.connection) {
this.agentConfig.logger.error('No connection on the messageContext')
return
}

const { message } = await this.proofService.createAck(proofRecord)

return createOutboundMessage(messageContext.connection, message)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,62 @@
import type { AgentConfig } from '../../../agent/AgentConfig'
import type { Handler, HandlerInboundMessage } from '../../../agent/Handler'
import type { ProofResponseCoordinator } from '../ProofResponseCoordinator'
import type { ProofRecord } from '../repository'
import type { ProofService } from '../services'

import { createOutboundMessage } from '../../../agent/helpers'
import { ProposePresentationMessage } from '../messages'

export class ProposePresentationHandler implements Handler {
private proofService: ProofService
private agentConfig: AgentConfig
private proofResponseCoordinator: ProofResponseCoordinator
public supportedMessages = [ProposePresentationMessage]

public constructor(proofService: ProofService) {
public constructor(
proofService: ProofService,
agentConfig: AgentConfig,
proofResponseCoordinator: ProofResponseCoordinator
) {
this.proofService = proofService
this.agentConfig = agentConfig
this.proofResponseCoordinator = proofResponseCoordinator
}

public async handle(messageContext: HandlerInboundMessage<ProposePresentationHandler>) {
await this.proofService.processProposal(messageContext)
const proofRecord = await this.proofService.processProposal(messageContext)

if (this.proofResponseCoordinator.shoudlAutoRespondToProposal(proofRecord)) {
return await this.createRequest(proofRecord, messageContext)
}
}

private async createRequest(
proofRecord: ProofRecord,
messageContext: HandlerInboundMessage<ProposePresentationHandler>
) {
this.agentConfig.logger.info(
`Automatically sending request with autoAccept on ${this.agentConfig.autoAcceptProofs}`
)

if (!messageContext.connection) {
this.agentConfig.logger.error('No connection on the messageContext')
return
}
if (!proofRecord.proposalMessage) {
this.agentConfig.logger.error(`Proof record with id ${proofRecord.id} is missing required credential proposal`)
return
}
const proofRequest = await this.proofService.createProofRequestFromProposal(
proofRecord.proposalMessage.presentationProposal,
{
name: 'proof-request',
version: '1.0',
}
)

const { message } = await this.proofService.createRequestAsResponse(proofRecord, proofRequest)

return createOutboundMessage(messageContext.connection, message)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,64 @@
import type { AgentConfig } from '../../../agent/AgentConfig'
import type { Handler, HandlerInboundMessage } from '../../../agent/Handler'
import type { ProofResponseCoordinator } from '../ProofResponseCoordinator'
import type { ProofRecord } from '../repository'
import type { ProofService } from '../services'

import { createOutboundMessage } from '../../../agent/helpers'
import { RequestPresentationMessage } from '../messages'

export class RequestPresentationHandler implements Handler {
private proofService: ProofService
private agentConfig: AgentConfig
private proofResponseCoordinator: ProofResponseCoordinator
public supportedMessages = [RequestPresentationMessage]

public constructor(proofService: ProofService) {
public constructor(
proofService: ProofService,
agentConfig: AgentConfig,
proofResponseCoordinator: ProofResponseCoordinator
) {
this.proofService = proofService
this.agentConfig = agentConfig
this.proofResponseCoordinator = proofResponseCoordinator
}

public async handle(messageContext: HandlerInboundMessage<RequestPresentationHandler>) {
await this.proofService.processRequest(messageContext)
const proofRecord = await this.proofService.processRequest(messageContext)

if (this.proofResponseCoordinator.shouldAutoRespondToRequest(proofRecord)) {
return await this.createPresentation(proofRecord, messageContext)
}
}

private async createPresentation(
proofRecord: ProofRecord,
messageContext: HandlerInboundMessage<RequestPresentationHandler>
) {
const indyProofRequest = proofRecord.requestMessage?.indyProofRequest

this.agentConfig.logger.info(
`Automatically sending presentation with autoAccept on ${this.agentConfig.autoAcceptProofs}`
)

if (!messageContext.connection) {
this.agentConfig.logger.error('No connection on the messageContext')
return
}

if (!indyProofRequest) {
return
}

const retrievedCredentials = await this.proofService.getRequestedCredentialsForProofRequest(
indyProofRequest,
proofRecord.proposalMessage?.presentationProposal
)

const requestedCredentials = this.proofService.autoSelectCredentialsForProofRequest(retrievedCredentials)

const { message } = await this.proofService.createPresentation(proofRecord, requestedCredentials)

return createOutboundMessage(messageContext.connection, message)
}
}
1 change: 1 addition & 0 deletions packages/core/src/modules/proofs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './ProofState'
export * from './repository'
export * from './ProofEvents'
export * from './ProofsModule'
export * from './ProofAutoAcceptType'
Loading

0 comments on commit 735d578

Please sign in to comment.