diff --git a/demo/src/Alice.ts b/demo/src/Alice.ts index 359cd7ac31..54eae3b019 100644 --- a/demo/src/Alice.ts +++ b/demo/src/Alice.ts @@ -103,11 +103,17 @@ export class Alice extends BaseAgent { } public async acceptProofRequest(proofRecord: ProofRecord) { - const retrievedCredentials = await this.agent.proofs.getRequestedCredentialsForProofRequest(proofRecord.id, { - filterByPresentationPreview: true, + const requestedCredentials = await this.agent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: proofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + await this.agent.proofs.acceptRequest({ + proofRecordId: proofRecord.id, + proofFormats: requestedCredentials.proofFormats, }) - const requestedCredentials = this.agent.proofs.autoSelectCredentialsForProofRequest(retrievedCredentials) - await this.agent.proofs.acceptRequest(proofRecord.id, requestedCredentials) console.log(greenText('\nProof request accepted!\n')) } diff --git a/demo/src/Faber.ts b/demo/src/Faber.ts index c5b23058e6..e94b3a922b 100644 --- a/demo/src/Faber.ts +++ b/demo/src/Faber.ts @@ -2,7 +2,13 @@ import type { ConnectionRecord } from '@aries-framework/core' import type { CredDef, Schema } from 'indy-sdk' import type BottomBar from 'inquirer/lib/ui/bottom-bar' -import { V1CredentialPreview, AttributeFilter, ProofAttributeInfo, utils } from '@aries-framework/core' +import { + AttributeFilter, + ProofAttributeInfo, + ProofProtocolVersion, + utils, + V1CredentialPreview, +} from '@aries-framework/core' import { ui } from 'inquirer' import { BaseAgent } from './BaseAgent' @@ -137,8 +143,18 @@ export class Faber extends BaseAgent { const connectionRecord = await this.getConnectionRecord() const proofAttribute = await this.newProofAttribute() await this.printProofFlow(greenText('\nRequesting proof...\n', false)) - await this.agent.proofs.requestProof(connectionRecord.id, { - requestedAttributes: proofAttribute, + + await this.agent.proofs.requestProof({ + protocolVersion: ProofProtocolVersion.V1, + connectionId: connectionRecord.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: proofAttribute, + }, + }, }) this.ui.updateBottomBar( `\nProof request sent!\n\nGo to the Alice agent to accept the proof request\n\n${Color.Reset}` diff --git a/packages/core/src/agent/AgentConfig.ts b/packages/core/src/agent/AgentConfig.ts index 1f391d481d..be90bdf17b 100644 --- a/packages/core/src/agent/AgentConfig.ts +++ b/packages/core/src/agent/AgentConfig.ts @@ -6,7 +6,7 @@ import { DID_COMM_TRANSPORT_QUEUE } from '../constants' import { AriesFrameworkError } from '../error' import { ConsoleLogger, LogLevel } from '../logger' import { AutoAcceptCredential } from '../modules/credentials/models/CredentialAutoAcceptType' -import { AutoAcceptProof } from '../modules/proofs/ProofAutoAcceptType' +import { AutoAcceptProof } from '../modules/proofs/models/ProofAutoAcceptType' import { DidCommMimeType } from '../types' export class AgentConfig { diff --git a/packages/core/src/agent/BaseAgent.ts b/packages/core/src/agent/BaseAgent.ts index 2a895f777b..c18f937f25 100644 --- a/packages/core/src/agent/BaseAgent.ts +++ b/packages/core/src/agent/BaseAgent.ts @@ -83,7 +83,7 @@ export abstract class BaseAgent { // We set the modules in the constructor because that allows to set them as read-only this.connections = this.dependencyManager.resolve(ConnectionsApi) this.credentials = this.dependencyManager.resolve(CredentialsApi) as CredentialsApi - this.proofs = this.dependencyManager.resolve(ProofsApi) + this.proofs = this.dependencyManager.resolve(ProofsApi) as ProofsApi this.mediator = this.dependencyManager.resolve(MediatorApi) this.mediationRecipient = this.dependencyManager.resolve(RecipientApi) this.basicMessages = this.dependencyManager.resolve(BasicMessagesApi) diff --git a/packages/core/src/agent/__tests__/Agent.test.ts b/packages/core/src/agent/__tests__/Agent.test.ts index 7c92573fa4..c890630ca9 100644 --- a/packages/core/src/agent/__tests__/Agent.test.ts +++ b/packages/core/src/agent/__tests__/Agent.test.ts @@ -10,8 +10,10 @@ import { CredentialRepository } from '../../modules/credentials' import { CredentialsApi } from '../../modules/credentials/CredentialsApi' import { IndyLedgerService } from '../../modules/ledger' import { LedgerApi } from '../../modules/ledger/LedgerApi' -import { ProofRepository, ProofService } from '../../modules/proofs' +import { ProofRepository } from '../../modules/proofs' import { ProofsApi } from '../../modules/proofs/ProofsApi' +import { V1ProofService } from '../../modules/proofs/protocol/v1' +import { V2ProofService } from '../../modules/proofs/protocol/v2' import { MediatorApi, RecipientApi, @@ -115,8 +117,9 @@ describe('Agent', () => { expect(container.resolve(ConnectionRepository)).toBeInstanceOf(ConnectionRepository) expect(container.resolve(TrustPingService)).toBeInstanceOf(TrustPingService) + expect(container.resolve(V1ProofService)).toBeInstanceOf(V1ProofService) + expect(container.resolve(V2ProofService)).toBeInstanceOf(V2ProofService) expect(container.resolve(ProofsApi)).toBeInstanceOf(ProofsApi) - expect(container.resolve(ProofService)).toBeInstanceOf(ProofService) expect(container.resolve(ProofRepository)).toBeInstanceOf(ProofRepository) expect(container.resolve(CredentialsApi)).toBeInstanceOf(CredentialsApi) @@ -157,8 +160,9 @@ describe('Agent', () => { expect(container.resolve(ConnectionRepository)).toBe(container.resolve(ConnectionRepository)) expect(container.resolve(TrustPingService)).toBe(container.resolve(TrustPingService)) + expect(container.resolve(V1ProofService)).toBe(container.resolve(V1ProofService)) + expect(container.resolve(V2ProofService)).toBe(container.resolve(V2ProofService)) expect(container.resolve(ProofsApi)).toBe(container.resolve(ProofsApi)) - expect(container.resolve(ProofService)).toBe(container.resolve(ProofService)) expect(container.resolve(ProofRepository)).toBe(container.resolve(ProofRepository)) expect(container.resolve(CredentialsApi)).toBe(container.resolve(CredentialsApi)) diff --git a/packages/core/src/decorators/ack/AckDecorator.test.ts b/packages/core/src/decorators/ack/AckDecorator.test.ts index 324d997d99..257039be98 100644 --- a/packages/core/src/decorators/ack/AckDecorator.test.ts +++ b/packages/core/src/decorators/ack/AckDecorator.test.ts @@ -4,6 +4,7 @@ import { JsonTransformer } from '../../utils/JsonTransformer' import { MessageValidator } from '../../utils/MessageValidator' import { Compose } from '../../utils/mixins' +import { AckValues } from './AckDecorator' import { AckDecorated } from './AckDecoratorExtension' describe('Decorators | AckDecoratorExtension', () => { @@ -15,7 +16,7 @@ describe('Decorators | AckDecoratorExtension', () => { test('transforms AckDecorator class to JSON', () => { const message = new TestMessage() - message.setPleaseAck() + message.setPleaseAck([AckValues.Receipt]) expect(message.toJSON()).toEqual({ '@id': undefined, '@type': undefined, diff --git a/packages/core/src/modules/credentials/formats/CredentialFormatService.ts b/packages/core/src/modules/credentials/formats/CredentialFormatService.ts index 9d3f6f5da9..bf3c842d29 100644 --- a/packages/core/src/modules/credentials/formats/CredentialFormatService.ts +++ b/packages/core/src/modules/credentials/formats/CredentialFormatService.ts @@ -1,6 +1,4 @@ import type { AgentContext } from '../../../agent' -import type { EventEmitter } from '../../../agent/EventEmitter' -import type { CredentialRepository } from '../repository' import type { CredentialFormat } from './CredentialFormat' import type { FormatCreateProposalOptions, @@ -23,14 +21,6 @@ import { Attachment, AttachmentData } from '../../../decorators/attachment/Attac import { JsonEncoder } from '../../../utils/JsonEncoder' export abstract class CredentialFormatService { - protected credentialRepository: CredentialRepository - protected eventEmitter: EventEmitter - - public constructor(credentialRepository: CredentialRepository, eventEmitter: EventEmitter) { - this.credentialRepository = credentialRepository - this.eventEmitter = eventEmitter - } - abstract readonly formatKey: CF['formatKey'] abstract readonly credentialRecordType: CF['credentialRecordType'] @@ -86,7 +76,6 @@ export abstract class CredentialFormatService { - const credProposalJson = attachment.getDataAsJson() + const proposalJson = attachment.getDataAsJson() - if (!credProposalJson) { - throw new AriesFrameworkError('Missing indy credential proposal data payload') - } - - const credProposal = JsonTransformer.fromJSON(credProposalJson, IndyCredPropose) - MessageValidator.validateSync(credProposal) + // fromJSON also validates + JsonTransformer.fromJSON(proposalJson, IndyCredPropose) } public async acceptProposal( diff --git a/packages/core/src/modules/indy/services/IndyHolderService.ts b/packages/core/src/modules/indy/services/IndyHolderService.ts index e92b20896f..a53f2b7049 100644 --- a/packages/core/src/modules/indy/services/IndyHolderService.ts +++ b/packages/core/src/modules/indy/services/IndyHolderService.ts @@ -1,5 +1,5 @@ import type { AgentContext } from '../../../agent' -import type { RequestedCredentials } from '../../proofs' +import type { RequestedCredentials } from '../../proofs/formats/indy/models/RequestedCredentials' import type * as Indy from 'indy-sdk' import { AgentDependencies } from '../../../agent/AgentDependencies' diff --git a/packages/core/src/modules/indy/services/IndyRevocationService.ts b/packages/core/src/modules/indy/services/IndyRevocationService.ts index fa84997876..52c666d3ca 100644 --- a/packages/core/src/modules/indy/services/IndyRevocationService.ts +++ b/packages/core/src/modules/indy/services/IndyRevocationService.ts @@ -1,6 +1,6 @@ import type { AgentContext } from '../../../agent' import type { IndyRevocationInterval } from '../../credentials' -import type { RequestedCredentials } from '../../proofs' +import type { RequestedCredentials } from '../../proofs/formats/indy/models/RequestedCredentials' import type { default as Indy } from 'indy-sdk' import { AgentDependencies } from '../../../agent/AgentDependencies' diff --git a/packages/core/src/modules/proofs/ProofEvents.ts b/packages/core/src/modules/proofs/ProofEvents.ts index b3612dc9c6..ba1c7b047b 100644 --- a/packages/core/src/modules/proofs/ProofEvents.ts +++ b/packages/core/src/modules/proofs/ProofEvents.ts @@ -1,5 +1,5 @@ import type { BaseEvent } from '../../agent/Events' -import type { ProofState } from './ProofState' +import type { ProofState } from './models/ProofState' import type { ProofRecord } from './repository' export enum ProofEventTypes { diff --git a/packages/core/src/modules/proofs/ProofResponseCoordinator.ts b/packages/core/src/modules/proofs/ProofResponseCoordinator.ts index e101bd003d..24bf56dda5 100644 --- a/packages/core/src/modules/proofs/ProofResponseCoordinator.ts +++ b/packages/core/src/modules/proofs/ProofResponseCoordinator.ts @@ -1,10 +1,10 @@ -import type { AgentContext } from '../../agent/context' +import type { AgentContext } from '../../agent/context/AgentContext' import type { ProofRecord } from './repository' import { injectable } from '../../plugins' -import { AutoAcceptProof } from './ProofAutoAcceptType' -import { ProofsModuleConfig } from './ProofsModuleConfig' +import { ProofService } from './ProofService' +import { AutoAcceptProof } from './models/ProofAutoAcceptType' /** * This class handles all the automation with all the messages in the present proof protocol @@ -12,11 +12,12 @@ import { ProofsModuleConfig } from './ProofsModuleConfig' */ @injectable() export class ProofResponseCoordinator { - private proofsModuleConfig: ProofsModuleConfig + private proofService: ProofService - public constructor(proofsModuleConfig: ProofsModuleConfig) { - this.proofsModuleConfig = proofsModuleConfig + public constructor(proofService: ProofService) { + this.proofService = proofService } + /** * Returns the proof auto accept config based on priority: * - The record config takes first priority @@ -36,12 +37,17 @@ export class ProofResponseCoordinator { public shouldAutoRespondToProposal(agentContext: AgentContext, proofRecord: ProofRecord) { const autoAccept = ProofResponseCoordinator.composeAutoAccept( proofRecord.autoAcceptProof, - this.proofsModuleConfig.autoAcceptProofs + agentContext.config.autoAcceptProofs ) if (autoAccept === AutoAcceptProof.Always) { return true } + + if (autoAccept === AutoAcceptProof.ContentApproved) { + return this.proofService.shouldAutoRespondToProposal(agentContext, proofRecord) + } + return false } @@ -51,16 +57,17 @@ export class ProofResponseCoordinator { public shouldAutoRespondToRequest(agentContext: AgentContext, proofRecord: ProofRecord) { const autoAccept = ProofResponseCoordinator.composeAutoAccept( proofRecord.autoAcceptProof, - this.proofsModuleConfig.autoAcceptProofs + agentContext.config.autoAcceptProofs ) - if ( - autoAccept === AutoAcceptProof.Always || - (autoAccept === AutoAcceptProof.ContentApproved && proofRecord.proposalMessage) - ) { + if (autoAccept === AutoAcceptProof.Always) { return true } + if (autoAccept === AutoAcceptProof.ContentApproved) { + return this.proofService.shouldAutoRespondToRequest(agentContext, proofRecord) + } + return false } @@ -70,16 +77,17 @@ export class ProofResponseCoordinator { public shouldAutoRespondToPresentation(agentContext: AgentContext, proofRecord: ProofRecord) { const autoAccept = ProofResponseCoordinator.composeAutoAccept( proofRecord.autoAcceptProof, - this.proofsModuleConfig.autoAcceptProofs + agentContext.config.autoAcceptProofs ) - if ( - autoAccept === AutoAcceptProof.Always || - (autoAccept === AutoAcceptProof.ContentApproved && proofRecord.requestMessage) - ) { + if (autoAccept === AutoAcceptProof.Always) { return true } + if (autoAccept === AutoAcceptProof.ContentApproved) { + return this.proofService.shouldAutoRespondToPresentation(agentContext, proofRecord) + } + return false } } diff --git a/packages/core/src/modules/proofs/ProofService.ts b/packages/core/src/modules/proofs/ProofService.ts new file mode 100644 index 0000000000..e52376fd92 --- /dev/null +++ b/packages/core/src/modules/proofs/ProofService.ts @@ -0,0 +1,232 @@ +import type { AgentConfig } from '../../agent/AgentConfig' +import type { AgentMessage } from '../../agent/AgentMessage' +import type { Dispatcher } from '../../agent/Dispatcher' +import type { EventEmitter } from '../../agent/EventEmitter' +import type { AgentContext } from '../../agent/context/AgentContext' +import type { InboundMessageContext } from '../../agent/models/InboundMessageContext' +import type { Logger } from '../../logger' +import type { DidCommMessageRepository, DidCommMessageRole } from '../../storage' +import type { Wallet } from '../../wallet/Wallet' +import type { ConnectionService } from '../connections/services' +import type { MediationRecipientService, RoutingService } from '../routing' +import type { ProofStateChangedEvent } from './ProofEvents' +import type { ProofResponseCoordinator } from './ProofResponseCoordinator' +import type { ProofFormat } from './formats/ProofFormat' +import type { CreateProblemReportOptions } from './formats/models/ProofFormatServiceOptions' +import type { + CreateAckOptions, + CreatePresentationOptions, + CreateProofRequestFromProposalOptions, + CreateProposalAsResponseOptions, + CreateProposalOptions, + CreateRequestAsResponseOptions, + CreateRequestOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, + GetRequestedCredentialsForProofRequestOptions, + ProofRequestFromProposalOptions, +} from './models/ProofServiceOptions' +import type { ProofState } from './models/ProofState' +import type { ProofRecord, ProofRepository } from './repository' + +import { JsonTransformer } from '../../utils/JsonTransformer' + +import { ProofEventTypes } from './ProofEvents' + +export abstract class ProofService { + protected proofRepository: ProofRepository + protected didCommMessageRepository: DidCommMessageRepository + protected eventEmitter: EventEmitter + protected connectionService: ConnectionService + protected wallet: Wallet + protected logger: Logger + + public constructor( + agentConfig: AgentConfig, + proofRepository: ProofRepository, + connectionService: ConnectionService, + didCommMessageRepository: DidCommMessageRepository, + wallet: Wallet, + eventEmitter: EventEmitter + ) { + this.proofRepository = proofRepository + this.connectionService = connectionService + this.didCommMessageRepository = didCommMessageRepository + this.eventEmitter = eventEmitter + this.wallet = wallet + this.logger = agentConfig.logger + } + abstract readonly version: string + + public async generateProofRequestNonce() { + return await this.wallet.generateNonce() + } + + public emitStateChangedEvent(agentContext: AgentContext, proofRecord: ProofRecord, previousState: ProofState | null) { + const clonedProof = JsonTransformer.clone(proofRecord) + + this.eventEmitter.emit(agentContext, { + type: ProofEventTypes.ProofStateChanged, + payload: { + proofRecord: clonedProof, + previousState: previousState, + }, + }) + } + + /** + * Update the record to a new state and emit an state changed event. Also updates the record + * in storage. + * + * @param proofRecord The proof record to update the state for + * @param newState The state to update to + * + */ + public async updateState(agentContext: AgentContext, proofRecord: ProofRecord, newState: ProofState) { + const previousState = proofRecord.state + proofRecord.state = newState + await this.proofRepository.update(agentContext, proofRecord) + + this.emitStateChangedEvent(agentContext, proofRecord, previousState) + } + + public update(agentContext: AgentContext, proofRecord: ProofRecord) { + return this.proofRepository.update(agentContext, proofRecord) + } + + /** + * 1. Assert (connection ready, record state) + * 2. Create proposal message + * 3. loop through all formats from ProposeProofOptions and call format service + * 4. Create and store proof record + * 5. Store proposal message + * 6. Return proposal message + proof record + */ + abstract createProposal( + agentContext: AgentContext, + options: CreateProposalOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + /** + * Create a proposal message in response to a received proof request message + * + * 1. assert record state + * 2. Create proposal message + * 3. loop through all formats from ProposeProofOptions and call format service + * 4. Update proof record + * 5. Create or update proposal message + * 6. Return proposal message + proof record + */ + abstract createProposalAsResponse( + agentContext: AgentContext, + options: CreateProposalAsResponseOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + /** + * Process a received proposal message (does not accept yet) + * + * 1. Find proof record by thread and connection id + * + * Two flows possible: + * - Proof record already exist + * 2. Assert state + * 3. Save or update proposal message in storage (didcomm message record) + * 4. Loop through all format services to process proposal message + * 5. Update & return record + * + * - Proof record does not exist yet + * 2. Create record + * 3. Save proposal message + * 4. Loop through all format services to process proposal message + * 5. Save & return record + */ + abstract processProposal(messageContext: InboundMessageContext): Promise + + abstract createRequest( + agentContext: AgentContext, + options: CreateRequestOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + abstract createRequestAsResponse( + agentContext: AgentContext, + options: CreateRequestAsResponseOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + abstract processRequest(messageContext: InboundMessageContext): Promise + + abstract createPresentation( + agentContext: AgentContext, + options: CreatePresentationOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + abstract processPresentation(messageContext: InboundMessageContext): Promise + + abstract createAck( + agentContext: AgentContext, + options: CreateAckOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + abstract processAck(messageContext: InboundMessageContext): Promise + + abstract createProblemReport( + agentContext: AgentContext, + options: CreateProblemReportOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> + + abstract processProblemReport(messageContext: InboundMessageContext): Promise + + public abstract shouldAutoRespondToProposal(agentContext: AgentContext, proofRecord: ProofRecord): Promise + + public abstract shouldAutoRespondToRequest(agentContext: AgentContext, proofRecord: ProofRecord): Promise + + public abstract shouldAutoRespondToPresentation( + agentContext: AgentContext, + proofRecord: ProofRecord + ): Promise + + public abstract registerHandlers( + dispatcher: Dispatcher, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + mediationRecipientService: MediationRecipientService, + routingService: RoutingService + ): void + + public abstract findRequestMessage(agentContext: AgentContext, proofRecordId: string): Promise + + public abstract findPresentationMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise + + public abstract findProposalMessage(agentContext: AgentContext, proofRecordId: string): Promise + + public async saveOrUpdatePresentationMessage( + agentContext: AgentContext, + options: { + proofRecord: ProofRecord + message: AgentMessage + role: DidCommMessageRole + } + ): Promise { + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + agentMessage: options.message, + role: options.role, + }) + } + + public abstract getRequestedCredentialsForProofRequest( + agentContext: AgentContext, + options: GetRequestedCredentialsForProofRequestOptions + ): Promise> + + public abstract autoSelectCredentialsForProofRequest( + options: FormatRetrievedCredentialOptions + ): Promise> + + public abstract createProofRequestFromProposal( + agentContext: AgentContext, + options: CreateProofRequestFromProposalOptions + ): Promise> +} diff --git a/packages/core/src/modules/proofs/ProofsApi.ts b/packages/core/src/modules/proofs/ProofsApi.ts index 86af444d13..fd25819787 100644 --- a/packages/core/src/modules/proofs/ProofsApi.ts +++ b/packages/core/src/modules/proofs/ProofsApi.ts @@ -1,90 +1,168 @@ -import type { AutoAcceptProof } from './ProofAutoAcceptType' -import type { PresentationPreview, RequestPresentationMessage } from './messages' -import type { RequestedCredentials, RetrievedCredentials } from './models' -import type { ProofRequestOptions } from './models/ProofRequest' +import type { AgentMessage } from '../../agent/AgentMessage' +import type { ProofService } from './ProofService' +import type { + AcceptPresentationOptions, + AcceptProposalOptions, + OutOfBandRequestOptions, + ProposeProofOptions, + RequestProofOptions, + ServiceMap, +} from './ProofsApiOptions' +import type { ProofFormat } from './formats/ProofFormat' +import type { IndyProofFormat } from './formats/indy/IndyProofFormat' +import type { AutoSelectCredentialsForProofRequestOptions } from './models/ModuleOptions' +import type { + CreateOutOfBandRequestOptions, + CreatePresentationOptions, + CreateProposalOptions, + CreateRequestOptions, + CreateRequestAsResponseOptions, + CreateProofRequestFromProposalOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, +} from './models/ProofServiceOptions' import type { ProofRecord } from './repository/ProofRecord' -import { AgentContext } from '../../agent' +import { inject, injectable } from 'tsyringe' + +import { AgentConfig } from '../../agent/AgentConfig' import { Dispatcher } from '../../agent/Dispatcher' import { MessageSender } from '../../agent/MessageSender' +import { AgentContext } from '../../agent/context/AgentContext' import { createOutboundMessage } from '../../agent/helpers' import { InjectionSymbols } from '../../constants' import { ServiceDecorator } from '../../decorators/service/ServiceDecorator' import { AriesFrameworkError } from '../../error' import { Logger } from '../../logger' -import { inject, injectable } from '../../plugins' +import { DidCommMessageRole } from '../../storage/didcomm/DidCommMessageRole' import { ConnectionService } from '../connections/services/ConnectionService' +import { MediationRecipientService } from '../routing/services/MediationRecipientService' import { RoutingService } from '../routing/services/RoutingService' import { ProofResponseCoordinator } from './ProofResponseCoordinator' -import { PresentationProblemReportReason } from './errors' -import { - PresentationAckHandler, - PresentationHandler, - PresentationProblemReportHandler, - ProposePresentationHandler, - RequestPresentationHandler, -} from './handlers' -import { PresentationProblemReportMessage } from './messages/PresentationProblemReportMessage' -import { ProofRequest } from './models/ProofRequest' -import { ProofService } from './services' +import { ProofState } from './models/ProofState' +import { V1ProofService } from './protocol/v1/V1ProofService' +import { V2ProofService } from './protocol/v2/V2ProofService' +import { ProofRepository } from './repository/ProofRepository' + +export interface ProofsApi[]> { + // Proposal methods + proposeProof(options: ProposeProofOptions): Promise + acceptProposal(options: AcceptProposalOptions): Promise + + // Request methods + requestProof(options: RequestProofOptions): Promise + acceptRequest(options: AcceptPresentationOptions): Promise + declineRequest(proofRecordId: string): Promise + + // out of band + createOutOfBandRequest(options: OutOfBandRequestOptions): Promise<{ + message: AgentMessage + proofRecord: ProofRecord + }> + + // Present + acceptPresentation(proofRecordId: string): Promise + + // Auto Select + autoSelectCredentialsForProofRequest( + options: AutoSelectCredentialsForProofRequestOptions + ): Promise> + + sendProblemReport(proofRecordId: string, message: string): Promise + + // Record Methods + getAll(): Promise + getById(proofRecordId: string): Promise + deleteById(proofId: string): Promise + findById(proofRecordId: string): Promise + update(proofRecord: ProofRecord): Promise +} @injectable() -export class ProofsApi { - private proofService: ProofService +export class ProofsApi< + PFs extends ProofFormat[] = [IndyProofFormat], + PSs extends ProofService[] = [V1ProofService, V2ProofService] +> implements ProofsApi +{ private connectionService: ConnectionService private messageSender: MessageSender private routingService: RoutingService + private proofRepository: ProofRepository private agentContext: AgentContext - private proofResponseCoordinator: ProofResponseCoordinator + private agentConfig: AgentConfig private logger: Logger + private serviceMap: ServiceMap public constructor( dispatcher: Dispatcher, - proofService: ProofService, + mediationRecipientService: MediationRecipientService, + messageSender: MessageSender, connectionService: ConnectionService, - routingService: RoutingService, agentContext: AgentContext, - messageSender: MessageSender, - proofResponseCoordinator: ProofResponseCoordinator, - @inject(InjectionSymbols.Logger) logger: Logger + agentConfig: AgentConfig, + routingService: RoutingService, + @inject(InjectionSymbols.Logger) logger: Logger, + proofRepository: ProofRepository, + v1Service: V1ProofService, + v2Service: V2ProofService ) { - this.proofService = proofService - this.connectionService = connectionService this.messageSender = messageSender - this.routingService = routingService + this.connectionService = connectionService + this.proofRepository = proofRepository this.agentContext = agentContext - this.proofResponseCoordinator = proofResponseCoordinator + this.agentConfig = agentConfig + this.routingService = routingService this.logger = logger - this.registerHandlers(dispatcher) + // Dynamically build service map. This will be extracted once services are registered dynamically + this.serviceMap = [v1Service, v2Service].reduce( + (serviceMap, service) => ({ + ...serviceMap, + [service.version]: service, + }), + {} + ) as ServiceMap + + this.logger.debug(`Initializing Proofs Module for agent ${this.agentContext.config.label}`) + + this.registerHandlers(dispatcher, mediationRecipientService) + } + + public getService(protocolVersion: PVT): ProofService { + if (!this.serviceMap[protocolVersion]) { + throw new AriesFrameworkError(`No proof service registered for protocol version ${protocolVersion}`) + } + + return this.serviceMap[protocolVersion] } /** * Initiate a new presentation exchange as prover by sending a presentation proposal message * to the connection with the specified connection id. * - * @param connectionId The connection to send the proof proposal to - * @param presentationProposal The presentation proposal to include in the message - * @param config Additional configuration to use for the proposal + * @param options multiple properties like protocol version, connection id, proof format (indy/ presentation exchange) + * to include in the message * @returns Proof record associated with the sent proposal message - * */ - public async proposeProof( - connectionId: string, - presentationProposal: PresentationPreview, - config?: { - comment?: string - autoAcceptProof?: AutoAcceptProof - } - ): Promise { + public async proposeProof(options: ProposeProofOptions): Promise { + const service = this.getService(options.protocolVersion) + + const { connectionId } = options + const connection = await this.connectionService.getById(this.agentContext, connectionId) - const { message, proofRecord } = await this.proofService.createProposal( - this.agentContext, - connection, - presentationProposal, - config - ) + // Assert + connection.assertReady() + + const proposalOptions: CreateProposalOptions = { + connectionRecord: connection, + proofFormats: options.proofFormats, + autoAcceptProof: options.autoAcceptProof, + goalCode: options.goalCode, + comment: options.comment, + } + + const { message, proofRecord } = await service.createProposal(this.agentContext, proposalOptions) const outbound = createOutboundMessage(connection, message) await this.messageSender.sendMessage(this.agentContext, outbound) @@ -96,23 +174,14 @@ export class ProofsApi { * Accept a presentation proposal as verifier (by sending a presentation request message) to the connection * associated with the proof record. * - * @param proofRecordId The id of the proof record for which to accept the proposal - * @param config Additional configuration to use for the request + * @param options multiple properties like proof record id, additional configuration for creating the request * @returns Proof record associated with the presentation request - * */ - public async acceptProposal( - proofRecordId: string, - config?: { - request?: { - name?: string - version?: string - nonce?: string - } - comment?: string - } - ): Promise { - const proofRecord = await this.proofService.getById(this.agentContext, proofRecordId) + public async acceptProposal(options: AcceptProposalOptions): Promise { + const { proofRecordId } = options + const proofRecord = await this.getById(proofRecordId) + + const service = this.getService(proofRecord.protocolVersion) if (!proofRecord.connectionId) { throw new AriesFrameworkError( @@ -122,24 +191,27 @@ export class ProofsApi { const connection = await this.connectionService.getById(this.agentContext, proofRecord.connectionId) - const presentationProposal = proofRecord.proposalMessage?.presentationProposal - if (!presentationProposal) { - throw new AriesFrameworkError(`Proof record with id ${proofRecordId} is missing required presentation proposal`) + // Assert + connection.assertReady() + + const proofRequestFromProposalOptions: CreateProofRequestFromProposalOptions = { + proofRecord, } - const proofRequest = await this.proofService.createProofRequestFromProposal( + const proofRequest = await service.createProofRequestFromProposal( this.agentContext, - presentationProposal, - { - name: config?.request?.name ?? 'proof-request', - version: config?.request?.version ?? '1.0', - nonce: config?.request?.nonce, - } + proofRequestFromProposalOptions ) - const { message } = await this.proofService.createRequestAsResponse(this.agentContext, proofRecord, proofRequest, { - comment: config?.comment, - }) + const requestOptions: CreateRequestAsResponseOptions = { + proofRecord: proofRecord, + proofFormats: proofRequest.proofFormats, + goalCode: options.goalCode, + willConfirm: options.willConfirm ?? true, + comment: options.comment, + } + + const { message } = await service.createRequestAsResponse(this.agentContext, requestOptions) const outboundMessage = createOutboundMessage(connection, message) await this.messageSender.sendMessage(this.agentContext, outboundMessage) @@ -151,34 +223,24 @@ export class ProofsApi { * Initiate a new presentation exchange as verifier by sending a presentation request message * to the connection with the specified connection id * - * @param connectionId The connection to send the proof request to - * @param proofRequestOptions Options to build the proof request + * @param options multiple properties like connection id, protocol version, proof Formats to build the proof request * @returns Proof record associated with the sent request message - * */ - public async requestProof( - connectionId: string, - proofRequestOptions: CreateProofRequestOptions, - config?: ProofRequestConfig - ): Promise { - const connection = await this.connectionService.getById(this.agentContext, connectionId) + public async requestProof(options: RequestProofOptions): Promise { + const service = this.getService(options.protocolVersion) - const nonce = proofRequestOptions.nonce ?? (await this.proofService.generateProofRequestNonce(this.agentContext)) + const connection = await this.connectionService.getById(this.agentContext, options.connectionId) - const proofRequest = new ProofRequest({ - name: proofRequestOptions.name ?? 'proof-request', - version: proofRequestOptions.name ?? '1.0', - nonce, - requestedAttributes: proofRequestOptions.requestedAttributes, - requestedPredicates: proofRequestOptions.requestedPredicates, - }) + // Assert + connection.assertReady() - const { message, proofRecord } = await this.proofService.createRequest( - this.agentContext, - proofRequest, - connection, - config - ) + const createProofRequest: CreateRequestOptions = { + connectionRecord: connection, + proofFormats: options.proofFormats, + autoAcceptProof: options.autoAcceptProof, + comment: options.comment, + } + const { message, proofRecord } = await service.createRequest(this.agentContext, createProofRequest) const outboundMessage = createOutboundMessage(connection, message) await this.messageSender.sendMessage(this.agentContext, outboundMessage) @@ -186,108 +248,67 @@ export class ProofsApi { return proofRecord } - /** - * Initiate a new presentation exchange as verifier by creating a presentation request - * not bound to any connection. The request must be delivered out-of-band to the holder - * - * @param proofRequestOptions Options to build the proof request - * @returns The proof record and proof request message - * - */ - public async createOutOfBandRequest( - proofRequestOptions: CreateProofRequestOptions, - config?: ProofRequestConfig - ): Promise<{ - requestMessage: RequestPresentationMessage - proofRecord: ProofRecord - }> { - const nonce = proofRequestOptions.nonce ?? (await this.proofService.generateProofRequestNonce(this.agentContext)) - - const proofRequest = new ProofRequest({ - name: proofRequestOptions.name ?? 'proof-request', - version: proofRequestOptions.name ?? '1.0', - nonce, - requestedAttributes: proofRequestOptions.requestedAttributes, - requestedPredicates: proofRequestOptions.requestedPredicates, - }) - - const { message, proofRecord } = await this.proofService.createRequest( - this.agentContext, - proofRequest, - undefined, - config - ) - - // Create and set ~service decorator - const routing = await this.routingService.getRouting(this.agentContext) - message.service = new ServiceDecorator({ - serviceEndpoint: routing.endpoints[0], - recipientKeys: [routing.recipientKey.publicKeyBase58], - routingKeys: routing.routingKeys.map((key) => key.publicKeyBase58), - }) - - // Save ~service decorator to record (to remember our verkey) - proofRecord.requestMessage = message - await this.proofService.update(this.agentContext, proofRecord) - - return { proofRecord, requestMessage: message } - } - /** * Accept a presentation request as prover (by sending a presentation message) to the connection * associated with the proof record. * - * @param proofRecordId The id of the proof record for which to accept the request - * @param requestedCredentials The requested credentials object specifying which credentials to use for the proof - * @param config Additional configuration to use for the presentation + * @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 presentation message - * */ - public async acceptRequest( - proofRecordId: string, - requestedCredentials: RequestedCredentials, - config?: { - comment?: string + public async acceptRequest(options: AcceptPresentationOptions): Promise { + const { proofRecordId, proofFormats, comment } = options + + const record = await this.getById(proofRecordId) + + const service = this.getService(record.protocolVersion) + + const presentationOptions: CreatePresentationOptions = { + proofFormats, + proofRecord: record, + comment, } - ): Promise { - const record = await this.proofService.getById(this.agentContext, proofRecordId) - const { message, proofRecord } = await this.proofService.createPresentation( - this.agentContext, - record, - requestedCredentials, - config - ) + const { message, proofRecord } = await service.createPresentation(this.agentContext, presentationOptions) + + const requestMessage = await service.findRequestMessage(this.agentContext, proofRecord.id) // Use connection if present if (proofRecord.connectionId) { const connection = await this.connectionService.getById(this.agentContext, proofRecord.connectionId) + // Assert + connection.assertReady() + const outboundMessage = createOutboundMessage(connection, message) await this.messageSender.sendMessage(this.agentContext, outboundMessage) return proofRecord } + // Use ~service decorator otherwise - else if (proofRecord.requestMessage?.service) { + else if (requestMessage?.service) { // Create ~service decorator const routing = await this.routingService.getRouting(this.agentContext) - const ourService = new ServiceDecorator({ + message.service = new ServiceDecorator({ serviceEndpoint: routing.endpoints[0], recipientKeys: [routing.recipientKey.publicKeyBase58], routingKeys: routing.routingKeys.map((key) => key.publicKeyBase58), }) - const recipientService = proofRecord.requestMessage.service + const recipientService = requestMessage.service // Set and save ~service decorator to record (to remember our verkey) - message.service = ourService - proofRecord.presentationMessage = message - await this.proofService.update(this.agentContext, proofRecord) + + await service.saveOrUpdatePresentationMessage(this.agentContext, { + proofRecord: proofRecord, + message: message, + role: DidCommMessageRole.Sender, + }) await this.messageSender.sendMessageToService(this.agentContext, { message, service: recipientService.resolvedDidCommService, - senderKey: ourService.resolvedDidCommService.recipientKeys[0], + senderKey: message.service.resolvedDidCommService.recipientKeys[0], returnRoute: true, }) @@ -301,14 +322,49 @@ export class ProofsApi { } } - /** - * Declines a proof request as holder - * @param proofRecordId the id of the proof request to be declined - * @returns proof record that was declined - */ - public async declineRequest(proofRecordId: string) { - const proofRecord = await this.proofService.getById(this.agentContext, proofRecordId) - await this.proofService.declineRequest(this.agentContext, proofRecord) + public async createOutOfBandRequest(options: OutOfBandRequestOptions): Promise<{ + message: AgentMessage + proofRecord: ProofRecord + }> { + const service = this.getService(options.protocolVersion) + + const createProofRequest: CreateOutOfBandRequestOptions = { + proofFormats: options.proofFormats, + autoAcceptProof: options.autoAcceptProof, + comment: options.comment, + } + + const { message, proofRecord } = await service.createRequest(this.agentContext, createProofRequest) + + // Create and set ~service decorator + + const routing = await this.routingService.getRouting(this.agentContext) + message.service = new ServiceDecorator({ + serviceEndpoint: routing.endpoints[0], + recipientKeys: [routing.recipientKey.publicKeyBase58], + routingKeys: routing.routingKeys.map((key) => key.publicKeyBase58), + }) + // Save ~service decorator to record (to remember our verkey) + + await service.saveOrUpdatePresentationMessage(this.agentContext, { + message, + proofRecord: proofRecord, + role: DidCommMessageRole.Sender, + }) + + await service.update(this.agentContext, proofRecord) + + return { proofRecord, message } + } + + public async declineRequest(proofRecordId: string): Promise { + const proofRecord = await this.getById(proofRecordId) + const service = this.getService(proofRecord.protocolVersion) + + proofRecord.assertState(ProofState.RequestReceived) + + await service.updateState(this.agentContext, proofRecord, ProofState.Declined) + return proofRecord } @@ -321,19 +377,31 @@ export class ProofsApi { * */ public async acceptPresentation(proofRecordId: string): Promise { - const record = await this.proofService.getById(this.agentContext, proofRecordId) - const { message, proofRecord } = await this.proofService.createAck(this.agentContext, record) + const record = await this.getById(proofRecordId) + const service = this.getService(record.protocolVersion) + + const { message, proofRecord } = await service.createAck(this.agentContext, { + proofRecord: record, + }) + + const requestMessage = await service.findRequestMessage(this.agentContext, record.id) + + const presentationMessage = await service.findPresentationMessage(this.agentContext, record.id) // Use connection if present if (proofRecord.connectionId) { const connection = await this.connectionService.getById(this.agentContext, proofRecord.connectionId) + + // Assert + connection.assertReady() + const outboundMessage = createOutboundMessage(connection, message) await this.messageSender.sendMessage(this.agentContext, outboundMessage) } // Use ~service decorator otherwise - else if (proofRecord.requestMessage?.service && proofRecord.presentationMessage?.service) { - const recipientService = proofRecord.presentationMessage?.service - const ourService = proofRecord.requestMessage.service + else if (requestMessage?.service && presentationMessage?.service) { + const recipientService = presentationMessage?.service + const ourService = requestMessage.service await this.messageSender.sendMessageToService(this.agentContext, { message, @@ -342,7 +410,6 @@ export class ProofsApi { returnRoute: true, }) } - // Cannot send message without credentialId or ~service decorator else { throw new AriesFrameworkError( @@ -350,7 +417,7 @@ export class ProofsApi { ) } - return proofRecord + return record } /** @@ -358,84 +425,59 @@ export class ProofsApi { * use credentials in the wallet to build indy requested credentials object for input to proof creation. * If restrictions allow, self attested attributes will be used. * - * - * @param proofRecordId the id of the proof request to get the matching credentials for - * @param config optional configuration for credential selection process. Use `filterByPresentationPreview` (default `true`) to only include - * credentials that match the presentation preview from the presentation proposal (if available). - - * @returns RetrievedCredentials object + * @param options multiple properties like proof record id and optional configuration + * @returns RequestedCredentials */ - public async getRequestedCredentialsForProofRequest( - proofRecordId: string, - config?: GetRequestedCredentialsConfig - ): Promise { - const proofRecord = await this.proofService.getById(this.agentContext, proofRecordId) - - const indyProofRequest = proofRecord.requestMessage?.indyProofRequest - const presentationPreview = config?.filterByPresentationPreview - ? proofRecord.proposalMessage?.presentationProposal - : undefined - - if (!indyProofRequest) { - throw new AriesFrameworkError( - 'Unable to get requested credentials for proof request. No proof request message was found or the proof request message does not contain an indy proof request.' - ) - } + public async autoSelectCredentialsForProofRequest( + options: AutoSelectCredentialsForProofRequestOptions + ): Promise> { + const proofRecord = await this.getById(options.proofRecordId) - return this.proofService.getRequestedCredentialsForProofRequest(this.agentContext, indyProofRequest, { - presentationProposal: presentationPreview, - filterByNonRevocationRequirements: config?.filterByNonRevocationRequirements ?? true, - }) - } + const service = this.getService(proofRecord.protocolVersion) - /** - * Takes a RetrievedCredentials object and auto selects credentials in a RequestedCredentials object - * - * Use the return value of this method as input to {@link ProofService.createPresentation} to - * automatically accept a received presentation request. - * - * @param retrievedCredentials The retrieved credentials object to get credentials from - * - * @returns RequestedCredentials - */ - public autoSelectCredentialsForProofRequest(retrievedCredentials: RetrievedCredentials): RequestedCredentials { - return this.proofService.autoSelectCredentialsForProofRequest(retrievedCredentials) + const retrievedCredentials: FormatRetrievedCredentialOptions = + await service.getRequestedCredentialsForProofRequest(this.agentContext, { + proofRecord: proofRecord, + config: options.config, + }) + return await service.autoSelectCredentialsForProofRequest(retrievedCredentials) } /** * Send problem report message for a proof record + * * @param proofRecordId The id of the proof record for which to send problem report * @param message message to send * @returns proof record associated with the proof problem report message */ - public async sendProblemReport(proofRecordId: string, message: string) { - const record = await this.proofService.getById(this.agentContext, proofRecordId) + public async sendProblemReport(proofRecordId: string, message: string): Promise { + const record = await this.getById(proofRecordId) + const service = this.getService(record.protocolVersion) if (!record.connectionId) { throw new AriesFrameworkError(`No connectionId found for proof record '${record.id}'.`) } const connection = await this.connectionService.getById(this.agentContext, record.connectionId) - const presentationProblemReportMessage = new PresentationProblemReportMessage({ - description: { - en: message, - code: PresentationProblemReportReason.Abandoned, - }, - }) - presentationProblemReportMessage.setThread({ - threadId: record.threadId, + + // Assert + connection.assertReady() + + const { message: problemReport } = await service.createProblemReport(this.agentContext, { + proofRecord: record, + description: message, }) - const outboundMessage = createOutboundMessage(connection, presentationProblemReportMessage) + + const outboundMessage = createOutboundMessage(connection, problemReport) await this.messageSender.sendMessage(this.agentContext, outboundMessage) return record } - /** * Retrieve all proof records * * @returns List containing all proof records */ - public getAll(): Promise { - return this.proofService.getAll(this.agentContext) + public async getAll(): Promise { + return this.proofRepository.getAll(this.agentContext) } /** @@ -443,12 +485,11 @@ export class ProofsApi { * * @param proofRecordId The proof record id * @throws {RecordNotFoundError} If no record is found - * @throws {RecordDuplicateError} If multiple records are found * @return The proof record * */ public async getById(proofRecordId: string): Promise { - return this.proofService.getById(this.agentContext, proofRecordId) + return await this.proofRepository.getById(this.agentContext, proofRecordId) } /** @@ -459,7 +500,7 @@ export class ProofsApi { * */ public async findById(proofRecordId: string): Promise { - return this.proofService.findById(this.agentContext, proofRecordId) + return await this.proofRepository.findById(this.agentContext, proofRecordId) } /** @@ -468,47 +509,29 @@ export class ProofsApi { * @param proofId the proof record id */ public async deleteById(proofId: string) { - return this.proofService.deleteById(this.agentContext, proofId) + const proofRecord = await this.getById(proofId) + return await this.proofRepository.delete(this.agentContext, proofRecord) } - private registerHandlers(dispatcher: Dispatcher) { - dispatcher.registerHandler( - new ProposePresentationHandler(this.proofService, this.proofResponseCoordinator, this.logger) - ) - dispatcher.registerHandler( - new RequestPresentationHandler(this.proofService, this.proofResponseCoordinator, this.routingService, this.logger) - ) - dispatcher.registerHandler(new PresentationHandler(this.proofService, this.proofResponseCoordinator, this.logger)) - dispatcher.registerHandler(new PresentationAckHandler(this.proofService)) - dispatcher.registerHandler(new PresentationProblemReportHandler(this.proofService)) - } -} - -export type CreateProofRequestOptions = Partial< - Pick -> - -export interface ProofRequestConfig { - comment?: string - autoAcceptProof?: AutoAcceptProof -} - -export interface GetRequestedCredentialsConfig { /** - * Whether to filter the retrieved credentials using the presentation preview. - * This configuration will only have effect if a presentation proposal message is available - * containing a presentation preview. + * Update a proof record by * - * @default false + * @param proofRecord the proof record */ - filterByPresentationPreview?: boolean + public async update(proofRecord: ProofRecord) { + await this.proofRepository.update(this.agentContext, proofRecord) + } - /** - * Whether to filter the retrieved credentials using the non-revocation request in the proof request. - * This configuration will only have effect if the proof request requires proof on non-revocation of any kind. - * Default to true - * - * @default true - */ - filterByNonRevocationRequirements?: boolean + private registerHandlers(dispatcher: Dispatcher, mediationRecipientService: MediationRecipientService) { + for (const service of Object.values(this.serviceMap)) { + const proofService = service as ProofService + proofService.registerHandlers( + dispatcher, + this.agentConfig, + new ProofResponseCoordinator(proofService), + mediationRecipientService, + this.routingService + ) + } + } } diff --git a/packages/core/src/modules/proofs/ProofsApiOptions.ts b/packages/core/src/modules/proofs/ProofsApiOptions.ts new file mode 100644 index 0000000000..5643a5bb12 --- /dev/null +++ b/packages/core/src/modules/proofs/ProofsApiOptions.ts @@ -0,0 +1,72 @@ +import type { ProofService } from './ProofService' +import type { ProofFormat, ProofFormatPayload } from './formats/ProofFormat' +import type { AutoAcceptProof } from './models' +import type { ProofConfig } from './models/ModuleOptions' + +/** + * Get the supported protocol versions based on the provided credential services. + */ +export type ProtocolVersionType = PSs[number]['version'] + +/** + * Get the service map for usage in the credentials module. Will return a type mapping of protocol version to service. + * + * @example + * ``` + * type CredentialServiceMap = ServiceMap<[IndyCredentialFormat], [V1CredentialService]> + * + * // equal to + * type CredentialServiceMap = { + * v1: V1CredentialService + * } + * ``` + */ +export type ServiceMap[]> = { + [PS in PSs[number] as PS['version']]: ProofService +} + +export interface ProposeProofOptions< + PFs extends ProofFormat[] = ProofFormat[], + PSs extends ProofService[] = ProofService[] +> { + connectionId: string + protocolVersion: ProtocolVersionType + proofFormats: ProofFormatPayload + comment?: string + goalCode?: string + autoAcceptProof?: AutoAcceptProof +} +export interface AcceptPresentationOptions { + proofRecordId: string + comment?: string + proofFormats: ProofFormatPayload +} + +export interface AcceptProposalOptions { + proofRecordId: string + config?: ProofConfig + goalCode?: string + willConfirm?: boolean + comment?: string +} + +export interface RequestProofOptions< + PFs extends ProofFormat[] = ProofFormat[], + PSs extends ProofService[] = ProofService[] +> { + protocolVersion: ProtocolVersionType + connectionId: string + proofFormats: ProofFormatPayload + comment?: string + autoAcceptProof?: AutoAcceptProof +} + +export interface OutOfBandRequestOptions< + PFs extends ProofFormat[] = ProofFormat[], + PSs extends ProofService[] = ProofService[] +> { + protocolVersion: ProtocolVersionType + proofFormats: ProofFormatPayload + comment?: string + autoAcceptProof?: AutoAcceptProof +} diff --git a/packages/core/src/modules/proofs/ProofsModule.ts b/packages/core/src/modules/proofs/ProofsModule.ts index 829db07281..329c1c17e4 100644 --- a/packages/core/src/modules/proofs/ProofsModule.ts +++ b/packages/core/src/modules/proofs/ProofsModule.ts @@ -3,8 +3,10 @@ import type { ProofsModuleConfigOptions } from './ProofsModuleConfig' import { ProofsApi } from './ProofsApi' import { ProofsModuleConfig } from './ProofsModuleConfig' +import { IndyProofFormatService } from './formats/indy/IndyProofFormatService' +import { V1ProofService } from './protocol/v1' +import { V2ProofService } from './protocol/v2' import { ProofRepository } from './repository' -import { ProofService } from './services' export class ProofsModule implements Module { public readonly config: ProofsModuleConfig @@ -24,9 +26,13 @@ export class ProofsModule implements Module { dependencyManager.registerInstance(ProofsModuleConfig, this.config) // Services - dependencyManager.registerSingleton(ProofService) + dependencyManager.registerSingleton(V1ProofService) + dependencyManager.registerSingleton(V2ProofService) // Repositories dependencyManager.registerSingleton(ProofRepository) + + // Proof Formats + dependencyManager.registerSingleton(IndyProofFormatService) } } diff --git a/packages/core/src/modules/proofs/ProofsModuleConfig.ts b/packages/core/src/modules/proofs/ProofsModuleConfig.ts index 88fd470c0b..e0b12449e2 100644 --- a/packages/core/src/modules/proofs/ProofsModuleConfig.ts +++ b/packages/core/src/modules/proofs/ProofsModuleConfig.ts @@ -1,4 +1,4 @@ -import { AutoAcceptProof } from './ProofAutoAcceptType' +import { AutoAcceptProof } from './models/ProofAutoAcceptType' /** * ProofsModuleConfigOptions defines the interface for the options of the ProofsModuleConfig class. diff --git a/packages/core/src/modules/proofs/__tests__/ProofRequest.test.ts b/packages/core/src/modules/proofs/__tests__/ProofRequest.test.ts index 4a94da5aa9..fbfab93e5f 100644 --- a/packages/core/src/modules/proofs/__tests__/ProofRequest.test.ts +++ b/packages/core/src/modules/proofs/__tests__/ProofRequest.test.ts @@ -1,15 +1,15 @@ import { ClassValidationError } from '../../../error/ClassValidationError' import { JsonTransformer } from '../../../utils/JsonTransformer' import { MessageValidator } from '../../../utils/MessageValidator' -import { ProofRequest } from '../models' +import { ProofRequest } from '../formats/indy/models/ProofRequest' describe('ProofRequest', () => { - it('should successfully validate if the proof request json contains a valid structure', async () => { + it('should successfully validate if the proof request JSON contains a valid structure', async () => { const proofRequest = JsonTransformer.fromJSON( { name: 'ProofRequest', version: '1.0', - nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + nonce: '947121108704767252195123', requested_attributes: { First: { name: 'Timo', @@ -43,7 +43,7 @@ describe('ProofRequest', () => { const proofRequest = { name: 'ProofRequest', version: '1.0', - nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + nonce: '947121108704767252195123', requested_attributes: { First: { names: [], diff --git a/packages/core/src/modules/proofs/__tests__/ProofState.test.ts b/packages/core/src/modules/proofs/__tests__/ProofState.test.ts index 9cabafd183..4b67ed11d0 100644 --- a/packages/core/src/modules/proofs/__tests__/ProofState.test.ts +++ b/packages/core/src/modules/proofs/__tests__/ProofState.test.ts @@ -1,4 +1,4 @@ -import { ProofState } from '../ProofState' +import { ProofState } from '../models/ProofState' describe('ProofState', () => { test('state matches Present Proof 1.0 (RFC 0037) state value', () => { diff --git a/packages/core/src/modules/proofs/__tests__/ProofsModule.test.ts b/packages/core/src/modules/proofs/__tests__/ProofsModule.test.ts index 98ab74e7bc..6bba3fd99e 100644 --- a/packages/core/src/modules/proofs/__tests__/ProofsModule.test.ts +++ b/packages/core/src/modules/proofs/__tests__/ProofsModule.test.ts @@ -1,8 +1,10 @@ import { DependencyManager } from '../../../plugins/DependencyManager' import { ProofsApi } from '../ProofsApi' import { ProofsModule } from '../ProofsModule' +import { IndyProofFormatService } from '../formats/indy/IndyProofFormatService' +import { V1ProofService } from '../protocol/v1/V1ProofService' +import { V2ProofService } from '../protocol/v2/V2ProofService' import { ProofRepository } from '../repository' -import { ProofService } from '../services' jest.mock('../../../plugins/DependencyManager') const DependencyManagerMock = DependencyManager as jest.Mock @@ -16,8 +18,10 @@ describe('ProofsModule', () => { expect(dependencyManager.registerContextScoped).toHaveBeenCalledTimes(1) expect(dependencyManager.registerContextScoped).toHaveBeenCalledWith(ProofsApi) - expect(dependencyManager.registerSingleton).toHaveBeenCalledTimes(2) - expect(dependencyManager.registerSingleton).toHaveBeenCalledWith(ProofService) + expect(dependencyManager.registerSingleton).toHaveBeenCalledTimes(4) + expect(dependencyManager.registerSingleton).toHaveBeenCalledWith(V1ProofService) + expect(dependencyManager.registerSingleton).toHaveBeenCalledWith(V2ProofService) expect(dependencyManager.registerSingleton).toHaveBeenCalledWith(ProofRepository) + expect(dependencyManager.registerSingleton).toHaveBeenCalledWith(IndyProofFormatService) }) }) diff --git a/packages/core/src/modules/proofs/__tests__/ProofService.test.ts b/packages/core/src/modules/proofs/__tests__/V1ProofService.test.ts similarity index 81% rename from packages/core/src/modules/proofs/__tests__/ProofService.test.ts rename to packages/core/src/modules/proofs/__tests__/V1ProofService.test.ts index b64ded9b1c..b093e049dc 100644 --- a/packages/core/src/modules/proofs/__tests__/ProofService.test.ts +++ b/packages/core/src/modules/proofs/__tests__/V1ProofService.test.ts @@ -1,4 +1,5 @@ import type { AgentContext } from '../../../agent' +import type { Wallet } from '../../../wallet/Wallet' import type { CredentialRepository } from '../../credentials/repository' import type { ProofStateChangedEvent } from '../ProofEvents' import type { CustomProofTags } from './../repository/ProofRecord' @@ -9,21 +10,22 @@ import { getAgentConfig, getAgentContext, getMockConnection, mockFunction } from import { EventEmitter } from '../../../agent/EventEmitter' import { InboundMessageContext } from '../../../agent/models/InboundMessageContext' import { Attachment, AttachmentData } from '../../../decorators/attachment/Attachment' +import { DidCommMessageRepository } from '../../../storage' import { ConnectionService, DidExchangeState } from '../../connections' import { IndyHolderService } from '../../indy/services/IndyHolderService' import { IndyRevocationService } from '../../indy/services/IndyRevocationService' import { IndyLedgerService } from '../../ledger/services' import { ProofEventTypes } from '../ProofEvents' -import { ProofState } from '../ProofState' import { PresentationProblemReportReason } from '../errors/PresentationProblemReportReason' -import { INDY_PROOF_REQUEST_ATTACHMENT_ID } from '../messages' +import { IndyProofFormatService } from '../formats/indy/IndyProofFormatService' +import { ProofProtocolVersion } from '../models/ProofProtocolVersion' +import { ProofState } from '../models/ProofState' +import { V1ProofService } from '../protocol/v1' +import { INDY_PROOF_REQUEST_ATTACHMENT_ID, V1RequestPresentationMessage } from '../protocol/v1/messages' +import { V1PresentationProblemReportMessage } from '../protocol/v1/messages/V1PresentationProblemReportMessage' import { ProofRecord } from '../repository/ProofRecord' import { ProofRepository } from '../repository/ProofRepository' -import { ProofService } from '../services' -import { IndyVerifierService } from './../../indy/services/IndyVerifierService' -import { PresentationProblemReportMessage } from './../messages/PresentationProblemReportMessage' -import { RequestPresentationMessage } from './../messages/RequestPresentationMessage' import { credDef } from './fixtures' // Mock classes @@ -34,14 +36,16 @@ jest.mock('../../indy/services/IndyIssuerService') jest.mock('../../indy/services/IndyVerifierService') jest.mock('../../indy/services/IndyRevocationService') jest.mock('../../connections/services/ConnectionService') +jest.mock('../../../storage/Repository') // Mock typed object const ProofRepositoryMock = ProofRepository as jest.Mock const IndyLedgerServiceMock = IndyLedgerService as jest.Mock const IndyHolderServiceMock = IndyHolderService as jest.Mock -const IndyVerifierServiceMock = IndyVerifierService as jest.Mock const IndyRevocationServiceMock = IndyRevocationService as jest.Mock const connectionServiceMock = ConnectionService as jest.Mock +const didCommMessageRepositoryMock = DidCommMessageRepository as jest.Mock +const indyProofFormatServiceMock = IndyProofFormatService as jest.Mock const connection = getMockConnection({ id: '123', @@ -61,26 +65,25 @@ const requestAttachment = new Attachment({ // object to test our service would behave correctly. We use type assertion for `offer` attribute to `any`. const mockProofRecord = ({ state, - requestMessage, threadId, connectionId, tags, id, }: { state?: ProofState - requestMessage?: RequestPresentationMessage + requestMessage?: V1RequestPresentationMessage tags?: CustomProofTags threadId?: string connectionId?: string id?: string } = {}) => { - const requestPresentationMessage = new RequestPresentationMessage({ + const requestPresentationMessage = new V1RequestPresentationMessage({ comment: 'some comment', requestPresentationAttachments: [requestAttachment], }) const proofRecord = new ProofRecord({ - requestMessage, + protocolVersion: ProofProtocolVersion.V1, id, state: state || ProofState.RequestSent, threadId: threadId ?? requestPresentationMessage.id, @@ -91,50 +94,56 @@ const mockProofRecord = ({ return proofRecord } -describe('ProofService', () => { +describe('V1ProofService', () => { let proofRepository: ProofRepository - let proofService: ProofService + let proofService: V1ProofService let ledgerService: IndyLedgerService - let indyVerifierService: IndyVerifierService + let wallet: Wallet let indyHolderService: IndyHolderService let indyRevocationService: IndyRevocationService let eventEmitter: EventEmitter let credentialRepository: CredentialRepository let connectionService: ConnectionService + let didCommMessageRepository: DidCommMessageRepository + let indyProofFormatService: IndyProofFormatService let agentContext: AgentContext beforeEach(() => { - const agentConfig = getAgentConfig('ProofServiceTest') + const agentConfig = getAgentConfig('V1ProofServiceTest') + agentContext = getAgentContext() proofRepository = new ProofRepositoryMock() - indyVerifierService = new IndyVerifierServiceMock() indyHolderService = new IndyHolderServiceMock() indyRevocationService = new IndyRevocationServiceMock() ledgerService = new IndyLedgerServiceMock() eventEmitter = new EventEmitter(agentConfig.agentDependencies, new Subject()) connectionService = new connectionServiceMock() + didCommMessageRepository = new didCommMessageRepositoryMock() + indyProofFormatService = new indyProofFormatServiceMock() agentContext = getAgentContext() - proofService = new ProofService( + proofService = new V1ProofService( proofRepository, + didCommMessageRepository, ledgerService, - indyHolderService, - indyVerifierService, - indyRevocationService, + wallet, + agentConfig, connectionService, eventEmitter, credentialRepository, - agentConfig.logger + indyProofFormatService, + indyHolderService, + indyRevocationService ) mockFunction(ledgerService.getCredentialDefinition).mockReturnValue(Promise.resolve(credDef)) }) describe('processProofRequest', () => { - let presentationRequest: RequestPresentationMessage - let messageContext: InboundMessageContext + let presentationRequest: V1RequestPresentationMessage + let messageContext: InboundMessageContext beforeEach(() => { - presentationRequest = new RequestPresentationMessage({ + presentationRequest = new V1RequestPresentationMessage({ comment: 'abcd', requestPresentationAttachments: [requestAttachment], }) @@ -205,7 +214,7 @@ describe('ProofService', () => { mockFunction(proofRepository.getById).mockReturnValue(Promise.resolve(proof)) // when - const presentationProblemReportMessage = await new PresentationProblemReportMessage({ + const presentationProblemReportMessage = await new V1PresentationProblemReportMessage({ description: { en: 'Indy error', code: PresentationProblemReportReason.Abandoned, @@ -226,14 +235,14 @@ describe('ProofService', () => { describe('processProblemReport', () => { let proof: ProofRecord - let messageContext: InboundMessageContext + let messageContext: InboundMessageContext beforeEach(() => { proof = mockProofRecord({ state: ProofState.RequestReceived, }) - const presentationProblemReportMessage = new PresentationProblemReportMessage({ + const presentationProblemReportMessage = new V1PresentationProblemReportMessage({ description: { en: 'Indy error', code: PresentationProblemReportReason.Abandoned, diff --git a/packages/core/src/modules/proofs/__tests__/V2ProofService.test.ts b/packages/core/src/modules/proofs/__tests__/V2ProofService.test.ts new file mode 100644 index 0000000000..34348720d8 --- /dev/null +++ b/packages/core/src/modules/proofs/__tests__/V2ProofService.test.ts @@ -0,0 +1,274 @@ +import type { AgentContext } from '../../../agent' +import type { Wallet } from '../../../wallet/Wallet' +import type { ProofStateChangedEvent } from '../ProofEvents' +import type { CustomProofTags } from '../repository/ProofRecord' + +import { Subject } from 'rxjs' + +import { getAgentConfig, getAgentContext, getMockConnection, mockFunction } from '../../../../tests/helpers' +import { EventEmitter } from '../../../agent/EventEmitter' +import { InboundMessageContext } from '../../../agent/models/InboundMessageContext' +import { Attachment, AttachmentData } from '../../../decorators/attachment/Attachment' +import { DidCommMessageRepository } from '../../../storage' +import { ConnectionService, DidExchangeState } from '../../connections' +import { IndyLedgerService } from '../../ledger/services/IndyLedgerService' +import { ProofEventTypes } from '../ProofEvents' +import { PresentationProblemReportReason } from '../errors/PresentationProblemReportReason' +import { V2_INDY_PRESENTATION, V2_INDY_PRESENTATION_REQUEST } from '../formats/ProofFormatConstants' +import { IndyProofFormatService } from '../formats/indy/IndyProofFormatService' +import { ProofProtocolVersion } from '../models/ProofProtocolVersion' +import { ProofState } from '../models/ProofState' +import { V2ProofService } from '../protocol/v2/V2ProofService' +import { V2PresentationProblemReportMessage, V2RequestPresentationMessage } from '../protocol/v2/messages' +import { ProofRecord } from '../repository/ProofRecord' +import { ProofRepository } from '../repository/ProofRepository' + +import { credDef } from './fixtures' + +// Mock classes +jest.mock('../repository/ProofRepository') +jest.mock('../../../modules/ledger/services/IndyLedgerService') +jest.mock('../../indy/services/IndyHolderService') +jest.mock('../../indy/services/IndyIssuerService') +jest.mock('../../indy/services/IndyVerifierService') +jest.mock('../../connections/services/ConnectionService') +jest.mock('../../../storage/Repository') + +// Mock typed object +const ProofRepositoryMock = ProofRepository as jest.Mock +const IndyLedgerServiceMock = IndyLedgerService as jest.Mock +const connectionServiceMock = ConnectionService as jest.Mock +const didCommMessageRepositoryMock = DidCommMessageRepository as jest.Mock +const indyProofFormatServiceMock = IndyProofFormatService as jest.Mock + +const connection = getMockConnection({ + id: '123', + state: DidExchangeState.Completed, +}) + +const requestAttachment = new Attachment({ + id: 'abdc8b63-29c6-49ad-9e10-98f9d85db9a2', + mimeType: 'application/json', + data: new AttachmentData({ + base64: + 'eyJuYW1lIjogIlByb29mIHJlcXVlc3QiLCAibm9uX3Jldm9rZWQiOiB7ImZyb20iOiAxNjQwOTk1MTk5LCAidG8iOiAxNjQwOTk1MTk5fSwgIm5vbmNlIjogIjEiLCAicmVxdWVzdGVkX2F0dHJpYnV0ZXMiOiB7ImFkZGl0aW9uYWxQcm9wMSI6IHsibmFtZSI6ICJmYXZvdXJpdGVEcmluayIsICJub25fcmV2b2tlZCI6IHsiZnJvbSI6IDE2NDA5OTUxOTksICJ0byI6IDE2NDA5OTUxOTl9LCAicmVzdHJpY3Rpb25zIjogW3siY3JlZF9kZWZfaWQiOiAiV2dXeHF6dHJOb29HOTJSWHZ4U1RXdjozOkNMOjIwOnRhZyJ9XX19LCAicmVxdWVzdGVkX3ByZWRpY2F0ZXMiOiB7fSwgInZlcnNpb24iOiAiMS4wIn0=', + }), +}) + +// A record is deserialized to JSON when it's stored into the storage. We want to simulate this behaviour for `offer` +// object to test our service would behave correctly. We use type assertion for `offer` attribute to `any`. +const mockProofRecord = ({ + state, + threadId, + connectionId, + tags, + id, +}: { + state?: ProofState + requestMessage?: V2RequestPresentationMessage + tags?: CustomProofTags + threadId?: string + connectionId?: string + id?: string +} = {}) => { + const requestPresentationMessage = new V2RequestPresentationMessage({ + attachmentInfo: [ + { + format: { + attachmentId: 'abdc8b63-29c6-49ad-9e10-98f9d85db9a2', + format: V2_INDY_PRESENTATION, + }, + attachment: requestAttachment, + }, + ], + comment: 'some comment', + }) + + const proofRecord = new ProofRecord({ + protocolVersion: ProofProtocolVersion.V2, + id, + state: state || ProofState.RequestSent, + threadId: threadId ?? requestPresentationMessage.id, + connectionId: connectionId ?? '123', + tags, + }) + + return proofRecord +} + +describe('V2ProofService', () => { + let proofRepository: ProofRepository + let proofService: V2ProofService + let ledgerService: IndyLedgerService + let wallet: Wallet + let eventEmitter: EventEmitter + let connectionService: ConnectionService + let didCommMessageRepository: DidCommMessageRepository + let indyProofFormatService: IndyProofFormatService + let agentContext: AgentContext + + beforeEach(() => { + agentContext = getAgentContext() + const agentConfig = getAgentConfig('V2ProofServiceTest') + proofRepository = new ProofRepositoryMock() + ledgerService = new IndyLedgerServiceMock() + eventEmitter = new EventEmitter(agentConfig.agentDependencies, new Subject()) + connectionService = new connectionServiceMock() + didCommMessageRepository = new didCommMessageRepositoryMock() + indyProofFormatService = new indyProofFormatServiceMock() + + proofService = new V2ProofService( + agentConfig, + connectionService, + proofRepository, + didCommMessageRepository, + eventEmitter, + indyProofFormatService, + wallet + ) + + mockFunction(ledgerService.getCredentialDefinition).mockReturnValue(Promise.resolve(credDef)) + }) + + describe('processProofRequest', () => { + let presentationRequest: V2RequestPresentationMessage + let messageContext: InboundMessageContext + + beforeEach(() => { + presentationRequest = new V2RequestPresentationMessage({ + attachmentInfo: [ + { + format: { + attachmentId: 'abdc8b63-29c6-49ad-9e10-98f9d85db9a2', + format: V2_INDY_PRESENTATION_REQUEST, + }, + attachment: requestAttachment, + }, + ], + comment: 'Proof Request', + }) + messageContext = new InboundMessageContext(presentationRequest, { agentContext, connection }) + }) + + test(`creates and return proof record in ${ProofState.PresentationReceived} state with offer, without thread ID`, async () => { + const repositorySaveSpy = jest.spyOn(proofRepository, 'save') + + // when + const returnedProofRecord = await proofService.processRequest(messageContext) + + // then + const expectedProofRecord = { + type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + state: ProofState.RequestReceived, + threadId: presentationRequest.id, + connectionId: connection.id, + } + expect(repositorySaveSpy).toHaveBeenCalledTimes(1) + const [[, createdProofRecord]] = repositorySaveSpy.mock.calls + expect(createdProofRecord).toMatchObject(expectedProofRecord) + expect(returnedProofRecord).toMatchObject(expectedProofRecord) + }) + + test(`emits stateChange event with ${ProofState.RequestReceived}`, async () => { + const eventListenerMock = jest.fn() + eventEmitter.on(ProofEventTypes.ProofStateChanged, eventListenerMock) + + // when + await proofService.processRequest(messageContext) + + // then + expect(eventListenerMock).toHaveBeenCalledWith({ + type: 'ProofStateChanged', + metadata: { + contextCorrelationId: 'mock', + }, + payload: { + previousState: null, + proofRecord: expect.objectContaining({ + state: ProofState.RequestReceived, + }), + }, + }) + }) + }) + + describe('createProblemReport', () => { + const threadId = 'fd9c5ddb-ec11-4acd-bc32-540736249746' + let proof: ProofRecord + + beforeEach(() => { + proof = mockProofRecord({ + state: ProofState.RequestReceived, + threadId, + connectionId: 'b1e2f039-aa39-40be-8643-6ce2797b5190', + }) + }) + + test('returns problem report message base once get error', async () => { + // given + mockFunction(proofRepository.getById).mockReturnValue(Promise.resolve(proof)) + + // when + const presentationProblemReportMessage = await new V2PresentationProblemReportMessage({ + description: { + en: 'Indy error', + code: PresentationProblemReportReason.Abandoned, + }, + }) + + presentationProblemReportMessage.setThread({ threadId }) + // then + expect(presentationProblemReportMessage.toJSON()).toMatchObject({ + '@id': expect.any(String), + '@type': 'https://didcomm.org/present-proof/2.0/problem-report', + '~thread': { + thid: 'fd9c5ddb-ec11-4acd-bc32-540736249746', + }, + }) + }) + }) + + describe('processProblemReport', () => { + let proof: ProofRecord + let messageContext: InboundMessageContext + beforeEach(() => { + proof = mockProofRecord({ + state: ProofState.RequestReceived, + }) + + const presentationProblemReportMessage = new V2PresentationProblemReportMessage({ + description: { + en: 'Indy error', + code: PresentationProblemReportReason.Abandoned, + }, + }) + presentationProblemReportMessage.setThread({ threadId: 'somethreadid' }) + messageContext = new InboundMessageContext(presentationProblemReportMessage, { agentContext, connection }) + }) + + test(`updates problem report error message and returns proof record`, async () => { + const repositoryUpdateSpy = jest.spyOn(proofRepository, 'update') + + // given + mockFunction(proofRepository.getSingleByQuery).mockReturnValue(Promise.resolve(proof)) + + // when + const returnedCredentialRecord = await proofService.processProblemReport(messageContext) + + // then + const expectedCredentialRecord = { + errorMessage: 'abandoned: Indy error', + } + expect(proofRepository.getSingleByQuery).toHaveBeenNthCalledWith(1, agentContext, { + threadId: 'somethreadid', + connectionId: connection.id, + }) + expect(repositoryUpdateSpy).toHaveBeenCalledTimes(1) + const [[, updatedCredentialRecord]] = repositoryUpdateSpy.mock.calls + expect(updatedCredentialRecord).toMatchObject(expectedCredentialRecord) + expect(returnedCredentialRecord).toMatchObject(expectedCredentialRecord) + }) + }) +}) diff --git a/packages/core/src/modules/proofs/errors/PresentationProblemReportError.ts b/packages/core/src/modules/proofs/errors/PresentationProblemReportError.ts deleted file mode 100644 index 2869a026d5..0000000000 --- a/packages/core/src/modules/proofs/errors/PresentationProblemReportError.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ProblemReportErrorOptions } from '../../problem-reports' -import type { PresentationProblemReportReason } from './PresentationProblemReportReason' - -import { PresentationProblemReportMessage } from '../messages' - -import { ProblemReportError } from './../../problem-reports/errors/ProblemReportError' - -interface PresentationProblemReportErrorOptions extends ProblemReportErrorOptions { - problemCode: PresentationProblemReportReason -} - -export class PresentationProblemReportError extends ProblemReportError { - public problemReport: PresentationProblemReportMessage - - public constructor(public message: string, { problemCode }: PresentationProblemReportErrorOptions) { - super(message, { problemCode }) - this.problemReport = new PresentationProblemReportMessage({ - description: { - en: message, - code: problemCode, - }, - }) - } -} diff --git a/packages/core/src/modules/proofs/errors/index.ts b/packages/core/src/modules/proofs/errors/index.ts index 5e0ca1453b..b14650ff96 100644 --- a/packages/core/src/modules/proofs/errors/index.ts +++ b/packages/core/src/modules/proofs/errors/index.ts @@ -1,2 +1 @@ -export * from './PresentationProblemReportError' export * from './PresentationProblemReportReason' diff --git a/packages/core/src/modules/proofs/formats/ProofFormat.ts b/packages/core/src/modules/proofs/formats/ProofFormat.ts new file mode 100644 index 0000000000..18fbba278d --- /dev/null +++ b/packages/core/src/modules/proofs/formats/ProofFormat.ts @@ -0,0 +1,45 @@ +/** + * Get the payload for a specific method from a list of ProofFormat interfaces and a method + * + * @example + * ``` + * + * type CreateRequestProofFormats = ProofFormatPayload<[IndyProofFormat, PresentationExchangeProofFormat], 'createRequest'> + * + * // equal to + * type CreateRequestProofFormats = { + * indy: { + * // ... params for indy create request ... + * }, + * presentationExchange: { + * // ... params for pex create request ... + * } + * } + * ``` + */ +export type ProofFormatPayload = { + [ProofFormat in PFs[number] as ProofFormat['formatKey']]?: ProofFormat['proofFormats'][M] +} + +export interface ProofFormat { + formatKey: string // e.g. 'ProofManifest', cannot be shared between different formats + proofFormats: { + createProposal: unknown + acceptProposal: unknown + createRequest: unknown + acceptRequest: unknown + createPresentation: unknown + acceptPresentation: unknown + createProposalAsResponse: unknown + createOutOfBandRequest: unknown + createRequestAsResponse: unknown + createProofRequestFromProposal: unknown + requestCredentials: unknown + retrieveCredentials: unknown + } + formatData: { + proposal: unknown + request: unknown + presentation: unknown + } +} diff --git a/packages/core/src/modules/proofs/formats/ProofFormatConstants.ts b/packages/core/src/modules/proofs/formats/ProofFormatConstants.ts new file mode 100644 index 0000000000..35e1ce33ab --- /dev/null +++ b/packages/core/src/modules/proofs/formats/ProofFormatConstants.ts @@ -0,0 +1,4 @@ +export const INDY_ATTACH_ID = 'indy' +export const V2_INDY_PRESENTATION_PROPOSAL = 'hlindy/proof-req@v2.0' +export const V2_INDY_PRESENTATION_REQUEST = 'hlindy/proof-req@v2.0' +export const V2_INDY_PRESENTATION = 'hlindy/proof@v2.0' diff --git a/packages/core/src/modules/proofs/formats/ProofFormatService.ts b/packages/core/src/modules/proofs/formats/ProofFormatService.ts new file mode 100644 index 0000000000..92e00838ff --- /dev/null +++ b/packages/core/src/modules/proofs/formats/ProofFormatService.ts @@ -0,0 +1,79 @@ +import type { AgentContext } from '../../../agent' +import type { AgentConfig } from '../../../agent/AgentConfig' +import type { DidCommMessageRepository } from '../../../storage' +import type { + CreateRequestAsResponseOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, +} from '../models/ProofServiceOptions' +import type { ProofRequestFormats } from '../models/SharedOptions' +import type { ProofFormat } from './ProofFormat' +import type { IndyProofFormat } from './indy/IndyProofFormat' +import type { GetRequestedCredentialsFormat } from './indy/IndyProofFormatsServiceOptions' +import type { ProofAttachmentFormat } from './models/ProofAttachmentFormat' +import type { + CreatePresentationFormatsOptions, + CreateProposalOptions, + CreateRequestOptions, + FormatCreatePresentationOptions, + ProcessPresentationOptions, + ProcessProposalOptions, + ProcessRequestOptions, +} from './models/ProofFormatServiceOptions' + +/** + * This abstract class is the base class for any proof format + * specific service. + * + * @export + * @abstract + * @class ProofFormatService + */ +export abstract class ProofFormatService { + protected didCommMessageRepository: DidCommMessageRepository + protected agentConfig: AgentConfig + + abstract readonly formatKey: PF['formatKey'] + + public constructor(didCommMessageRepository: DidCommMessageRepository, agentConfig: AgentConfig) { + this.didCommMessageRepository = didCommMessageRepository + this.agentConfig = agentConfig + } + + abstract createProposal(options: CreateProposalOptions): Promise + + abstract processProposal(options: ProcessProposalOptions): Promise + + abstract createRequest(options: CreateRequestOptions): Promise + + abstract processRequest(options: ProcessRequestOptions): Promise + + abstract createPresentation( + agentContext: AgentContext, + options: FormatCreatePresentationOptions + ): Promise + + abstract processPresentation(agentContext: AgentContext, options: ProcessPresentationOptions): Promise + + abstract createProofRequestFromProposal(options: CreatePresentationFormatsOptions): Promise + + public abstract getRequestedCredentialsForProofRequest( + agentContext: AgentContext, + options: GetRequestedCredentialsFormat + ): Promise> + + public abstract autoSelectCredentialsForProofRequest( + options: FormatRetrievedCredentialOptions<[PF]> + ): Promise> + + abstract proposalAndRequestAreEqual( + proposalAttachments: ProofAttachmentFormat[], + requestAttachments: ProofAttachmentFormat[] + ): boolean + + abstract supportsFormat(formatIdentifier: string): boolean + + abstract createRequestAsResponse( + options: CreateRequestAsResponseOptions<[IndyProofFormat]> + ): Promise +} diff --git a/packages/core/src/modules/proofs/formats/ProofFormatServiceOptions.ts b/packages/core/src/modules/proofs/formats/ProofFormatServiceOptions.ts new file mode 100644 index 0000000000..12a0a69dc9 --- /dev/null +++ b/packages/core/src/modules/proofs/formats/ProofFormatServiceOptions.ts @@ -0,0 +1,31 @@ +import type { Attachment } from '../../../decorators/attachment/Attachment' +import type { ProofFormatSpec } from '../models/ProofFormatSpec' +import type { ProofFormat } from './ProofFormat' +import type { ProofFormatService } from './ProofFormatService' + +/** + * Get the service map for usage in the proofs module. Will return a type mapping of protocol version to service. + * + * @example + * ``` + * type ProofFormatServiceMap = FormatServiceMap<[IndyProofFormat]> + * + * // equal to + * type ProofFormatServiceMap = { + * indy: ProofFormatService + * } + * ``` + */ +export type FormatServiceMap = { + [PF in PFs[number] as PF['formatKey']]: ProofFormatService +} + +/** + * Base return type for all methods that create an attachment format. + * + * It requires an attachment and a format to be returned. + */ +export interface FormatCreateReturn { + format: ProofFormatSpec + attachment: Attachment +} diff --git a/packages/core/src/modules/proofs/formats/indy/IndyProofFormat.ts b/packages/core/src/modules/proofs/formats/indy/IndyProofFormat.ts new file mode 100644 index 0000000000..a0e9d893c4 --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/IndyProofFormat.ts @@ -0,0 +1,77 @@ +import type { LinkedAttachment } from '../../../../utils/LinkedAttachment' +import type { CredentialPreviewAttributeOptions } from '../../../credentials' +import type { + PresentationPreviewAttribute, + PresentationPreviewPredicate, +} from '../../protocol/v1/models/V1PresentationPreview' +import type { ProofFormat } from '../ProofFormat' +import type { IndyRequestProofFormat } from '../indy/IndyProofFormatsServiceOptions' +import type { RequestedAttribute } from './models/RequestedAttribute' +import type { IndyRequestedCredentialsOptions } from './models/RequestedCredentials' +import type { RequestedPredicate } from './models/RequestedPredicate' + +export interface IndyProposeProofFormat { + attributes?: PresentationPreviewAttribute[] + predicates?: PresentationPreviewPredicate[] + nonce: string + name: string + version: string +} + +/** + * This defines the module payload for calling CredentialsApi.acceptProposal + */ +export interface IndyAcceptProposalFormat { + credentialDefinitionId?: string + attributes?: CredentialPreviewAttributeOptions[] + linkedAttachments?: LinkedAttachment[] +} + +export interface IndyAcceptOfferFormat { + holderDid?: string +} + +export interface IndyRequestedCredentialsFormat { + requestedAttributes: Record + requestedPredicates: Record + selfAttestedAttributes: Record +} + +export interface IndyRetrievedCredentialsFormat { + requestedAttributes: Record + requestedPredicates: Record +} + +export interface IndyProofFormat extends ProofFormat { + formatKey: 'indy' + proofRecordType: 'indy' + proofFormats: { + createProposal: IndyProposeProofFormat + acceptProposal: unknown + createRequest: IndyRequestProofFormat + acceptRequest: unknown + createPresentation: IndyRequestedCredentialsOptions + acceptPresentation: unknown + createProposalAsResponse: IndyProposeProofFormat + createOutOfBandRequest: unknown + createRequestAsResponse: IndyRequestProofFormat + createProofRequestFromProposal: IndyRequestProofFormat + requestCredentials: IndyRequestedCredentialsFormat + retrieveCredentials: IndyRetrievedCredentialsFormat + } + // Format data is based on RFC 0592 + // https://github.com/hyperledger/aries-rfcs/tree/main/features/0592-indy-attachments + // formatData: { + // proposal: { + // schema_issuer_did?: string + // schema_name?: string + // schema_version?: string + // schema_id?: string + // issuer_did?: string + // cred_def_id?: string + // } + // offer: CredOffer + // request: CredReq + // credential: Cred + // } +} diff --git a/packages/core/src/modules/proofs/formats/indy/IndyProofFormatService.ts b/packages/core/src/modules/proofs/formats/indy/IndyProofFormatService.ts new file mode 100644 index 0000000000..83aca03ca6 --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/IndyProofFormatService.ts @@ -0,0 +1,646 @@ +import type { AgentContext } from '../../../../agent' +import type { Logger } from '../../../../logger' +import type { + CreateRequestAsResponseOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, +} from '../../models/ProofServiceOptions' +import type { ProofRequestFormats } from '../../models/SharedOptions' +import type { ProofAttachmentFormat } from '../models/ProofAttachmentFormat' +import type { + CreatePresentationFormatsOptions, + CreateProofAttachmentOptions, + CreateProposalOptions, + CreateRequestAttachmentOptions, + CreateRequestOptions, + FormatCreatePresentationOptions, + ProcessPresentationOptions, + ProcessProposalOptions, + ProcessRequestOptions, + VerifyProofOptions, +} from '../models/ProofFormatServiceOptions' +import type { IndyProofFormat } from './IndyProofFormat' +import type { GetRequestedCredentialsFormat } from './IndyProofFormatsServiceOptions' +import type { ProofAttributeInfo, ProofPredicateInfo } from './models' +import type { CredDef, IndyProof, Schema } from 'indy-sdk' + +import { Lifecycle, scoped } from 'tsyringe' + +import { AgentConfig } from '../../../../agent/AgentConfig' +import { Attachment, AttachmentData } from '../../../../decorators/attachment/Attachment' +import { AriesFrameworkError } from '../../../../error/AriesFrameworkError' +import { ConsoleLogger, LogLevel } from '../../../../logger' +import { DidCommMessageRepository } from '../../../../storage/didcomm/DidCommMessageRepository' +import { checkProofRequestForDuplicates } from '../../../../utils' +import { JsonEncoder } from '../../../../utils/JsonEncoder' +import { JsonTransformer } from '../../../../utils/JsonTransformer' +import { MessageValidator } from '../../../../utils/MessageValidator' +import { objectEquals } from '../../../../utils/objectCheck' +import { uuid } from '../../../../utils/uuid' +import { IndyWallet } from '../../../../wallet/IndyWallet' +import { IndyCredential, IndyCredentialInfo } from '../../../credentials' +import { IndyCredentialUtils } from '../../../credentials/formats/indy/IndyCredentialUtils' +import { IndyHolderService, IndyVerifierService, IndyRevocationService } from '../../../indy' +import { IndyLedgerService } from '../../../ledger' +import { ProofFormatSpec } from '../../models/ProofFormatSpec' +import { PartialProof } from '../../protocol/v1/models' +import { + V2_INDY_PRESENTATION_REQUEST, + V2_INDY_PRESENTATION_PROPOSAL, + V2_INDY_PRESENTATION, +} from '../ProofFormatConstants' +import { ProofFormatService } from '../ProofFormatService' + +import { InvalidEncodedValueError } from './errors/InvalidEncodedValueError' +import { MissingIndyProofMessageError } from './errors/MissingIndyProofMessageError' +import { RequestedAttribute, RequestedPredicate } from './models' +import { ProofRequest } from './models/ProofRequest' +import { RequestedCredentials } from './models/RequestedCredentials' +import { RetrievedCredentials } from './models/RetrievedCredentials' + +@scoped(Lifecycle.ContainerScoped) +export class IndyProofFormatService extends ProofFormatService { + private indyHolderService: IndyHolderService + private indyVerifierService: IndyVerifierService + private indyRevocationService: IndyRevocationService + private ledgerService: IndyLedgerService + private logger: Logger + private wallet: IndyWallet + + public constructor( + agentConfig: AgentConfig, + indyHolderService: IndyHolderService, + indyVerifierService: IndyVerifierService, + indyRevocationService: IndyRevocationService, + ledgerService: IndyLedgerService, + didCommMessageRepository: DidCommMessageRepository, + wallet: IndyWallet + ) { + super(didCommMessageRepository, agentConfig) + this.indyHolderService = indyHolderService + this.indyVerifierService = indyVerifierService + this.indyRevocationService = indyRevocationService + this.ledgerService = ledgerService + this.wallet = wallet + this.logger = new ConsoleLogger(LogLevel.off) + } + public readonly formatKey = 'indy' as const + public readonly proofRecordType = 'indy' as const + + private createRequestAttachment(options: CreateRequestAttachmentOptions): ProofAttachmentFormat { + const format = new ProofFormatSpec({ + attachmentId: options.id, + format: V2_INDY_PRESENTATION_REQUEST, + }) + + const request = new ProofRequest(options.proofRequestOptions) + + // Assert attribute and predicate (group) names do not match + checkProofRequestForDuplicates(request) + + const attachment = new Attachment({ + id: options.id, + mimeType: 'application/json', + data: new AttachmentData({ + base64: JsonEncoder.toBase64(request), + }), + }) + return { format, attachment } + } + + private async createProofAttachment(options: CreateProofAttachmentOptions): Promise { + const format = new ProofFormatSpec({ + attachmentId: options.id, + format: V2_INDY_PRESENTATION_PROPOSAL, + }) + + const request = new ProofRequest(options.proofProposalOptions) + await MessageValidator.validateSync(request) + + const attachment = new Attachment({ + id: options.id, + mimeType: 'application/json', + data: new AttachmentData({ + base64: JsonEncoder.toBase64(JsonTransformer.toJSON(request)), + }), + }) + return { format, attachment } + } + + public async createProposal(options: CreateProposalOptions): Promise { + if (!options.formats.indy) { + throw Error('Missing indy format to create proposal attachment format') + } + const indyFormat = options.formats.indy + + return await this.createProofAttachment({ + id: options.id ?? uuid(), + proofProposalOptions: indyFormat, + }) + } + + public async processProposal(options: ProcessProposalOptions): Promise { + const proofProposalJson = options.proposal.attachment.getDataAsJson() + + // Assert attachment + if (!proofProposalJson) { + throw new AriesFrameworkError( + `Missing required base64 or json encoded attachment data for presentation proposal with thread id ${options.record?.threadId}` + ) + } + + const proposalMessage = JsonTransformer.fromJSON(proofProposalJson, ProofRequest) + + await MessageValidator.validateSync(proposalMessage) + } + + public async createRequestAsResponse( + options: CreateRequestAsResponseOptions<[IndyProofFormat]> + ): Promise { + if (!options.proofFormats.indy) { + throw Error('Missing indy format to create proposal attachment format') + } + + const id = options.id ?? uuid() + + const format = new ProofFormatSpec({ + attachmentId: id, + format: V2_INDY_PRESENTATION_REQUEST, + }) + + const attachment = new Attachment({ + id: id, + mimeType: 'application/json', + data: new AttachmentData({ + base64: JsonEncoder.toBase64(options.proofFormats.indy), + }), + }) + return { format, attachment } + } + + public async createRequest(options: CreateRequestOptions): Promise { + if (!options.formats.indy) { + throw new AriesFrameworkError('Missing indy format to create proof request attachment format.') + } + + return this.createRequestAttachment({ + id: options.id ?? uuid(), + proofRequestOptions: options.formats.indy, + }) + } + + public async processRequest(options: ProcessRequestOptions): Promise { + const proofRequestJson = options.requestAttachment.attachment.getDataAsJson() + + const proofRequest = JsonTransformer.fromJSON(proofRequestJson, ProofRequest) + + // Assert attachment + if (!proofRequest) { + throw new AriesFrameworkError( + `Missing required base64 or json encoded attachment data for presentation request with thread id ${options.record?.threadId}` + ) + } + await MessageValidator.validateSync(proofRequest) + + // Assert attribute and predicate (group) names do not match + checkProofRequestForDuplicates(proofRequest) + } + + public async createPresentation( + agentContext: AgentContext, + options: FormatCreatePresentationOptions + ): Promise { + // Extract proof request from attachment + const proofRequestJson = options.attachment.getDataAsJson() ?? null + const proofRequest = JsonTransformer.fromJSON(proofRequestJson, ProofRequest) + + // verify everything is there + if (!options.proofFormats.indy) { + throw new AriesFrameworkError('Missing indy format to create proof presentation attachment format.') + } + + const requestedCredentials = new RequestedCredentials({ + requestedAttributes: options.proofFormats.indy.requestedAttributes, + requestedPredicates: options.proofFormats.indy.requestedPredicates, + selfAttestedAttributes: options.proofFormats.indy.selfAttestedAttributes, + }) + + const proof = await this.createProof(agentContext, proofRequest, requestedCredentials) + + const attachmentId = options.id ?? uuid() + + const format = new ProofFormatSpec({ + attachmentId, + format: V2_INDY_PRESENTATION, + }) + + const attachment = new Attachment({ + id: attachmentId, + mimeType: 'application/json', + data: new AttachmentData({ + base64: JsonEncoder.toBase64(proof), + }), + }) + return { format, attachment } + } + + public async processPresentation(agentContext: AgentContext, options: ProcessPresentationOptions): Promise { + const requestFormat = options.formatAttachments.request.find( + (x) => x.format.format === V2_INDY_PRESENTATION_REQUEST + ) + + if (!requestFormat) { + throw new MissingIndyProofMessageError( + 'Missing Indy Proof Request format while trying to process an Indy proof presentation.' + ) + } + + const proofFormat = options.formatAttachments.presentation.find((x) => x.format.format === V2_INDY_PRESENTATION) + + if (!proofFormat) { + throw new MissingIndyProofMessageError( + 'Missing Indy Proof Presentation format while trying to process an Indy proof presentation.' + ) + } + + return await this.verifyProof(agentContext, { request: requestFormat.attachment, proof: proofFormat.attachment }) + } + + public async verifyProof(agentContext: AgentContext, options: VerifyProofOptions): Promise { + if (!options) { + throw new AriesFrameworkError('No Indy proof was provided.') + } + const proofRequestJson = options.request.getDataAsJson() ?? null + const proofRequest = JsonTransformer.fromJSON(proofRequestJson, ProofRequest) + + const proofJson = options.proof.getDataAsJson() ?? null + + const proof = JsonTransformer.fromJSON(proofJson, PartialProof) + + for (const [referent, attribute] of proof.requestedProof.revealedAttributes.entries()) { + if (!IndyCredentialUtils.checkValidEncoding(attribute.raw, attribute.encoded)) { + throw new InvalidEncodedValueError( + `The encoded value for '${referent}' is invalid. ` + + `Expected '${IndyCredentialUtils.encode(attribute.raw)}'. ` + + `Actual '${attribute.encoded}'` + ) + } + } + + // TODO: pre verify proof json + // I'm not 100% sure how much indy does. Also if it checks whether the proof requests matches the proof + // @see https://github.com/hyperledger/aries-cloudagent-python/blob/master/aries_cloudagent/indy/sdk/verifier.py#L79-L164 + + const schemas = await this.getSchemas(agentContext, new Set(proof.identifiers.map((i) => i.schemaId))) + const credentialDefinitions = await this.getCredentialDefinitions( + agentContext, + new Set(proof.identifiers.map((i) => i.credentialDefinitionId)) + ) + + return await this.indyVerifierService.verifyProof(agentContext, { + proofRequest: proofRequest.toJSON(), + proof: proofJson, + schemas, + credentialDefinitions, + }) + } + + public supportsFormat(formatIdentifier: string): boolean { + const supportedFormats = [V2_INDY_PRESENTATION_PROPOSAL, V2_INDY_PRESENTATION_REQUEST, V2_INDY_PRESENTATION] + return supportedFormats.includes(formatIdentifier) + } + + /** + * Compare presentation attrs with request/proposal attrs (auto-accept) + * + * @param proposalAttachments attachment data from the proposal + * @param requestAttachments attachment data from the request + * @returns boolean value + */ + public proposalAndRequestAreEqual( + proposalAttachments: ProofAttachmentFormat[], + requestAttachments: ProofAttachmentFormat[] + ) { + const proposalAttachment = proposalAttachments.find( + (x) => x.format.format === V2_INDY_PRESENTATION_PROPOSAL + )?.attachment + const requestAttachment = requestAttachments.find( + (x) => x.format.format === V2_INDY_PRESENTATION_REQUEST + )?.attachment + + if (!proposalAttachment) { + throw new AriesFrameworkError('Proposal message has no attachment linked to it') + } + + if (!requestAttachment) { + throw new AriesFrameworkError('Request message has no attachment linked to it') + } + + const proposalAttachmentJson = proposalAttachment.getDataAsJson() + const proposalAttachmentData = JsonTransformer.fromJSON(proposalAttachmentJson, ProofRequest) + + const requestAttachmentJson = requestAttachment.getDataAsJson() + const requestAttachmentData = JsonTransformer.fromJSON(requestAttachmentJson, ProofRequest) + + if ( + objectEquals(proposalAttachmentData.requestedAttributes, requestAttachmentData.requestedAttributes) && + objectEquals(proposalAttachmentData.requestedPredicates, requestAttachmentData.requestedPredicates) + ) { + return true + } + + return false + } + + /** + * Build credential definitions object needed to create and verify proof objects. + * + * Creates object with `{ credentialDefinitionId: CredentialDefinition }` mapping + * + * @param credentialDefinitionIds List of credential definition ids + * @returns Object containing credential definitions for specified credential definition ids + * + */ + private async getCredentialDefinitions(agentContext: AgentContext, credentialDefinitionIds: Set) { + const credentialDefinitions: { [key: string]: CredDef } = {} + + for (const credDefId of credentialDefinitionIds) { + const credDef = await this.ledgerService.getCredentialDefinition(agentContext, credDefId) + credentialDefinitions[credDefId] = credDef + } + + return credentialDefinitions + } + + public async getRequestedCredentialsForProofRequest( + agentContext: AgentContext, + options: GetRequestedCredentialsFormat + ): Promise> { + const retrievedCredentials = new RetrievedCredentials({}) + const { attachment, presentationProposal } = options + const filterByNonRevocationRequirements = options.config?.filterByNonRevocationRequirements + + const proofRequestJson = attachment.getDataAsJson() ?? null + const proofRequest = JsonTransformer.fromJSON(proofRequestJson, ProofRequest) + + for (const [referent, requestedAttribute] of proofRequest.requestedAttributes.entries()) { + let credentialMatch: IndyCredential[] = [] + const credentials = await this.getCredentialsForProofRequest(agentContext, proofRequest, referent) + + // If we have exactly one credential, or no proposal to pick preferences + // on the credentials to use, we will use the first one + if (credentials.length === 1 || !presentationProposal) { + credentialMatch = credentials + } + // If we have a proposal we will use that to determine the credentials to use + else { + const names = requestedAttribute.names ?? [requestedAttribute.name] + + // Find credentials that matches all parameters from the proposal + credentialMatch = credentials.filter((credential) => { + const { attributes, credentialDefinitionId } = credential.credentialInfo + + // Check if credentials matches all parameters from proposal + return names.every((name) => + presentationProposal.attributes.find( + (a) => + a.name === name && + a.credentialDefinitionId === credentialDefinitionId && + (!a.value || a.value === attributes[name]) + ) + ) + }) + } + + retrievedCredentials.requestedAttributes[referent] = await Promise.all( + credentialMatch.map(async (credential: IndyCredential) => { + const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, { + proofRequest, + requestedItem: requestedAttribute, + credential, + }) + + return new RequestedAttribute({ + credentialId: credential.credentialInfo.referent, + revealed: true, + credentialInfo: credential.credentialInfo, + timestamp: deltaTimestamp, + revoked, + }) + }) + ) + + // We only attach revoked state if non-revocation is requested. So if revoked is true it means + // the credential is not applicable to the proof request + if (filterByNonRevocationRequirements) { + retrievedCredentials.requestedAttributes[referent] = retrievedCredentials.requestedAttributes[referent].filter( + (r) => !r.revoked + ) + } + } + + for (const [referent, requestedPredicate] of proofRequest.requestedPredicates.entries()) { + const credentials = await this.getCredentialsForProofRequest(agentContext, proofRequest, referent) + + retrievedCredentials.requestedPredicates[referent] = await Promise.all( + credentials.map(async (credential) => { + const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, { + proofRequest, + requestedItem: requestedPredicate, + credential, + }) + + return new RequestedPredicate({ + credentialId: credential.credentialInfo.referent, + credentialInfo: credential.credentialInfo, + timestamp: deltaTimestamp, + revoked, + }) + }) + ) + + // We only attach revoked state if non-revocation is requested. So if revoked is true it means + // the credential is not applicable to the proof request + if (filterByNonRevocationRequirements) { + retrievedCredentials.requestedPredicates[referent] = retrievedCredentials.requestedPredicates[referent].filter( + (r) => !r.revoked + ) + } + } + + return { + proofFormats: { + indy: retrievedCredentials, + }, + } + } + + private async getCredentialsForProofRequest( + agentContext: AgentContext, + proofRequest: ProofRequest, + attributeReferent: string + ): Promise { + const credentialsJson = await this.indyHolderService.getCredentialsForProofRequest(agentContext, { + proofRequest: proofRequest.toJSON(), + attributeReferent, + }) + + return JsonTransformer.fromJSON(credentialsJson, IndyCredential) as unknown as IndyCredential[] + } + + public async autoSelectCredentialsForProofRequest( + options: FormatRetrievedCredentialOptions<[IndyProofFormat]> + ): Promise> { + const { proofFormats } = options + const indy = proofFormats.indy + + if (!indy) { + throw new AriesFrameworkError('No indy options provided') + } + + const requestedCredentials = new RequestedCredentials({}) + + Object.keys(indy.requestedAttributes).forEach((attributeName) => { + const attributeArray = indy.requestedAttributes[attributeName] + + if (attributeArray.length === 0) { + throw new AriesFrameworkError('Unable to automatically select requested attributes.') + } else { + requestedCredentials.requestedAttributes[attributeName] = attributeArray[0] + } + }) + + Object.keys(indy.requestedPredicates).forEach((attributeName) => { + if (indy.requestedPredicates[attributeName].length === 0) { + throw new AriesFrameworkError('Unable to automatically select requested predicates.') + } else { + requestedCredentials.requestedPredicates[attributeName] = indy.requestedPredicates[attributeName][0] + } + }) + + return { + proofFormats: { + indy: requestedCredentials, + }, + } + } + + /** + * Build schemas object needed to create and verify proof objects. + * + * Creates object with `{ schemaId: Schema }` mapping + * + * @param schemaIds List of schema ids + * @returns Object containing schemas for specified schema ids + * + */ + private async getSchemas(agentContext: AgentContext, schemaIds: Set) { + const schemas: { [key: string]: Schema } = {} + + for (const schemaId of schemaIds) { + const schema = await this.ledgerService.getSchema(agentContext, schemaId) + schemas[schemaId] = schema + } + + return schemas + } + + /** + * Create indy proof from a given proof request and requested credential object. + * + * @param proofRequest The proof request to create the proof for + * @param requestedCredentials The requested credentials object specifying which credentials to use for the proof + * @returns indy proof object + */ + private async createProof( + agentContext: AgentContext, + proofRequest: ProofRequest, + requestedCredentials: RequestedCredentials + ): Promise { + const credentialObjects = await Promise.all( + [ + ...Object.values(requestedCredentials.requestedAttributes), + ...Object.values(requestedCredentials.requestedPredicates), + ].map(async (c) => { + if (c.credentialInfo) { + return c.credentialInfo + } + const credentialInfo = await this.indyHolderService.getCredential(agentContext, c.credentialId) + return JsonTransformer.fromJSON(credentialInfo, IndyCredentialInfo) + }) + ) + + const schemas = await this.getSchemas(agentContext, new Set(credentialObjects.map((c) => c.schemaId))) + const credentialDefinitions = await this.getCredentialDefinitions( + agentContext, + new Set(credentialObjects.map((c) => c.credentialDefinitionId)) + ) + + return await this.indyHolderService.createProof(agentContext, { + proofRequest: proofRequest.toJSON(), + requestedCredentials: requestedCredentials, + schemas, + credentialDefinitions, + }) + } + + public async createProofRequestFromProposal(options: CreatePresentationFormatsOptions): Promise { + const proofRequestJson = options.presentationAttachment.getDataAsJson() + + const proofRequest = JsonTransformer.fromJSON(proofRequestJson, ProofRequest) + + // Assert attachment + if (!proofRequest) { + throw new AriesFrameworkError(`Missing required base64 or json encoded attachment data for presentation request.`) + } + await MessageValidator.validateSync(proofRequest) + + // Assert attribute and predicate (group) names do not match + checkProofRequestForDuplicates(proofRequest) + + return { + indy: proofRequest, + } + } + + private async getRevocationStatusForRequestedItem( + agentContext: AgentContext, + { + proofRequest, + requestedItem, + credential, + }: { + proofRequest: ProofRequest + requestedItem: ProofAttributeInfo | ProofPredicateInfo + credential: IndyCredential + } + ) { + const requestNonRevoked = requestedItem.nonRevoked ?? proofRequest.nonRevoked + const credentialRevocationId = credential.credentialInfo.credentialRevocationId + const revocationRegistryId = credential.credentialInfo.revocationRegistryId + + // If revocation interval is present and the credential is revocable then fetch the revocation status of credentials for display + if (requestNonRevoked && credentialRevocationId && revocationRegistryId) { + this.logger.trace( + `Presentation is requesting proof of non revocation, getting revocation status for credential`, + { + requestNonRevoked, + credentialRevocationId, + revocationRegistryId, + } + ) + + // Note presentation from-to's vs ledger from-to's: https://github.com/hyperledger/indy-hipe/blob/master/text/0011-cred-revocation/README.md#indy-node-revocation-registry-intervals + const status = await this.indyRevocationService.getRevocationStatus( + agentContext, + credentialRevocationId, + revocationRegistryId, + requestNonRevoked + ) + + return status + } + + return { revoked: undefined, deltaTimestamp: undefined } + } +} diff --git a/packages/core/src/modules/proofs/formats/indy/IndyProofFormatsServiceOptions.ts b/packages/core/src/modules/proofs/formats/indy/IndyProofFormatsServiceOptions.ts new file mode 100644 index 0000000000..f5bc85f69a --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/IndyProofFormatsServiceOptions.ts @@ -0,0 +1,44 @@ +import type { Attachment } from '../../../../decorators/attachment/Attachment' +import type { IndyRevocationInterval } from '../../../credentials' +import type { GetRequestedCredentialsConfig } from '../../models/GetRequestedCredentialsConfig' +import type { PresentationPreview } from '../../protocol/v1/models/V1PresentationPreview' +import type { ProofRecord } from '../../repository/ProofRecord' +import type { RequestedAttribute, RequestedPredicate } from '.././indy/models' +import type { ProofAttributeInfo } from '.././indy/models/ProofAttributeInfo' +import type { ProofPredicateInfo } from '.././indy/models/ProofPredicateInfo' +import type { ProofRequest } from '.././indy/models/ProofRequest' + +export interface IndyRequestProofFormat { + name: string + version: string + nonce: string + nonRevoked?: IndyRevocationInterval + ver?: '1.0' | '2.0' + requestedAttributes?: Record | Map + requestedPredicates?: Record | Map + proofRequest?: ProofRequest +} + +export interface IndyVerifyProofFormat { + proofJson: Attachment + proofRequest: Attachment +} + +export interface IndyPresentationProofFormat { + requestedAttributes?: Record + requestedPredicates?: Record + selfAttestedAttributes?: Record +} + +export interface GetRequestedCredentialsFormat { + attachment: Attachment + presentationProposal?: PresentationPreview + config?: GetRequestedCredentialsConfig +} + +export interface IndyProofRequestFromProposalOptions { + proofRecord: ProofRecord + name?: string + version?: string + nonce?: string +} diff --git a/packages/core/src/modules/proofs/formats/indy/IndyProofUtils.ts b/packages/core/src/modules/proofs/formats/indy/IndyProofUtils.ts new file mode 100644 index 0000000000..137d9edb25 --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/IndyProofUtils.ts @@ -0,0 +1,115 @@ +import type { CreateProposalOptions } from '../../models/ProofServiceOptions' +import type { ProofRequestFormats } from '../../models/SharedOptions' +import type { PresentationPreviewAttribute } from '../../protocol/v1/models/V1PresentationPreview' +import type { IndyProofFormat, IndyProposeProofFormat } from './IndyProofFormat' + +import { AriesFrameworkError } from '../../../../error/AriesFrameworkError' +import { uuid } from '../../../../utils/uuid' +import { PresentationPreview } from '../../protocol/v1/models/V1PresentationPreview' + +import { AttributeFilter } from './models/AttributeFilter' +import { ProofAttributeInfo } from './models/ProofAttributeInfo' +import { ProofPredicateInfo } from './models/ProofPredicateInfo' +import { ProofRequest } from './models/ProofRequest' + +export class IndyProofUtils { + public static async createRequestFromPreview( + options: CreateProposalOptions<[IndyProofFormat]> + ): Promise { + const indyFormat = options.proofFormats?.indy + + if (!indyFormat) { + throw new AriesFrameworkError('No Indy format found.') + } + + const preview = new PresentationPreview({ + attributes: indyFormat.attributes, + predicates: indyFormat.predicates, + }) + + if (!preview) { + throw new AriesFrameworkError(`No preview found`) + } + + const proofRequest = IndyProofUtils.createReferentForProofRequest(indyFormat, preview) + + return { + indy: proofRequest, + } + } + + public static createReferentForProofRequest( + indyFormat: IndyProposeProofFormat, + preview: PresentationPreview + ): ProofRequest { + const proofRequest = new ProofRequest({ + name: indyFormat.name, + version: indyFormat.version, + nonce: indyFormat.nonce, + }) + + /** + * Create mapping of attributes by referent. This required the + * attributes to come from the same credential. + * @see https://github.com/hyperledger/aries-rfcs/blob/master/features/0037-present-proof/README.md#referent + * + * { + * "referent1": [Attribute1, Attribute2], + * "referent2": [Attribute3] + * } + */ + const attributesByReferent: Record = {} + for (const proposedAttributes of preview.attributes) { + if (!proposedAttributes.referent) proposedAttributes.referent = uuid() + + const referentAttributes = attributesByReferent[proposedAttributes.referent] + + // Referent key already exist, add to list + if (referentAttributes) { + referentAttributes.push(proposedAttributes) + } + + // Referent key does not exist yet, create new entry + else { + attributesByReferent[proposedAttributes.referent] = [proposedAttributes] + } + } + + // Transform attributes by referent to requested attributes + for (const [referent, proposedAttributes] of Object.entries(attributesByReferent)) { + // Either attributeName or attributeNames will be undefined + const attributeName = proposedAttributes.length == 1 ? proposedAttributes[0].name : undefined + const attributeNames = proposedAttributes.length > 1 ? proposedAttributes.map((a) => a.name) : undefined + + const requestedAttribute = new ProofAttributeInfo({ + name: attributeName, + names: attributeNames, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: proposedAttributes[0].credentialDefinitionId, + }), + ], + }) + + proofRequest.requestedAttributes.set(referent, requestedAttribute) + } + + // Transform proposed predicates to requested predicates + for (const proposedPredicate of preview.predicates) { + const requestedPredicate = new ProofPredicateInfo({ + name: proposedPredicate.name, + predicateType: proposedPredicate.predicate, + predicateValue: proposedPredicate.threshold, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: proposedPredicate.credentialDefinitionId, + }), + ], + }) + + proofRequest.requestedPredicates.set(uuid(), requestedPredicate) + } + + return proofRequest + } +} diff --git a/packages/core/src/modules/proofs/formats/indy/errors/InvalidEncodedValueError.ts b/packages/core/src/modules/proofs/formats/indy/errors/InvalidEncodedValueError.ts new file mode 100644 index 0000000000..84ac6e1385 --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/errors/InvalidEncodedValueError.ts @@ -0,0 +1,3 @@ +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' + +export class InvalidEncodedValueError extends AriesFrameworkError {} diff --git a/packages/core/src/modules/proofs/formats/indy/errors/MissingIndyProofMessageError.ts b/packages/core/src/modules/proofs/formats/indy/errors/MissingIndyProofMessageError.ts new file mode 100644 index 0000000000..2ab9c3f15e --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/errors/MissingIndyProofMessageError.ts @@ -0,0 +1,3 @@ +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' + +export class MissingIndyProofMessageError extends AriesFrameworkError {} diff --git a/packages/core/src/modules/proofs/models/AttributeFilter.ts b/packages/core/src/modules/proofs/formats/indy/models/AttributeFilter.ts similarity index 98% rename from packages/core/src/modules/proofs/models/AttributeFilter.ts rename to packages/core/src/modules/proofs/formats/indy/models/AttributeFilter.ts index 90b628799e..b2a804ab2d 100644 --- a/packages/core/src/modules/proofs/models/AttributeFilter.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/AttributeFilter.ts @@ -1,7 +1,7 @@ import { Expose, Transform, TransformationType, Type } from 'class-transformer' import { IsInstance, IsOptional, IsString, Matches, ValidateNested } from 'class-validator' -import { credDefIdRegex, indyDidRegex, schemaIdRegex, schemaVersionRegex } from '../../../utils' +import { credDefIdRegex, indyDidRegex, schemaIdRegex, schemaVersionRegex } from '../../../../../utils/regex' export class AttributeValue { public constructor(options: AttributeValue) { diff --git a/packages/core/src/modules/proofs/models/PredicateType.ts b/packages/core/src/modules/proofs/formats/indy/models/PredicateType.ts similarity index 100% rename from packages/core/src/modules/proofs/models/PredicateType.ts rename to packages/core/src/modules/proofs/formats/indy/models/PredicateType.ts diff --git a/packages/core/src/modules/proofs/models/ProofAttributeInfo.ts b/packages/core/src/modules/proofs/formats/indy/models/ProofAttributeInfo.ts similarity index 84% rename from packages/core/src/modules/proofs/models/ProofAttributeInfo.ts rename to packages/core/src/modules/proofs/formats/indy/models/ProofAttributeInfo.ts index bc2edd724b..4bf1f136b0 100644 --- a/packages/core/src/modules/proofs/models/ProofAttributeInfo.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/ProofAttributeInfo.ts @@ -1,7 +1,7 @@ import { Expose, Type } from 'class-transformer' -import { IsString, IsOptional, IsArray, ValidateNested, IsInstance, ValidateIf, ArrayNotEmpty } from 'class-validator' +import { ArrayNotEmpty, IsArray, IsInstance, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator' -import { IndyRevocationInterval } from '../../credentials' +import { IndyRevocationInterval } from '../../../../credentials' import { AttributeFilter } from './AttributeFilter' diff --git a/packages/core/src/modules/proofs/models/ProofPredicateInfo.ts b/packages/core/src/modules/proofs/formats/indy/models/ProofPredicateInfo.ts similarity index 94% rename from packages/core/src/modules/proofs/models/ProofPredicateInfo.ts rename to packages/core/src/modules/proofs/formats/indy/models/ProofPredicateInfo.ts index 00aa1f310b..8f246746bf 100644 --- a/packages/core/src/modules/proofs/models/ProofPredicateInfo.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/ProofPredicateInfo.ts @@ -1,7 +1,7 @@ import { Expose, Type } from 'class-transformer' import { IsArray, IsEnum, IsInstance, IsInt, IsOptional, IsString, ValidateNested } from 'class-validator' -import { IndyRevocationInterval } from '../../credentials' +import { IndyRevocationInterval } from '../../../../credentials' import { AttributeFilter } from './AttributeFilter' import { PredicateType } from './PredicateType' diff --git a/packages/core/src/modules/proofs/models/ProofRequest.ts b/packages/core/src/modules/proofs/formats/indy/models/ProofRequest.ts similarity index 90% rename from packages/core/src/modules/proofs/models/ProofRequest.ts rename to packages/core/src/modules/proofs/formats/indy/models/ProofRequest.ts index 17d92f8f35..224169c864 100644 --- a/packages/core/src/modules/proofs/models/ProofRequest.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/ProofRequest.ts @@ -1,11 +1,11 @@ import type { IndyProofRequest } from 'indy-sdk' import { Expose, Type } from 'class-transformer' -import { IsString, ValidateNested, IsOptional, IsIn, IsInstance } from 'class-validator' +import { IsIn, IsInstance, IsOptional, IsString, ValidateNested } from 'class-validator' -import { JsonTransformer } from '../../../utils/JsonTransformer' -import { IsMap } from '../../../utils/transformers' -import { IndyRevocationInterval } from '../../credentials' +import { JsonTransformer } from '../../../../../utils/JsonTransformer' +import { IsMap } from '../../../../../utils/transformers' +import { IndyRevocationInterval } from '../../../../credentials' import { ProofAttributeInfo } from './ProofAttributeInfo' import { ProofPredicateInfo } from './ProofPredicateInfo' diff --git a/packages/core/src/modules/proofs/models/RequestedAttribute.ts b/packages/core/src/modules/proofs/formats/indy/models/RequestedAttribute.ts similarity index 89% rename from packages/core/src/modules/proofs/models/RequestedAttribute.ts rename to packages/core/src/modules/proofs/formats/indy/models/RequestedAttribute.ts index 4998a8b097..048a89cf82 100644 --- a/packages/core/src/modules/proofs/models/RequestedAttribute.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/RequestedAttribute.ts @@ -1,7 +1,7 @@ import { Exclude, Expose } from 'class-transformer' import { IsBoolean, IsInt, IsOptional, IsString } from 'class-validator' -import { IndyCredentialInfo } from '../../credentials' +import { IndyCredentialInfo } from '../../../../credentials/formats/indy/models/IndyCredentialInfo' /** * Requested Attribute for Indy proof creation diff --git a/packages/core/src/modules/proofs/models/RequestedCredentials.ts b/packages/core/src/modules/proofs/formats/indy/models/RequestedCredentials.ts similarity index 87% rename from packages/core/src/modules/proofs/models/RequestedCredentials.ts rename to packages/core/src/modules/proofs/formats/indy/models/RequestedCredentials.ts index 5d15cae028..b2824bf7bd 100644 --- a/packages/core/src/modules/proofs/models/RequestedCredentials.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/RequestedCredentials.ts @@ -3,13 +3,13 @@ import type { IndyRequestedCredentials } from 'indy-sdk' import { Expose } from 'class-transformer' import { ValidateNested } from 'class-validator' -import { JsonTransformer } from '../../../utils/JsonTransformer' -import { RecordTransformer } from '../../../utils/transformers' +import { JsonTransformer } from '../../../../../utils/JsonTransformer' +import { RecordTransformer } from '../../../../../utils/transformers' import { RequestedAttribute } from './RequestedAttribute' import { RequestedPredicate } from './RequestedPredicate' -interface RequestedCredentialsOptions { +export interface IndyRequestedCredentialsOptions { requestedAttributes?: Record requestedPredicates?: Record selfAttestedAttributes?: Record @@ -21,7 +21,7 @@ interface RequestedCredentialsOptions { * @see https://github.com/hyperledger/indy-sdk/blob/57dcdae74164d1c7aa06f2cccecaae121cefac25/libindy/src/api/anoncreds.rs#L1433-L1445 */ export class RequestedCredentials { - public constructor(options: RequestedCredentialsOptions = {}) { + public constructor(options: IndyRequestedCredentialsOptions = {}) { if (options) { this.requestedAttributes = options.requestedAttributes ?? {} this.requestedPredicates = options.requestedPredicates ?? {} diff --git a/packages/core/src/modules/proofs/models/RequestedPredicate.ts b/packages/core/src/modules/proofs/formats/indy/models/RequestedPredicate.ts similarity index 92% rename from packages/core/src/modules/proofs/models/RequestedPredicate.ts rename to packages/core/src/modules/proofs/formats/indy/models/RequestedPredicate.ts index 5e7d4dc5f9..9109b51a4d 100644 --- a/packages/core/src/modules/proofs/models/RequestedPredicate.ts +++ b/packages/core/src/modules/proofs/formats/indy/models/RequestedPredicate.ts @@ -1,7 +1,7 @@ import { Exclude, Expose } from 'class-transformer' import { IsInt, IsOptional, IsString } from 'class-validator' -import { IndyCredentialInfo } from '../../credentials' +import { IndyCredentialInfo } from '../../../../credentials' /** * Requested Predicate for Indy proof creation diff --git a/packages/core/src/modules/proofs/models/RetrievedCredentials.ts b/packages/core/src/modules/proofs/formats/indy/models/RetrievedCredentials.ts similarity index 100% rename from packages/core/src/modules/proofs/models/RetrievedCredentials.ts rename to packages/core/src/modules/proofs/formats/indy/models/RetrievedCredentials.ts diff --git a/packages/core/src/modules/proofs/formats/indy/models/index.ts b/packages/core/src/modules/proofs/formats/indy/models/index.ts new file mode 100644 index 0000000000..b38776d360 --- /dev/null +++ b/packages/core/src/modules/proofs/formats/indy/models/index.ts @@ -0,0 +1,7 @@ +export * from './ProofAttributeInfo' +export * from './ProofPredicateInfo' +export * from './RequestedAttribute' +export * from './RequestedPredicate' +export * from './ProofRequest' +export * from './AttributeFilter' +export * from './PredicateType' diff --git a/packages/core/src/modules/proofs/formats/models/ProofAttachmentFormat.ts b/packages/core/src/modules/proofs/formats/models/ProofAttachmentFormat.ts new file mode 100644 index 0000000000..5bc2fc881b --- /dev/null +++ b/packages/core/src/modules/proofs/formats/models/ProofAttachmentFormat.ts @@ -0,0 +1,7 @@ +import type { Attachment } from '../../../../decorators/attachment/Attachment' +import type { ProofFormatSpec } from '../../models/ProofFormatSpec' + +export interface ProofAttachmentFormat { + format: ProofFormatSpec + attachment: Attachment +} diff --git a/packages/core/src/modules/proofs/formats/models/ProofFormatServiceOptions.ts b/packages/core/src/modules/proofs/formats/models/ProofFormatServiceOptions.ts new file mode 100644 index 0000000000..8212d2b6dd --- /dev/null +++ b/packages/core/src/modules/proofs/formats/models/ProofFormatServiceOptions.ts @@ -0,0 +1,64 @@ +import type { Attachment } from '../../../../decorators/attachment/Attachment' +import type { ProposeProofFormats } from '../../models/SharedOptions' +import type { ProofRecord } from '../../repository' +import type { ProofFormat, ProofFormatPayload } from '../ProofFormat' +import type { ProofRequestOptions } from '../indy/models/ProofRequest' +import type { ProofAttachmentFormat } from './ProofAttachmentFormat' + +export interface CreateRequestAttachmentOptions { + id?: string + proofRequestOptions: ProofRequestOptions +} + +export interface CreateProofAttachmentOptions { + id?: string + proofProposalOptions: ProofRequestOptions +} + +export interface CreateProposalOptions { + id?: string + formats: ProposeProofFormats +} + +export interface ProcessProposalOptions { + proposal: ProofAttachmentFormat + record?: ProofRecord +} + +export interface CreateRequestOptions { + id?: string + formats: ProposeProofFormats +} + +export interface ProcessRequestOptions { + requestAttachment: ProofAttachmentFormat + record?: ProofRecord +} + +export interface FormatCreatePresentationOptions { + id?: string + attachment: Attachment + proofFormats: ProofFormatPayload<[PF], 'createPresentation'> +} + +export interface ProcessPresentationOptions { + record: ProofRecord + formatAttachments: { + request: ProofAttachmentFormat[] + presentation: ProofAttachmentFormat[] + } +} + +export interface VerifyProofOptions { + request: Attachment + proof: Attachment +} + +export interface CreateProblemReportOptions { + proofRecord: ProofRecord + description: string +} + +export interface CreatePresentationFormatsOptions { + presentationAttachment: Attachment +} diff --git a/packages/core/src/modules/proofs/handlers/PresentationAckHandler.ts b/packages/core/src/modules/proofs/handlers/PresentationAckHandler.ts deleted file mode 100644 index fa7b194df6..0000000000 --- a/packages/core/src/modules/proofs/handlers/PresentationAckHandler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Handler, HandlerInboundMessage } from '../../../agent/Handler' -import type { ProofService } from '../services' - -import { PresentationAckMessage } from '../messages' - -export class PresentationAckHandler implements Handler { - private proofService: ProofService - public supportedMessages = [PresentationAckMessage] - - public constructor(proofService: ProofService) { - this.proofService = proofService - } - - public async handle(messageContext: HandlerInboundMessage) { - await this.proofService.processAck(messageContext) - } -} diff --git a/packages/core/src/modules/proofs/handlers/PresentationHandler.ts b/packages/core/src/modules/proofs/handlers/PresentationHandler.ts deleted file mode 100644 index 8f651a9562..0000000000 --- a/packages/core/src/modules/proofs/handlers/PresentationHandler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { Handler, HandlerInboundMessage } from '../../../agent/Handler' -import type { Logger } from '../../../logger' -import type { ProofResponseCoordinator } from '../ProofResponseCoordinator' -import type { ProofRecord } from '../repository' -import type { ProofService } from '../services' - -import { createOutboundMessage, createOutboundServiceMessage } from '../../../agent/helpers' -import { PresentationMessage } from '../messages' - -export class PresentationHandler implements Handler { - private proofService: ProofService - private proofResponseCoordinator: ProofResponseCoordinator - private logger: Logger - public supportedMessages = [PresentationMessage] - - public constructor(proofService: ProofService, proofResponseCoordinator: ProofResponseCoordinator, logger: Logger) { - this.proofService = proofService - this.proofResponseCoordinator = proofResponseCoordinator - this.logger = logger - } - - public async handle(messageContext: HandlerInboundMessage) { - const proofRecord = await this.proofService.processPresentation(messageContext) - - if (this.proofResponseCoordinator.shouldAutoRespondToPresentation(messageContext.agentContext, proofRecord)) { - return await this.createAck(proofRecord, messageContext) - } - } - - private async createAck(record: ProofRecord, messageContext: HandlerInboundMessage) { - this.logger.info(`Automatically sending acknowledgement with autoAccept`) - - const { message, proofRecord } = await this.proofService.createAck(messageContext.agentContext, record) - - if (messageContext.connection) { - return createOutboundMessage(messageContext.connection, message) - } else if (proofRecord.requestMessage?.service && proofRecord.presentationMessage?.service) { - const recipientService = proofRecord.presentationMessage?.service - const ourService = proofRecord.requestMessage?.service - - return createOutboundServiceMessage({ - payload: message, - service: recipientService.resolvedDidCommService, - senderKey: ourService.resolvedDidCommService.recipientKeys[0], - }) - } - - this.logger.error(`Could not automatically create presentation ack`) - } -} diff --git a/packages/core/src/modules/proofs/handlers/PresentationProblemReportHandler.ts b/packages/core/src/modules/proofs/handlers/PresentationProblemReportHandler.ts deleted file mode 100644 index 925941e3a4..0000000000 --- a/packages/core/src/modules/proofs/handlers/PresentationProblemReportHandler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Handler, HandlerInboundMessage } from '../../../agent/Handler' -import type { ProofService } from '../services' - -import { PresentationProblemReportMessage } from '../messages' - -export class PresentationProblemReportHandler implements Handler { - private proofService: ProofService - public supportedMessages = [PresentationProblemReportMessage] - - public constructor(proofService: ProofService) { - this.proofService = proofService - } - - public async handle(messageContext: HandlerInboundMessage) { - await this.proofService.processProblemReport(messageContext) - } -} diff --git a/packages/core/src/modules/proofs/handlers/ProposePresentationHandler.ts b/packages/core/src/modules/proofs/handlers/ProposePresentationHandler.ts deleted file mode 100644 index 3e07ebfc60..0000000000 --- a/packages/core/src/modules/proofs/handlers/ProposePresentationHandler.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { Handler, HandlerInboundMessage } from '../../../agent/Handler' -import type { Logger } from '../../../logger' -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 proofResponseCoordinator: ProofResponseCoordinator - private logger: Logger - public supportedMessages = [ProposePresentationMessage] - - public constructor(proofService: ProofService, proofResponseCoordinator: ProofResponseCoordinator, logger: Logger) { - this.proofService = proofService - this.proofResponseCoordinator = proofResponseCoordinator - this.logger = logger - } - - public async handle(messageContext: HandlerInboundMessage) { - const proofRecord = await this.proofService.processProposal(messageContext) - - if (this.proofResponseCoordinator.shouldAutoRespondToProposal(messageContext.agentContext, proofRecord)) { - return await this.createRequest(proofRecord, messageContext) - } - } - - private async createRequest( - proofRecord: ProofRecord, - messageContext: HandlerInboundMessage - ) { - this.logger.info(`Automatically sending request with autoAccept`) - - if (!messageContext.connection) { - this.logger.error('No connection on the messageContext') - return - } - if (!proofRecord.proposalMessage) { - this.logger.error(`Proof record with id ${proofRecord.id} is missing required credential proposal`) - return - } - const proofRequest = await this.proofService.createProofRequestFromProposal( - messageContext.agentContext, - proofRecord.proposalMessage.presentationProposal, - { - name: 'proof-request', - version: '1.0', - } - ) - - const { message } = await this.proofService.createRequestAsResponse( - messageContext.agentContext, - proofRecord, - proofRequest - ) - - return createOutboundMessage(messageContext.connection, message) - } -} diff --git a/packages/core/src/modules/proofs/handlers/RequestPresentationHandler.ts b/packages/core/src/modules/proofs/handlers/RequestPresentationHandler.ts deleted file mode 100644 index e2839783c8..0000000000 --- a/packages/core/src/modules/proofs/handlers/RequestPresentationHandler.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { Handler, HandlerInboundMessage } from '../../../agent/Handler' -import type { Logger } from '../../../logger' -import type { RoutingService } from '../../routing/services/RoutingService' -import type { ProofResponseCoordinator } from '../ProofResponseCoordinator' -import type { ProofRecord } from '../repository' -import type { ProofService } from '../services' - -import { createOutboundMessage, createOutboundServiceMessage } from '../../../agent/helpers' -import { ServiceDecorator } from '../../../decorators/service/ServiceDecorator' -import { RequestPresentationMessage } from '../messages' - -export class RequestPresentationHandler implements Handler { - private proofService: ProofService - private proofResponseCoordinator: ProofResponseCoordinator - private routingService: RoutingService - private logger: Logger - public supportedMessages = [RequestPresentationMessage] - - public constructor( - proofService: ProofService, - proofResponseCoordinator: ProofResponseCoordinator, - routingService: RoutingService, - logger: Logger - ) { - this.proofService = proofService - this.proofResponseCoordinator = proofResponseCoordinator - this.routingService = routingService - this.logger = logger - } - - public async handle(messageContext: HandlerInboundMessage) { - const proofRecord = await this.proofService.processRequest(messageContext) - - if (this.proofResponseCoordinator.shouldAutoRespondToRequest(messageContext.agentContext, proofRecord)) { - return await this.createPresentation(proofRecord, messageContext) - } - } - - private async createPresentation( - record: ProofRecord, - messageContext: HandlerInboundMessage - ) { - const indyProofRequest = record.requestMessage?.indyProofRequest - const presentationProposal = record.proposalMessage?.presentationProposal - - this.logger.info(`Automatically sending presentation with autoAccept`) - - if (!indyProofRequest) { - this.logger.error('Proof request is undefined.') - return - } - - const retrievedCredentials = await this.proofService.getRequestedCredentialsForProofRequest( - messageContext.agentContext, - indyProofRequest, - { - presentationProposal, - } - ) - - const requestedCredentials = this.proofService.autoSelectCredentialsForProofRequest(retrievedCredentials) - - const { message, proofRecord } = await this.proofService.createPresentation( - messageContext.agentContext, - record, - requestedCredentials - ) - - if (messageContext.connection) { - return createOutboundMessage(messageContext.connection, message) - } else if (proofRecord.requestMessage?.service) { - // Create ~service decorator - const routing = await this.routingService.getRouting(messageContext.agentContext) - const ourService = new ServiceDecorator({ - serviceEndpoint: routing.endpoints[0], - recipientKeys: [routing.recipientKey.publicKeyBase58], - routingKeys: routing.routingKeys.map((key) => key.publicKeyBase58), - }) - - const recipientService = proofRecord.requestMessage.service - - // Set and save ~service decorator to record (to remember our verkey) - message.service = ourService - proofRecord.presentationMessage = message - await this.proofService.update(messageContext.agentContext, proofRecord) - - return createOutboundServiceMessage({ - payload: message, - service: recipientService.resolvedDidCommService, - senderKey: ourService.resolvedDidCommService.recipientKeys[0], - }) - } - - this.logger.error(`Could not automatically create presentation`) - } -} diff --git a/packages/core/src/modules/proofs/handlers/index.ts b/packages/core/src/modules/proofs/handlers/index.ts deleted file mode 100644 index ba30911942..0000000000 --- a/packages/core/src/modules/proofs/handlers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './PresentationAckHandler' -export * from './PresentationHandler' -export * from './ProposePresentationHandler' -export * from './RequestPresentationHandler' -export * from './PresentationProblemReportHandler' diff --git a/packages/core/src/modules/proofs/index.ts b/packages/core/src/modules/proofs/index.ts index 44efac8eba..7660d50fa2 100644 --- a/packages/core/src/modules/proofs/index.ts +++ b/packages/core/src/modules/proofs/index.ts @@ -1,9 +1,10 @@ -export * from './messages' +export * from './protocol/v1/messages' +export * from './protocol/v1/models' +export * from './protocol/v2/messages' +export * from './ProofService' export * from './models' -export * from './services' -export * from './ProofState' export * from './repository' export * from './ProofEvents' -export * from './ProofsApi' -export * from './ProofAutoAcceptType' +export * from './formats/indy/models' +export * from './formats/indy/IndyProofUtils' export * from './ProofsModule' diff --git a/packages/core/src/modules/proofs/messages/PresentationAckMessage.ts b/packages/core/src/modules/proofs/messages/PresentationAckMessage.ts index 12d405f6dc..64e60f56b2 100644 --- a/packages/core/src/modules/proofs/messages/PresentationAckMessage.ts +++ b/packages/core/src/modules/proofs/messages/PresentationAckMessage.ts @@ -1,19 +1,10 @@ +import type { ProtocolVersion } from '../../../types' import type { AckMessageOptions } from '../../common' -import { IsValidMessageType, parseMessageType } from '../../../utils/messageType' -import { AckMessage } from '../../common' - export type PresentationAckMessageOptions = AckMessageOptions -/** - * @see https://github.com/hyperledger/aries-rfcs/blob/master/features/0015-acks/README.md#explicit-acks - */ -export class PresentationAckMessage extends AckMessage { - public constructor(options: PresentationAckMessageOptions) { - super(options) - } +type PresentationAckMessageType = `https://didcomm.org/present-proof/${ProtocolVersion}/ack` - @IsValidMessageType(PresentationAckMessage.type) - public readonly type = PresentationAckMessage.type.messageTypeUri - public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/ack') +export interface PresentationAckMessage { + type: PresentationAckMessageType } diff --git a/packages/core/src/modules/proofs/messages/PresentationProblemReportMessage.ts b/packages/core/src/modules/proofs/messages/PresentationProblemReportMessage.ts deleted file mode 100644 index 2d62a6e2b9..0000000000 --- a/packages/core/src/modules/proofs/messages/PresentationProblemReportMessage.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ProblemReportMessageOptions } from '../../problem-reports/messages/ProblemReportMessage' - -import { IsValidMessageType, parseMessageType } from '../../../utils/messageType' -import { ProblemReportMessage } from '../../problem-reports/messages/ProblemReportMessage' - -export type PresentationProblemReportMessageOptions = ProblemReportMessageOptions - -/** - * @see https://github.com/hyperledger/aries-rfcs/blob/main/features/0035-report-problem/README.md - */ -export class PresentationProblemReportMessage extends ProblemReportMessage { - /** - * Create new PresentationProblemReportMessage instance. - * @param options - */ - public constructor(options: PresentationProblemReportMessageOptions) { - super(options) - } - - @IsValidMessageType(PresentationProblemReportMessage.type) - public readonly type = PresentationProblemReportMessage.type.messageTypeUri - public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/problem-report') -} diff --git a/packages/core/src/modules/proofs/messages/index.ts b/packages/core/src/modules/proofs/messages/index.ts deleted file mode 100644 index f2ad906c75..0000000000 --- a/packages/core/src/modules/proofs/messages/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './ProposePresentationMessage' -export * from './RequestPresentationMessage' -export * from './PresentationMessage' -export * from './PresentationPreview' -export * from './PresentationAckMessage' -export * from './PresentationProblemReportMessage' diff --git a/packages/core/src/modules/proofs/models/GetRequestedCredentialsConfig.ts b/packages/core/src/modules/proofs/models/GetRequestedCredentialsConfig.ts new file mode 100644 index 0000000000..9041bbabe3 --- /dev/null +++ b/packages/core/src/modules/proofs/models/GetRequestedCredentialsConfig.ts @@ -0,0 +1,19 @@ +export interface GetRequestedCredentialsConfig { + /** + * Whether to filter the retrieved credentials using the presentation preview. + * This configuration will only have effect if a presentation proposal message is available + * containing a presentation preview. + * + * @default false + */ + filterByPresentationPreview?: boolean + + /** + * Whether to filter the retrieved credentials using the non-revocation request in the proof request. + * This configuration will only have effect if the proof request requires proof on non-revocation of any kind. + * Default to true + * + * @default true + */ + filterByNonRevocationRequirements?: boolean +} diff --git a/packages/core/src/modules/proofs/models/ModuleOptions.ts b/packages/core/src/modules/proofs/models/ModuleOptions.ts new file mode 100644 index 0000000000..f60e9d853b --- /dev/null +++ b/packages/core/src/modules/proofs/models/ModuleOptions.ts @@ -0,0 +1,20 @@ +import type { GetRequestedCredentialsConfig } from './GetRequestedCredentialsConfig' +import type { AutoAcceptProof } from './ProofAutoAcceptType' +import type { ProposeProofFormats } from './SharedOptions' + +export interface ProofConfig { + name: string + version: string +} + +export interface NegotiateRequestOptions { + proofRecordId: string + proofFormats: ProposeProofFormats + comment?: string + autoAcceptProof?: AutoAcceptProof +} + +export interface AutoSelectCredentialsForProofRequestOptions { + proofRecordId: string + config?: GetRequestedCredentialsConfig +} diff --git a/packages/core/src/modules/proofs/ProofAutoAcceptType.ts b/packages/core/src/modules/proofs/models/ProofAutoAcceptType.ts similarity index 100% rename from packages/core/src/modules/proofs/ProofAutoAcceptType.ts rename to packages/core/src/modules/proofs/models/ProofAutoAcceptType.ts diff --git a/packages/core/src/modules/proofs/models/ProofFormatSpec.ts b/packages/core/src/modules/proofs/models/ProofFormatSpec.ts new file mode 100644 index 0000000000..54c0b40f73 --- /dev/null +++ b/packages/core/src/modules/proofs/models/ProofFormatSpec.ts @@ -0,0 +1,25 @@ +import { Expose } from 'class-transformer' +import { IsString } from 'class-validator' + +import { uuid } from '../../../utils/uuid' + +export interface ProofFormatSpecOptions { + attachmentId?: string + format: string +} + +export class ProofFormatSpec { + public constructor(options: ProofFormatSpecOptions) { + if (options) { + this.attachmentId = options.attachmentId ?? uuid() + this.format = options.format + } + } + + @Expose({ name: 'attach_id' }) + @IsString() + public attachmentId!: string + + @IsString() + public format!: string +} diff --git a/packages/core/src/modules/proofs/models/ProofProtocolVersion.ts b/packages/core/src/modules/proofs/models/ProofProtocolVersion.ts new file mode 100644 index 0000000000..6027d21111 --- /dev/null +++ b/packages/core/src/modules/proofs/models/ProofProtocolVersion.ts @@ -0,0 +1,4 @@ +export enum ProofProtocolVersion { + V1 = 'v1', + V2 = 'v2', +} diff --git a/packages/core/src/modules/proofs/models/ProofServiceOptions.ts b/packages/core/src/modules/proofs/models/ProofServiceOptions.ts new file mode 100644 index 0000000000..7e97a9884a --- /dev/null +++ b/packages/core/src/modules/proofs/models/ProofServiceOptions.ts @@ -0,0 +1,71 @@ +import type { ConnectionRecord } from '../../connections' +import type { ProofFormat, ProofFormatPayload } from '../formats/ProofFormat' +import type { ProofRecord } from '../repository' +import type { GetRequestedCredentialsConfig } from './GetRequestedCredentialsConfig' +import type { AutoAcceptProof } from './ProofAutoAcceptType' + +interface BaseOptions { + willConfirm?: boolean + goalCode?: string + comment?: string + autoAcceptProof?: AutoAcceptProof +} + +export interface CreateProposalOptions extends BaseOptions { + connectionRecord: ConnectionRecord + proofFormats: ProofFormatPayload +} + +export interface CreateProposalAsResponseOptions extends BaseOptions { + proofRecord: ProofRecord + proofFormats: ProofFormatPayload +} + +export interface CreateRequestAsResponseOptions extends BaseOptions { + id?: string + proofRecord: ProofRecord + proofFormats: ProofFormatPayload +} + +// ----- Out Of Band Proof ----- // +export interface CreateOutOfBandRequestOptions extends BaseOptions { + proofFormats: ProofFormatPayload +} + +export interface CreateRequestOptions extends BaseOptions { + connectionRecord?: ConnectionRecord + proofFormats: ProofFormatPayload +} + +export interface CreateProofRequestFromProposalOptions extends BaseOptions { + id?: string + proofRecord: ProofRecord +} + +export interface FormatRetrievedCredentialOptions { + proofFormats: ProofFormatPayload +} + +export interface FormatRequestedCredentialReturn { + proofFormats: ProofFormatPayload +} + +export interface CreatePresentationOptions extends BaseOptions { + proofRecord: ProofRecord + proofFormats: ProofFormatPayload // + lastPresentation?: boolean +} + +export interface CreateAckOptions { + proofRecord: ProofRecord +} + +export interface GetRequestedCredentialsForProofRequestOptions { + proofRecord: ProofRecord + config?: GetRequestedCredentialsConfig +} + +export interface ProofRequestFromProposalOptions { + proofRecord: ProofRecord + proofFormats: ProofFormatPayload +} diff --git a/packages/core/src/modules/proofs/ProofState.ts b/packages/core/src/modules/proofs/models/ProofState.ts similarity index 94% rename from packages/core/src/modules/proofs/ProofState.ts rename to packages/core/src/modules/proofs/models/ProofState.ts index 73869e80aa..e10b5d1ff8 100644 --- a/packages/core/src/modules/proofs/ProofState.ts +++ b/packages/core/src/modules/proofs/models/ProofState.ts @@ -11,5 +11,6 @@ export enum ProofState { PresentationSent = 'presentation-sent', PresentationReceived = 'presentation-received', Declined = 'declined', + Abandoned = 'abandoned', Done = 'done', } diff --git a/packages/core/src/modules/proofs/models/SharedOptions.ts b/packages/core/src/modules/proofs/models/SharedOptions.ts new file mode 100644 index 0000000000..e479dea456 --- /dev/null +++ b/packages/core/src/modules/proofs/models/SharedOptions.ts @@ -0,0 +1,62 @@ +import type { IndyProposeProofFormat } from '../formats/indy/IndyProofFormat' +import type { IndyRequestProofFormat, IndyVerifyProofFormat } from '../formats/indy/IndyProofFormatsServiceOptions' +import type { ProofRequest } from '../formats/indy/models/ProofRequest' +import type { IndyRequestedCredentialsOptions } from '../formats/indy/models/RequestedCredentials' +import type { RetrievedCredentials } from '../formats/indy/models/RetrievedCredentials' +import type { GetRequestedCredentialsConfig } from './GetRequestedCredentialsConfig' + +export interface ProposeProofFormats { + // If you want to propose an indy proof without attributes or + // any of the other properties you should pass an empty object + indy?: IndyProposeProofFormat + presentationExchange?: never +} + +export interface RequestProofFormats { + indy?: IndyRequestProofFormat + presentationExchange?: never +} + +export interface CreatePresentationFormats { + indy?: IndyRequestedCredentialsOptions + presentationExchange?: never +} + +export interface AcceptProposalFormats { + indy?: IndyAcceptProposalOptions + presentationExchange?: never +} + +export interface VerifyProofFormats { + indy?: IndyVerifyProofFormat + presentationExchange?: never +} + +export interface RequestedCredentialConfigOptions { + indy?: GetRequestedCredentialsConfig + presentationExchange?: never +} + +// export interface RetrievedCredentialOptions { +// indy?: RetrievedCredentials +// presentationExchange?: undefined +// } + +export interface ProofRequestFormats { + indy?: ProofRequest + presentationExchange?: undefined +} + +// export interface RequestedCredentialsFormats { +// indy?: RequestedCredentials +// presentationExchange?: undefined +// } + +interface IndyAcceptProposalOptions { + request: ProofRequest +} + +export interface AutoSelectCredentialOptions { + indy?: RetrievedCredentials + presentationExchange?: undefined +} diff --git a/packages/core/src/modules/proofs/models/index.ts b/packages/core/src/modules/proofs/models/index.ts index d313158b63..827448009e 100644 --- a/packages/core/src/modules/proofs/models/index.ts +++ b/packages/core/src/modules/proofs/models/index.ts @@ -1,13 +1,4 @@ -export * from './AttributeFilter' -export * from './PartialProof' -export * from './PredicateType' -export * from './ProofAttribute' -export * from './ProofAttributeInfo' -export * from './ProofIdentifier' -export * from './ProofPredicateInfo' -export * from './ProofRequest' -export * from './RequestedAttribute' -export * from './RequestedCredentials' -export * from './RequestedPredicate' -export * from './RequestedProof' -export * from './RetrievedCredentials' +export * from './GetRequestedCredentialsConfig' +export * from './ProofAutoAcceptType' +export * from './ProofProtocolVersion' +export * from './ProofState' diff --git a/packages/core/src/modules/proofs/protocol/v1/V1ProofService.ts b/packages/core/src/modules/proofs/protocol/v1/V1ProofService.ts new file mode 100644 index 0000000000..a97f002388 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/V1ProofService.ts @@ -0,0 +1,1039 @@ +import type { AgentContext } from '../../../../agent' +import type { AgentMessage } from '../../../../agent/AgentMessage' +import type { Dispatcher } from '../../../../agent/Dispatcher' +import type { InboundMessageContext } from '../../../../agent/models/InboundMessageContext' +import type { Attachment } from '../../../../decorators/attachment/Attachment' +import type { MediationRecipientService } from '../../../routing/services/MediationRecipientService' +import type { RoutingService } from '../../../routing/services/RoutingService' +import type { ProofResponseCoordinator } from '../../ProofResponseCoordinator' +import type { ProofFormat } from '../../formats/ProofFormat' +import type { ProofFormatService } from '../../formats/ProofFormatService' +import type { IndyProofFormat, IndyProposeProofFormat } from '../../formats/indy/IndyProofFormat' +import type { ProofAttributeInfo } from '../../formats/indy/models' +import type { + CreateProblemReportOptions, + FormatCreatePresentationOptions, +} from '../../formats/models/ProofFormatServiceOptions' +import type { + CreateAckOptions, + CreatePresentationOptions, + CreateProofRequestFromProposalOptions, + CreateProposalAsResponseOptions, + CreateProposalOptions, + CreateRequestAsResponseOptions, + CreateRequestOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, + GetRequestedCredentialsForProofRequestOptions, + ProofRequestFromProposalOptions, +} from '../../models/ProofServiceOptions' + +import { validateOrReject } from 'class-validator' +import { inject, Lifecycle, scoped } from 'tsyringe' + +import { AgentConfig } from '../../../../agent/AgentConfig' +import { EventEmitter } from '../../../../agent/EventEmitter' +import { InjectionSymbols } from '../../../../constants' +import { AriesFrameworkError } from '../../../../error/AriesFrameworkError' +import { DidCommMessageRole } from '../../../../storage' +import { DidCommMessageRepository } from '../../../../storage/didcomm/DidCommMessageRepository' +import { checkProofRequestForDuplicates } from '../../../../utils' +import { JsonTransformer } from '../../../../utils/JsonTransformer' +import { MessageValidator } from '../../../../utils/MessageValidator' +import { Wallet } from '../../../../wallet' +import { AckStatus } from '../../../common/messages/AckMessage' +import { ConnectionService } from '../../../connections' +import { CredentialRepository } from '../../../credentials' +import { IndyCredentialInfo } from '../../../credentials/formats/indy/models/IndyCredentialInfo' +import { IndyHolderService, IndyRevocationService } from '../../../indy' +import { IndyLedgerService } from '../../../ledger/services/IndyLedgerService' +import { ProofService } from '../../ProofService' +import { PresentationProblemReportReason } from '../../errors/PresentationProblemReportReason' +import { IndyProofFormatService } from '../../formats/indy/IndyProofFormatService' +import { IndyProofUtils } from '../../formats/indy/IndyProofUtils' +import { ProofRequest } from '../../formats/indy/models/ProofRequest' +import { RequestedCredentials } from '../../formats/indy/models/RequestedCredentials' +import { ProofProtocolVersion } from '../../models/ProofProtocolVersion' +import { ProofState } from '../../models/ProofState' +import { ProofRecord } from '../../repository/ProofRecord' +import { ProofRepository } from '../../repository/ProofRepository' + +import { V1PresentationProblemReportError } from './errors' +import { + V1PresentationAckHandler, + V1PresentationHandler, + V1PresentationProblemReportHandler, + V1ProposePresentationHandler, + V1RequestPresentationHandler, +} from './handlers' +import { + INDY_PROOF_ATTACHMENT_ID, + INDY_PROOF_REQUEST_ATTACHMENT_ID, + V1PresentationAckMessage, + V1PresentationMessage, + V1ProposePresentationMessage, + V1RequestPresentationMessage, +} from './messages' +import { V1PresentationProblemReportMessage } from './messages/V1PresentationProblemReportMessage' +import { PresentationPreview } from './models/V1PresentationPreview' + +/** + * @todo add method to check if request matches proposal. Useful to see if a request I received is the same as the proposal I sent. + * @todo add method to reject / revoke messages + * @todo validate attachments / messages + */ +@scoped(Lifecycle.ContainerScoped) +export class V1ProofService extends ProofService<[IndyProofFormat]> { + private credentialRepository: CredentialRepository + private ledgerService: IndyLedgerService + private indyHolderService: IndyHolderService + private indyRevocationService: IndyRevocationService + private indyProofFormatService: ProofFormatService + + public constructor( + proofRepository: ProofRepository, + didCommMessageRepository: DidCommMessageRepository, + ledgerService: IndyLedgerService, + @inject(InjectionSymbols.Wallet) wallet: Wallet, + agentConfig: AgentConfig, + connectionService: ConnectionService, + eventEmitter: EventEmitter, + credentialRepository: CredentialRepository, + formatService: IndyProofFormatService, + indyHolderService: IndyHolderService, + indyRevocationService: IndyRevocationService + ) { + super(agentConfig, proofRepository, connectionService, didCommMessageRepository, wallet, eventEmitter) + this.credentialRepository = credentialRepository + this.ledgerService = ledgerService + this.wallet = wallet + this.indyProofFormatService = formatService + this.indyHolderService = indyHolderService + this.indyRevocationService = indyRevocationService + } + + public readonly version = 'v1' as const + + public async createProposal( + agentContext: AgentContext, + options: CreateProposalOptions<[IndyProofFormat]> + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const { connectionRecord, proofFormats } = options + + // Assert + connectionRecord.assertReady() + + if (!proofFormats.indy || Object.keys(proofFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + + const presentationProposal = new PresentationPreview({ + attributes: proofFormats.indy?.attributes, + predicates: proofFormats.indy?.predicates, + }) + + // Create message + const proposalMessage = new V1ProposePresentationMessage({ + comment: options?.comment, + presentationProposal, + }) + + // Create record + const proofRecord = new ProofRecord({ + connectionId: connectionRecord.id, + threadId: proposalMessage.threadId, + state: ProofState.ProposalSent, + autoAcceptProof: options?.autoAcceptProof, + protocolVersion: ProofProtocolVersion.V1, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: proposalMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + await this.proofRepository.save(agentContext, proofRecord) + this.emitStateChangedEvent(agentContext, proofRecord, null) + + return { proofRecord, message: proposalMessage } + } + + public async createProposalAsResponse( + agentContext: AgentContext, + options: CreateProposalAsResponseOptions<[IndyProofFormat]> + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const { proofRecord, proofFormats, comment } = options + + // Assert + proofRecord.assertState(ProofState.RequestReceived) + + if (!proofFormats.indy || Object.keys(proofFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + + // Create message + const presentationPreview = new PresentationPreview({ + attributes: proofFormats.indy?.attributes, + predicates: proofFormats.indy?.predicates, + }) + + const proposalMessage: V1ProposePresentationMessage = new V1ProposePresentationMessage({ + comment, + presentationProposal: presentationPreview, + }) + + proposalMessage.setThread({ threadId: proofRecord.threadId }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: proposalMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + // Update record + await this.updateState(agentContext, proofRecord, ProofState.ProposalSent) + + return { proofRecord, message: proposalMessage } + } + + public async processProposal( + messageContext: InboundMessageContext + ): Promise { + let proofRecord: ProofRecord + const { message: proposalMessage, connection } = messageContext + + this.logger.debug(`Processing presentation proposal with id ${proposalMessage.id}`) + + try { + // Proof record already exists + proofRecord = await this.getByThreadAndConnectionId( + messageContext.agentContext, + proposalMessage.threadId, + connection?.id + ) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.RequestSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: proposalMessage, + previousSentMessage: requestMessage ?? undefined, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proposalMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Update record + await this.updateState(messageContext.agentContext, proofRecord, ProofState.ProposalReceived) + } catch { + // No proof record exists with thread id + proofRecord = new ProofRecord({ + connectionId: connection?.id, + threadId: proposalMessage.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + // Assert + this.connectionService.assertConnectionOrServiceDecorator(messageContext) + + // Save record + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proposalMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + await this.proofRepository.save(messageContext.agentContext, proofRecord) + + this.emitStateChangedEvent(messageContext.agentContext, proofRecord, null) + } + + return proofRecord + } + + public async createRequestAsResponse( + agentContext: AgentContext, + options: CreateRequestAsResponseOptions<[IndyProofFormat]> + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const { proofRecord, comment, proofFormats } = options + if (!proofFormats.indy) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + + // Assert + proofRecord.assertState(ProofState.ProposalReceived) + + // Create message + const { attachment } = await this.indyProofFormatService.createRequest({ + id: INDY_PROOF_REQUEST_ATTACHMENT_ID, + formats: proofFormats, + }) + + const requestPresentationMessage = new V1RequestPresentationMessage({ + comment, + requestPresentationAttachments: [attachment], + }) + requestPresentationMessage.setThread({ + threadId: proofRecord.threadId, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: requestPresentationMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + // Update record + await this.updateState(agentContext, proofRecord, ProofState.RequestSent) + + return { message: requestPresentationMessage, proofRecord } + } + + public async createRequest( + agentContext: AgentContext, + options: CreateRequestOptions<[IndyProofFormat]> + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + this.logger.debug(`Creating proof request`) + + // Assert + if (options.connectionRecord) { + options.connectionRecord.assertReady() + } + + if (!options.proofFormats.indy || Object.keys(options.proofFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + + // Create message + const { attachment } = await this.indyProofFormatService.createRequest({ + id: INDY_PROOF_REQUEST_ATTACHMENT_ID, + formats: options.proofFormats, + }) + + const requestPresentationMessage = new V1RequestPresentationMessage({ + comment: options?.comment, + requestPresentationAttachments: [attachment], + }) + + // Create record + const proofRecord = new ProofRecord({ + connectionId: options.connectionRecord?.id, + threadId: requestPresentationMessage.threadId, + state: ProofState.RequestSent, + autoAcceptProof: options?.autoAcceptProof, + protocolVersion: ProofProtocolVersion.V1, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: requestPresentationMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + await this.proofRepository.save(agentContext, proofRecord) + this.emitStateChangedEvent(agentContext, proofRecord, null) + + return { message: requestPresentationMessage, proofRecord } + } + + public async processRequest( + messageContext: InboundMessageContext + ): Promise { + let proofRecord: ProofRecord + const { message: proofRequestMessage, connection } = messageContext + + this.logger.debug(`Processing presentation request with id ${proofRequestMessage.id}`) + + const requestAttachments = proofRequestMessage.getAttachmentFormats() + + for (const attachmentFormat of requestAttachments) { + await this.indyProofFormatService.processRequest({ + requestAttachment: attachmentFormat, + }) + } + + const proofRequest = proofRequestMessage.indyProofRequest + + // Assert attachment + if (!proofRequest) { + throw new V1PresentationProblemReportError( + `Missing required base64 or json encoded attachment data for presentation request with thread id ${proofRequestMessage.threadId}`, + { problemCode: PresentationProblemReportReason.Abandoned } + ) + } + await validateOrReject(proofRequest) + + // Assert attribute and predicate (group) names do not match + checkProofRequestForDuplicates(proofRequest) + + this.logger.debug('received proof request', proofRequest) + + try { + // Proof record already exists + proofRecord = await this.getByThreadAndConnectionId( + messageContext.agentContext, + proofRequestMessage.threadId, + connection?.id + ) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.ProposalSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: requestMessage ?? undefined, + previousSentMessage: proposalMessage ?? undefined, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proofRequestMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Update record + await this.updateState(messageContext.agentContext, proofRecord, ProofState.RequestReceived) + } catch { + // No proof record exists with thread id + proofRecord = new ProofRecord({ + connectionId: connection?.id, + threadId: proofRequestMessage.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proofRequestMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Assert + this.connectionService.assertConnectionOrServiceDecorator(messageContext) + + // Save in repository + await this.proofRepository.save(messageContext.agentContext, proofRecord) + this.emitStateChangedEvent(messageContext.agentContext, proofRecord, null) + } + + return proofRecord + } + + public async createPresentation( + agentContext: AgentContext, + options: CreatePresentationOptions<[IndyProofFormat]> + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const { proofRecord, proofFormats } = options + + this.logger.debug(`Creating presentation for proof record with id ${proofRecord.id}`) + + if (!proofFormats.indy || Object.keys(proofFormats).length !== 1) { + throw new AriesFrameworkError('Only indy proof format is supported for present proof protocol v1') + } + + // Assert + proofRecord.assertState(ProofState.RequestReceived) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + const requestAttachment = requestMessage?.indyAttachment + + if (!requestAttachment) { + throw new V1PresentationProblemReportError( + `Missing required base64 or json encoded attachment data for presentation with thread id ${proofRecord.threadId}`, + { problemCode: PresentationProblemReportReason.Abandoned } + ) + } + + const presentationOptions: FormatCreatePresentationOptions = { + id: INDY_PROOF_ATTACHMENT_ID, + attachment: requestAttachment, + proofFormats: proofFormats, + } + + const proof = await this.indyProofFormatService.createPresentation(agentContext, presentationOptions) + + // Extract proof request from attachment + const proofRequestJson = requestAttachment.getDataAsJson() ?? null + const proofRequest = JsonTransformer.fromJSON(proofRequestJson, ProofRequest) + + const requestedCredentials = new RequestedCredentials({ + requestedAttributes: proofFormats.indy?.requestedAttributes, + requestedPredicates: proofFormats.indy?.requestedPredicates, + selfAttestedAttributes: proofFormats.indy?.selfAttestedAttributes, + }) + + // Get the matching attachments to the requested credentials + const linkedAttachments = await this.getRequestedAttachmentsForRequestedCredentials( + agentContext, + proofRequest, + requestedCredentials + ) + + const presentationMessage = new V1PresentationMessage({ + comment: options?.comment, + presentationAttachments: [proof.attachment], + attachments: linkedAttachments, + }) + presentationMessage.setThread({ threadId: proofRecord.threadId }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: presentationMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + // Update record + await this.updateState(agentContext, proofRecord, ProofState.PresentationSent) + + return { message: presentationMessage, proofRecord } + } + + public async processPresentation(messageContext: InboundMessageContext): Promise { + const { message: presentationMessage, connection } = messageContext + + this.logger.debug(`Processing presentation with id ${presentationMessage.id}`) + + const proofRecord = await this.getByThreadAndConnectionId( + messageContext.agentContext, + presentationMessage.threadId, + connection?.id + ) + + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + const requestMessage = await this.didCommMessageRepository.getAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.RequestSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: proposalMessage ?? undefined, + previousSentMessage: requestMessage ?? undefined, + }) + + try { + const isValid = await this.indyProofFormatService.processPresentation(messageContext.agentContext, { + record: proofRecord, + formatAttachments: { + presentation: presentationMessage.getAttachmentFormats(), + request: requestMessage.getAttachmentFormats(), + }, + }) + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: presentationMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Update record + proofRecord.isVerified = isValid + await this.updateState(messageContext.agentContext, proofRecord, ProofState.PresentationReceived) + } catch (e) { + if (e instanceof AriesFrameworkError) { + throw new V1PresentationProblemReportError(e.message, { + problemCode: PresentationProblemReportReason.Abandoned, + }) + } + throw e + } + + return proofRecord + } + + public async processAck(messageContext: InboundMessageContext): Promise { + const { message: presentationAckMessage, connection } = messageContext + + this.logger.debug(`Processing presentation ack with id ${presentationAckMessage.id}`) + + const proofRecord = await this.getByThreadAndConnectionId( + messageContext.agentContext, + presentationAckMessage.threadId, + connection?.id + ) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + const presentationMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1PresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.PresentationSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: requestMessage ?? undefined, + previousSentMessage: presentationMessage ?? undefined, + }) + + // Update record + await this.updateState(messageContext.agentContext, proofRecord, ProofState.Done) + + return proofRecord + } + + public async createProblemReport( + agentContext: AgentContext, + options: CreateProblemReportOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const msg = new V1PresentationProblemReportMessage({ + description: { + code: PresentationProblemReportReason.Abandoned, + en: options.description, + }, + }) + + msg.setThread({ + threadId: options.proofRecord.threadId, + }) + + return { + proofRecord: options.proofRecord, + message: msg, + } + } + + public async processProblemReport( + messageContext: InboundMessageContext + ): Promise { + const { message: presentationProblemReportMessage } = messageContext + + const connection = messageContext.assertReadyConnection() + + this.logger.debug(`Processing problem report with id ${presentationProblemReportMessage.id}`) + + const proofRecord = await this.getByThreadAndConnectionId( + messageContext.agentContext, + presentationProblemReportMessage.threadId, + connection?.id + ) + + proofRecord.errorMessage = `${presentationProblemReportMessage.description.code}: ${presentationProblemReportMessage.description.en}` + await this.updateState(messageContext.agentContext, proofRecord, ProofState.Abandoned) + return proofRecord + } + + public async generateProofRequestNonce() { + return this.wallet.generateNonce() + } + + public async createProofRequestFromProposal( + agentContext: AgentContext, + options: CreateProofRequestFromProposalOptions + ): Promise> { + const proofRecordId = options.proofRecord.id + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V1ProposePresentationMessage, + }) + + if (!proposalMessage) { + throw new AriesFrameworkError(`Proof record with id ${proofRecordId} is missing required presentation proposal`) + } + + const indyProposeProofFormat: IndyProposeProofFormat = { + name: 'Proof Request', + version: '1.0', + nonce: await this.generateProofRequestNonce(), + } + + const proofRequest: ProofRequest = IndyProofUtils.createReferentForProofRequest( + indyProposeProofFormat, + proposalMessage.presentationProposal + ) + + return { + proofRecord: options.proofRecord, + proofFormats: { + indy: proofRequest, + }, + } + } + + /** + * Retrieves the linked attachments for an {@link indyProofRequest} + * @param indyProofRequest The proof request for which the linked attachments have to be found + * @param requestedCredentials The requested credentials + * @returns a list of attachments that are linked to the requested credentials + */ + public async getRequestedAttachmentsForRequestedCredentials( + agentContext: AgentContext, + indyProofRequest: ProofRequest, + requestedCredentials: RequestedCredentials + ): Promise { + const attachments: Attachment[] = [] + const credentialIds = new Set() + const requestedAttributesNames: (string | undefined)[] = [] + + // Get the credentialIds if it contains a hashlink + for (const [referent, requestedAttribute] of Object.entries(requestedCredentials.requestedAttributes)) { + // Find the requested Attributes + const requestedAttributes = indyProofRequest.requestedAttributes.get(referent) as ProofAttributeInfo + + // List the requested attributes + requestedAttributesNames.push(...(requestedAttributes.names ?? [requestedAttributes.name])) + + //Get credentialInfo + if (!requestedAttribute.credentialInfo) { + const indyCredentialInfo = await this.indyHolderService.getCredential( + agentContext, + requestedAttribute.credentialId + ) + requestedAttribute.credentialInfo = JsonTransformer.fromJSON(indyCredentialInfo, IndyCredentialInfo) + } + + // Find the attributes that have a hashlink as a value + for (const attribute of Object.values(requestedAttribute.credentialInfo.attributes)) { + if (attribute.toLowerCase().startsWith('hl:')) { + credentialIds.add(requestedAttribute.credentialId) + } + } + } + + // Only continues if there is an attribute value that contains a hashlink + for (const credentialId of credentialIds) { + // Get the credentialRecord that matches the ID + + const credentialRecord = await this.credentialRepository.getSingleByQuery(agentContext, { + credentialIds: [credentialId], + }) + + if (credentialRecord.linkedAttachments) { + // Get the credentials that have a hashlink as value and are requested + const requestedCredentials = credentialRecord.credentialAttributes?.filter( + (credential) => + credential.value.toLowerCase().startsWith('hl:') && requestedAttributesNames.includes(credential.name) + ) + + // Get the linked attachments that match the requestedCredentials + const linkedAttachments = credentialRecord.linkedAttachments.filter((attachment) => + requestedCredentials?.map((credential) => credential.value.split(':')[1]).includes(attachment.id) + ) + + if (linkedAttachments) { + attachments.push(...linkedAttachments) + } + } + } + + return attachments.length ? attachments : undefined + } + + public async shouldAutoRespondToProposal(agentContext: AgentContext, proofRecord: ProofRecord): Promise { + const proposal = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + if (!proposal) { + return false + } + await MessageValidator.validateSync(proposal) + + // check the proposal against a possible previous request + const request = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + if (!request) { + return false + } + + const proofRequest = request.indyProofRequest + + if (!proofRequest) { + throw new V1PresentationProblemReportError( + `Missing required base64 or json encoded attachment data for presentation request with thread id ${request.threadId}`, + { problemCode: PresentationProblemReportReason.Abandoned } + ) + } + await validateOrReject(proofRequest) + + // Assert attribute and predicate (group) names do not match + checkProofRequestForDuplicates(proofRequest) + + const proposalAttributes = proposal.presentationProposal.attributes + const requestedAttributes = proofRequest.requestedAttributes + + const proposedAttributeNames = proposalAttributes.map((x) => x.name) + let requestedAttributeNames: string[] = [] + + const requestedAttributeList = Array.from(requestedAttributes.values()) + + requestedAttributeList.forEach((x) => { + if (x.name) { + requestedAttributeNames.push(x.name) + } else if (x.names) { + requestedAttributeNames = requestedAttributeNames.concat(x.names) + } + }) + + if (requestedAttributeNames.length > proposedAttributeNames.length) { + // more attributes are requested than have been proposed + return false + } + + requestedAttributeNames.forEach((x) => { + if (!proposedAttributeNames.includes(x)) { + this.logger.debug(`Attribute ${x} was requested but wasn't proposed.`) + return false + } + }) + + // assert that all requested attributes are provided + const providedPredicateNames = proposal.presentationProposal.predicates.map((x) => x.name) + proofRequest.requestedPredicates.forEach((x) => { + if (!providedPredicateNames.includes(x.name)) { + return false + } + }) + return true + } + + public async shouldAutoRespondToRequest(agentContext: AgentContext, proofRecord: ProofRecord): Promise { + const proposal = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + if (!proposal) { + return false + } + + const request = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + if (!request) { + throw new AriesFrameworkError(`Expected to find a request message for ProofRecord with id ${proofRecord.id}`) + } + + const proofRequest = request.indyProofRequest + + // Assert attachment + if (!proofRequest) { + throw new V1PresentationProblemReportError( + `Missing required base64 or json encoded attachment data for presentation request with thread id ${request.threadId}`, + { problemCode: PresentationProblemReportReason.Abandoned } + ) + } + await validateOrReject(proofRequest) + + // Assert attribute and predicate (group) names do not match + checkProofRequestForDuplicates(proofRequest) + + const proposalAttributes = proposal.presentationProposal.attributes + const requestedAttributes = proofRequest.requestedAttributes + + const proposedAttributeNames = proposalAttributes.map((x) => x.name) + let requestedAttributeNames: string[] = [] + + const requestedAttributeList = Array.from(requestedAttributes.values()) + + requestedAttributeList.forEach((x) => { + if (x.name) { + requestedAttributeNames.push(x.name) + } else if (x.names) { + requestedAttributeNames = requestedAttributeNames.concat(x.names) + } + }) + + if (requestedAttributeNames.length > proposedAttributeNames.length) { + // more attributes are requested than have been proposed + return false + } + + requestedAttributeNames.forEach((x) => { + if (!proposedAttributeNames.includes(x)) { + this.logger.debug(`Attribute ${x} was requested but wasn't proposed.`) + return false + } + }) + + // assert that all requested attributes are provided + const providedPredicateNames = proposal.presentationProposal.predicates.map((x) => x.name) + proofRequest.requestedPredicates.forEach((x) => { + if (!providedPredicateNames.includes(x.name)) { + return false + } + }) + + return true + } + + public async shouldAutoRespondToPresentation(agentContext: AgentContext, proofRecord: ProofRecord): Promise { + this.logger.debug(`Should auto respond to presentation for proof record id: ${proofRecord.id}`) + return true + } + + public async getRequestedCredentialsForProofRequest( + agentContext: AgentContext, + options: GetRequestedCredentialsForProofRequestOptions + ): Promise> { + const requestMessage = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + const indyProofRequest = requestMessage?.requestPresentationAttachments + + if (!indyProofRequest) { + throw new AriesFrameworkError('Could not find proof request') + } + + const requestedCredentials: FormatRetrievedCredentialOptions<[IndyProofFormat]> = + await this.indyProofFormatService.getRequestedCredentialsForProofRequest(agentContext, { + attachment: indyProofRequest[0], + presentationProposal: proposalMessage?.presentationProposal, + config: options.config ?? undefined, + }) + return requestedCredentials + } + + public async autoSelectCredentialsForProofRequest( + options: FormatRetrievedCredentialOptions + ): Promise> { + return await this.indyProofFormatService.autoSelectCredentialsForProofRequest(options) + } + + public registerHandlers( + dispatcher: Dispatcher, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + mediationRecipientService: MediationRecipientService, + routingService: RoutingService + ): void { + dispatcher.registerHandler( + new V1ProposePresentationHandler(this, agentConfig, proofResponseCoordinator, this.didCommMessageRepository) + ) + + dispatcher.registerHandler( + new V1RequestPresentationHandler( + this, + agentConfig, + proofResponseCoordinator, + mediationRecipientService, + this.didCommMessageRepository, + routingService + ) + ) + + dispatcher.registerHandler( + new V1PresentationHandler(this, agentConfig, proofResponseCoordinator, this.didCommMessageRepository) + ) + dispatcher.registerHandler(new V1PresentationAckHandler(this)) + dispatcher.registerHandler(new V1PresentationProblemReportHandler(this)) + } + + public async findRequestMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise { + return await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V1RequestPresentationMessage, + }) + } + public async findPresentationMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise { + return await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V1PresentationMessage, + }) + } + + public async findProposalMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise { + return await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V1ProposePresentationMessage, + }) + } + + /** + * Retrieve all proof records + * + * @returns List containing all proof records + */ + public async getAll(agentContext: AgentContext): Promise { + return this.proofRepository.getAll(agentContext) + } + + /** + * Retrieve a proof record by connection id and thread id + * + * @param connectionId The connection id + * @param threadId The thread id + * @throws {RecordNotFoundError} If no record is found + * @throws {RecordDuplicateError} If multiple records are found + * @returns The proof record + */ + public async getByThreadAndConnectionId( + agentContext: AgentContext, + threadId: string, + connectionId?: string + ): Promise { + return this.proofRepository.getSingleByQuery(agentContext, { threadId, connectionId }) + } + + public async createAck( + gentContext: AgentContext, + options: CreateAckOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const { proofRecord } = options + this.logger.debug(`Creating presentation ack for proof record with id ${proofRecord.id}`) + + // Assert + proofRecord.assertState(ProofState.PresentationReceived) + + // Create message + const ackMessage = new V1PresentationAckMessage({ + status: AckStatus.OK, + threadId: proofRecord.threadId, + }) + + // Update record + await this.updateState(gentContext, proofRecord, ProofState.Done) + + return { message: ackMessage, proofRecord } + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-presentation.test.ts b/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-presentation.test.ts new file mode 100644 index 0000000000..eb9effdb0d --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-presentation.test.ts @@ -0,0 +1,246 @@ +import type { Agent } from '../../../../../agent/Agent' +import type { ConnectionRecord } from '../../../../connections/repository/ConnectionRecord' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { PresentationPreview } from '../models/V1PresentationPreview' + +import { setupProofsTest, waitForProofRecord } from '../../../../../../tests/helpers' +import testLogger from '../../../../../../tests/logger' +import { DidCommMessageRepository } from '../../../../../storage/didcomm' +import { ProofProtocolVersion } from '../../../models/ProofProtocolVersion' +import { ProofState } from '../../../models/ProofState' +import { V1PresentationMessage, V1ProposePresentationMessage, V1RequestPresentationMessage } from '../messages' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + let faberProofRecord: ProofRecord + let aliceProofRecord: ProofRecord + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, aliceConnection, presentationPreview } = await setupProofsTest( + 'Faber agent', + 'Alice agent' + )) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test(`Alice Creates and sends Proof Proposal to Faber`, async () => { + testLogger.test('Alice sends proof proposal to Faber') + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + aliceProofRecord = await aliceAgent.proofs.proposeProof({ + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'ProofRequest', + nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + comment: 'V1 propose proof test', + }) + + testLogger.test('Faber waits for presentation from Alice') + + faberProofRecord = await faberProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/propose-presentation', + id: expect.any(String), + comment: 'V1 propose proof test', + presentationProposal: { + type: 'https://didcomm.org/present-proof/1.0/presentation-preview', + attributes: [ + { + name: 'name', + credentialDefinitionId: presentationPreview.attributes[0].credentialDefinitionId, + value: 'John', + referent: '0', + }, + { + name: 'image_0', + credentialDefinitionId: presentationPreview.attributes[1].credentialDefinitionId, + }, + ], + predicates: [ + { + name: 'age', + credentialDefinitionId: presentationPreview.predicates[0].credentialDefinitionId, + predicate: '>=', + threshold: 50, + }, + ], + }, + }) + expect(faberProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + }) + + test(`Faber accepts the Proposal send by Alice`, async () => { + // Accept Proposal + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + }) + + testLogger.test('Faber accepts presentation proposal from Alice') + faberProofRecord = await faberAgent.proofs.acceptProposal({ + proofRecordId: faberProofRecord.id, + }) + + testLogger.test('Alice waits for proof request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/request-presentation', + id: expect.any(String), + requestPresentationAttachments: [ + { + id: 'libindy-request-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(aliceProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + }) + + test(`Alice accepts presentation request from Faber`, async () => { + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + // Faber waits for the presentation from Alice + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + const presentation = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1PresentationMessage, + }) + + expect(presentation).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/presentation', + id: expect.any(String), + presentationAttachments: [ + { + id: 'libindy-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + appendedAttachments: [ + { + id: expect.any(String), + filename: expect.any(String), + data: { + base64: expect.any(String), + }, + }, + ], + thread: { + threadId: expect.any(String), + }, + }) + + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.PresentationReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + }) + + test(`Faber accepts the presentation provided by Alice`, async () => { + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts the presentation provided by Alice + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits until she received a presentation acknowledgement + testLogger.test('Alice waits until she receives a presentation acknowledgement') + aliceProofRecord = await aliceProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: aliceProofRecord.threadId, + connectionId: expect.any(String), + isVerified: true, + state: ProofState.PresentationReceived, + }) + + expect(aliceProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: faberProofRecord.threadId, + connectionId: expect.any(String), + state: ProofState.Done, + }) + }) +}) diff --git a/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-proposal.test.ts b/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-proposal.test.ts new file mode 100644 index 0000000000..8e100bce8a --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-proposal.test.ts @@ -0,0 +1,109 @@ +import type { AgentContext } from '../../../../../agent' +import type { Agent } from '../../../../../agent/Agent' +import type { ConnectionRecord } from '../../../../connections/repository/ConnectionRecord' +import type { ProposeProofOptions } from '../../../ProofsApiOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { PresentationPreview } from '../models/V1PresentationPreview' + +import { getAgentContext, setupProofsTest, waitForProofRecord } from '../../../../../../tests/helpers' +import testLogger from '../../../../../../tests/logger' +import { DidCommMessageRepository } from '../../../../../storage' +import { ProofProtocolVersion } from '../../../models/ProofProtocolVersion' +import { ProofState } from '../../../models/ProofState' +import { V1ProposePresentationMessage } from '../messages' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + let faberProofRecord: ProofRecord + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, aliceConnection, presentationPreview } = await setupProofsTest( + 'Faber agent', + 'Alice agent' + )) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test(`Alice Creates and sends Proof Proposal to Faber`, async () => { + testLogger.test('Alice sends proof proposal to Faber') + + const proposeOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'ProofRequest', + nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + comment: 'V1 propose proof test', + } + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + await aliceAgent.proofs.proposeProof(proposeOptions) + + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/propose-presentation', + id: expect.any(String), + comment: 'V1 propose proof test', + presentationProposal: { + type: 'https://didcomm.org/present-proof/1.0/presentation-preview', + attributes: [ + { + name: 'name', + credentialDefinitionId: presentationPreview.attributes[0].credentialDefinitionId, + value: 'John', + referent: '0', + }, + { + name: 'image_0', + credentialDefinitionId: presentationPreview.attributes[1].credentialDefinitionId, + }, + ], + predicates: [ + { + name: 'age', + credentialDefinitionId: presentationPreview.predicates[0].credentialDefinitionId, + predicate: '>=', + threshold: 50, + }, + ], + }, + }) + + expect(faberProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + }) +}) diff --git a/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-request.test.ts b/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-request.test.ts new file mode 100644 index 0000000000..6b096cd21c --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/__tests__/indy-proof-request.test.ts @@ -0,0 +1,156 @@ +import type { Agent } from '../../../../../agent/Agent' +import type { ConnectionRecord } from '../../../../connections/repository/ConnectionRecord' +import type { ProposeProofOptions, AcceptProposalOptions } from '../../../ProofsApiOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { PresentationPreview } from '../models/V1PresentationPreview' + +import { setupProofsTest, waitForProofRecord } from '../../../../../../tests/helpers' +import testLogger from '../../../../../../tests/logger' +import { DidCommMessageRepository } from '../../../../../storage/didcomm' +import { ProofProtocolVersion } from '../../../models/ProofProtocolVersion' +import { ProofState } from '../../../models/ProofState' +import { V1ProposePresentationMessage, V1RequestPresentationMessage } from '../messages' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + let faberProofRecord: ProofRecord + let aliceProofRecord: ProofRecord + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, aliceConnection, presentationPreview } = await setupProofsTest( + 'Faber agent', + 'Alice agent' + )) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test(`Alice Creates and sends Proof Proposal to Faber`, async () => { + testLogger.test('Alice sends proof proposal to Faber') + + const proposeOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'ProofRequest', + nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + comment: 'V1 propose proof test', + } + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + aliceProofRecord = await aliceAgent.proofs.proposeProof(proposeOptions) + + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/propose-presentation', + id: expect.any(String), + comment: 'V1 propose proof test', + presentationProposal: { + type: 'https://didcomm.org/present-proof/1.0/presentation-preview', + attributes: [ + { + name: 'name', + credentialDefinitionId: presentationPreview.attributes[0].credentialDefinitionId, + value: 'John', + referent: '0', + }, + { + name: 'image_0', + credentialDefinitionId: presentationPreview.attributes[1].credentialDefinitionId, + }, + ], + predicates: [ + { + name: 'age', + credentialDefinitionId: presentationPreview.predicates[0].credentialDefinitionId, + predicate: '>=', + threshold: 50, + }, + ], + }, + }) + expect(faberProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + }) + + test(`Faber accepts the Proposal send by Alice and Creates Proof Request`, async () => { + // Accept Proposal + const acceptProposalOptions: AcceptProposalOptions = { + proofRecordId: faberProofRecord.id, + } + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + }) + + testLogger.test('Faber accepts presentation proposal from Alice') + faberProofRecord = await faberAgent.proofs.acceptProposal(acceptProposalOptions) + + testLogger.test('Alice waits for proof request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/request-presentation', + id: expect.any(String), + requestPresentationAttachments: [ + { + id: 'libindy-request-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(aliceProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + }) +}) diff --git a/packages/core/src/modules/proofs/protocol/v1/errors/V1PresentationProblemReportError.ts b/packages/core/src/modules/proofs/protocol/v1/errors/V1PresentationProblemReportError.ts new file mode 100644 index 0000000000..27c77c0f82 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/errors/V1PresentationProblemReportError.ts @@ -0,0 +1,23 @@ +import type { ProblemReportErrorOptions } from '../../../../problem-reports' +import type { PresentationProblemReportReason } from '../../../errors/PresentationProblemReportReason' + +import { ProblemReportError } from '../../../../problem-reports' +import { V1PresentationProblemReportMessage } from '../messages/V1PresentationProblemReportMessage' + +interface V1PresentationProblemReportErrorOptions extends ProblemReportErrorOptions { + problemCode: PresentationProblemReportReason +} + +export class V1PresentationProblemReportError extends ProblemReportError { + public problemReport: V1PresentationProblemReportMessage + + public constructor(public message: string, { problemCode }: V1PresentationProblemReportErrorOptions) { + super(message, { problemCode }) + this.problemReport = new V1PresentationProblemReportMessage({ + description: { + en: message, + code: problemCode, + }, + }) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/errors/index.ts b/packages/core/src/modules/proofs/protocol/v1/errors/index.ts new file mode 100644 index 0000000000..75d23e13a1 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/errors/index.ts @@ -0,0 +1 @@ +export * from './V1PresentationProblemReportError' diff --git a/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationAckHandler.ts b/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationAckHandler.ts new file mode 100644 index 0000000000..aa0c050c82 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationAckHandler.ts @@ -0,0 +1,17 @@ +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { V1ProofService } from '../V1ProofService' + +import { V1PresentationAckMessage } from '../messages' + +export class V1PresentationAckHandler implements Handler { + private proofService: V1ProofService + public supportedMessages = [V1PresentationAckMessage] + + public constructor(proofService: V1ProofService) { + this.proofService = proofService + } + + public async handle(messageContext: HandlerInboundMessage) { + await this.proofService.processAck(messageContext) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationHandler.ts b/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationHandler.ts new file mode 100644 index 0000000000..9c97a5991d --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationHandler.ts @@ -0,0 +1,72 @@ +import type { AgentConfig } from '../../../../../agent/AgentConfig' +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { DidCommMessageRepository } from '../../../../../storage' +import type { ProofResponseCoordinator } from '../../../ProofResponseCoordinator' +import type { ProofRecord } from '../../../repository' +import type { V1ProofService } from '../V1ProofService' + +import { createOutboundMessage, createOutboundServiceMessage } from '../../../../../agent/helpers' +import { V1PresentationMessage, V1RequestPresentationMessage } from '../messages' + +export class V1PresentationHandler implements Handler { + private proofService: V1ProofService + private agentConfig: AgentConfig + private proofResponseCoordinator: ProofResponseCoordinator + private didCommMessageRepository: DidCommMessageRepository + public supportedMessages = [V1PresentationMessage] + + public constructor( + proofService: V1ProofService, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + didCommMessageRepository: DidCommMessageRepository + ) { + this.proofService = proofService + this.agentConfig = agentConfig + this.proofResponseCoordinator = proofResponseCoordinator + this.didCommMessageRepository = didCommMessageRepository + } + + public async handle(messageContext: HandlerInboundMessage) { + const proofRecord = await this.proofService.processPresentation(messageContext) + + if (this.proofResponseCoordinator.shouldAutoRespondToPresentation(messageContext.agentContext, proofRecord)) { + return await this.createAck(proofRecord, messageContext) + } + } + + private async createAck(record: ProofRecord, messageContext: HandlerInboundMessage) { + this.agentConfig.logger.info( + `Automatically sending acknowledgement with autoAccept on ${this.agentConfig.autoAcceptProofs}` + ) + + const { message, proofRecord } = await this.proofService.createAck(messageContext.agentContext, { + proofRecord: record, + }) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + const presentationMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1PresentationMessage, + }) + + if (messageContext.connection) { + return createOutboundMessage(messageContext.connection, message) + } else if (requestMessage?.service && presentationMessage?.service) { + const recipientService = presentationMessage?.service + const ourService = requestMessage?.service + + return createOutboundServiceMessage({ + payload: message, + service: recipientService.resolvedDidCommService, + senderKey: ourService.resolvedDidCommService.recipientKeys[0], + }) + } + + this.agentConfig.logger.error(`Could not automatically create presentation ack`) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationProblemReportHandler.ts b/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationProblemReportHandler.ts new file mode 100644 index 0000000000..da2af78c18 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/handlers/V1PresentationProblemReportHandler.ts @@ -0,0 +1,17 @@ +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { V1ProofService } from '../V1ProofService' + +import { V1PresentationProblemReportMessage } from '../messages/V1PresentationProblemReportMessage' + +export class V1PresentationProblemReportHandler implements Handler { + private proofService: V1ProofService + public supportedMessages = [V1PresentationProblemReportMessage] + + public constructor(proofService: V1ProofService) { + this.proofService = proofService + } + + public async handle(messageContext: HandlerInboundMessage) { + await this.proofService.processProblemReport(messageContext) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/handlers/V1ProposePresentationHandler.ts b/packages/core/src/modules/proofs/protocol/v1/handlers/V1ProposePresentationHandler.ts new file mode 100644 index 0000000000..19c88f33ab --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/handlers/V1ProposePresentationHandler.ts @@ -0,0 +1,104 @@ +import type { AgentConfig } from '../../../../../agent/AgentConfig' +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { DidCommMessageRepository } from '../../../../../storage/didcomm/DidCommMessageRepository' +import type { ProofResponseCoordinator } from '../../../ProofResponseCoordinator' +import type { IndyProofFormat } from '../../../formats/indy/IndyProofFormat' +import type { IndyProofRequestFromProposalOptions } from '../../../formats/indy/IndyProofFormatsServiceOptions' +import type { ProofRequestFromProposalOptions } from '../../../models/ProofServiceOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { V1ProofService } from '../V1ProofService' + +import { createOutboundMessage } from '../../../../../agent/helpers' +import { AriesFrameworkError } from '../../../../../error' +import { V1ProposePresentationMessage } from '../messages' + +export class V1ProposePresentationHandler implements Handler { + private proofService: V1ProofService + private agentConfig: AgentConfig + private didCommMessageRepository: DidCommMessageRepository + private proofResponseCoordinator: ProofResponseCoordinator + public supportedMessages = [V1ProposePresentationMessage] + + public constructor( + proofService: V1ProofService, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + didCommMessageRepository: DidCommMessageRepository + ) { + this.proofService = proofService + this.agentConfig = agentConfig + this.proofResponseCoordinator = proofResponseCoordinator + this.didCommMessageRepository = didCommMessageRepository + } + + public async handle(messageContext: HandlerInboundMessage) { + const proofRecord = await this.proofService.processProposal(messageContext) + if (this.proofResponseCoordinator.shouldAutoRespondToProposal(messageContext.agentContext, proofRecord)) { + return await this.createRequest(proofRecord, messageContext) + } + } + + private async createRequest( + proofRecord: ProofRecord, + messageContext: HandlerInboundMessage + ) { + 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') + throw new AriesFrameworkError('No connection on the messageContext') + } + + const proposalMessage = await this.didCommMessageRepository.getAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + if (!proposalMessage) { + this.agentConfig.logger.error(`Proof record with id ${proofRecord.id} is missing required credential proposal`) + throw new AriesFrameworkError(`Proof record with id ${proofRecord.id} is missing required credential proposal`) + } + + const proofRequestFromProposalOptions: IndyProofRequestFromProposalOptions = { + name: 'proof-request', + version: '1.0', + nonce: await this.proofService.generateProofRequestNonce(), + proofRecord, + } + + const proofRequest: ProofRequestFromProposalOptions<[IndyProofFormat]> = + await this.proofService.createProofRequestFromProposal( + messageContext.agentContext, + proofRequestFromProposalOptions + ) + + const indyProofRequest = proofRequest.proofFormats + + if (!indyProofRequest || !indyProofRequest.indy) { + this.agentConfig.logger.error(`No Indy proof request was found`) + throw new AriesFrameworkError('No Indy proof request was found') + } + + const { message } = await this.proofService.createRequestAsResponse(messageContext.agentContext, { + proofFormats: { + indy: { + name: indyProofRequest.indy?.name, + version: indyProofRequest.indy?.version, + nonRevoked: indyProofRequest.indy?.nonRevoked, + requestedAttributes: indyProofRequest.indy?.requestedAttributes, + requestedPredicates: indyProofRequest.indy?.requestedPredicates, + ver: indyProofRequest.indy?.ver, + proofRequest: indyProofRequest.indy?.proofRequest, + nonce: indyProofRequest.indy?.nonce, + }, + }, + proofRecord: proofRecord, + autoAcceptProof: proofRecord.autoAcceptProof, + willConfirm: true, + }) + + return createOutboundMessage(messageContext.connection, message) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/handlers/V1RequestPresentationHandler.ts b/packages/core/src/modules/proofs/protocol/v1/handlers/V1RequestPresentationHandler.ts new file mode 100644 index 0000000000..e38f3ba0cb --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/handlers/V1RequestPresentationHandler.ts @@ -0,0 +1,123 @@ +import type { AgentConfig } from '../../../../../agent/AgentConfig' +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { DidCommMessageRepository } from '../../../../../storage/didcomm/DidCommMessageRepository' +import type { MediationRecipientService, RoutingService } from '../../../../routing' +import type { ProofResponseCoordinator } from '../../../ProofResponseCoordinator' +import type { IndyProofFormat } from '../../../formats/indy/IndyProofFormat' +import type { + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, +} from '../../../models/ProofServiceOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { V1ProofService } from '../V1ProofService' + +import { createOutboundMessage, createOutboundServiceMessage } from '../../../../../agent/helpers' +import { ServiceDecorator } from '../../../../../decorators/service/ServiceDecorator' +import { AriesFrameworkError } from '../../../../../error' +import { DidCommMessageRole } from '../../../../../storage' +import { V1RequestPresentationMessage } from '../messages' + +export class V1RequestPresentationHandler implements Handler { + private proofService: V1ProofService + private agentConfig: AgentConfig + private proofResponseCoordinator: ProofResponseCoordinator + private mediationRecipientService: MediationRecipientService + private didCommMessageRepository: DidCommMessageRepository + private routingService: RoutingService + public supportedMessages = [V1RequestPresentationMessage] + + public constructor( + proofService: V1ProofService, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + mediationRecipientService: MediationRecipientService, + didCommMessageRepository: DidCommMessageRepository, + routingService: RoutingService + ) { + this.proofService = proofService + this.agentConfig = agentConfig + this.proofResponseCoordinator = proofResponseCoordinator + this.mediationRecipientService = mediationRecipientService + this.didCommMessageRepository = didCommMessageRepository + this.routingService = routingService + } + + public async handle(messageContext: HandlerInboundMessage) { + const proofRecord = await this.proofService.processRequest(messageContext) + if (this.proofResponseCoordinator.shouldAutoRespondToRequest(messageContext.agentContext, proofRecord)) { + return await this.createPresentation(proofRecord, messageContext) + } + } + + private async createPresentation( + record: ProofRecord, + messageContext: HandlerInboundMessage + ) { + const requestMessage = await this.didCommMessageRepository.getAgentMessage(messageContext.agentContext, { + associatedRecordId: record.id, + messageClass: V1RequestPresentationMessage, + }) + + const indyProofRequest = requestMessage.indyProofRequest + + this.agentConfig.logger.info( + `Automatically sending presentation with autoAccept on ${this.agentConfig.autoAcceptProofs}` + ) + + if (!indyProofRequest) { + this.agentConfig.logger.error('Proof request is undefined.') + throw new AriesFrameworkError('No proof request found.') + } + + const retrievedCredentials: FormatRetrievedCredentialOptions<[IndyProofFormat]> = + await this.proofService.getRequestedCredentialsForProofRequest(messageContext.agentContext, { + proofRecord: record, + config: { + filterByPresentationPreview: true, + }, + }) + if (!retrievedCredentials.proofFormats.indy) { + this.agentConfig.logger.error('No matching Indy credentials could be retrieved.') + throw new AriesFrameworkError('No matching Indy credentials could be retrieved.') + } + + const options: FormatRetrievedCredentialOptions<[IndyProofFormat]> = { + proofFormats: retrievedCredentials.proofFormats, + } + const requestedCredentials: FormatRequestedCredentialReturn<[IndyProofFormat]> = + await this.proofService.autoSelectCredentialsForProofRequest(options) + + const { message, proofRecord } = await this.proofService.createPresentation(messageContext.agentContext, { + proofRecord: record, + proofFormats: { + indy: requestedCredentials.proofFormats.indy, + }, + willConfirm: true, + }) + + if (messageContext.connection) { + return createOutboundMessage(messageContext.connection, message) + } else if (requestMessage.service) { + const routing = await this.routingService.getRouting(messageContext.agentContext) + message.service = new ServiceDecorator({ + serviceEndpoint: routing.endpoints[0], + recipientKeys: [routing.recipientKey.publicKeyBase58], + routingKeys: routing.routingKeys.map((key) => key.publicKeyBase58), + }) + const recipientService = requestMessage.service + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: message, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + return createOutboundServiceMessage({ + payload: message, + service: recipientService.resolvedDidCommService, + senderKey: message.service.resolvedDidCommService.recipientKeys[0], + }) + } + + this.agentConfig.logger.error(`Could not automatically create presentation`) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v1/handlers/index.ts b/packages/core/src/modules/proofs/protocol/v1/handlers/index.ts new file mode 100644 index 0000000000..c202042b9b --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/handlers/index.ts @@ -0,0 +1,5 @@ +export * from './V1PresentationAckHandler' +export * from './V1PresentationHandler' +export * from './V1ProposePresentationHandler' +export * from './V1RequestPresentationHandler' +export * from './V1PresentationProblemReportHandler' diff --git a/packages/core/src/modules/proofs/protocol/v1/index.ts b/packages/core/src/modules/proofs/protocol/v1/index.ts new file mode 100644 index 0000000000..1b43254564 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/index.ts @@ -0,0 +1 @@ +export * from './V1ProofService' diff --git a/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationAckMessage.ts b/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationAckMessage.ts new file mode 100644 index 0000000000..29f12a8dd9 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationAckMessage.ts @@ -0,0 +1,14 @@ +import type { AckMessageOptions } from '../../../../common' + +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { AckMessage } from '../../../../common' + +export class V1PresentationAckMessage extends AckMessage { + public constructor(options: AckMessageOptions) { + super(options) + } + + @IsValidMessageType(V1PresentationAckMessage.type) + public readonly type = V1PresentationAckMessage.type.messageTypeUri + public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/ack') +} diff --git a/packages/core/src/modules/proofs/messages/PresentationMessage.ts b/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationMessage.ts similarity index 57% rename from packages/core/src/modules/proofs/messages/PresentationMessage.ts rename to packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationMessage.ts index 72d68cbdcc..d66360d0e5 100644 --- a/packages/core/src/modules/proofs/messages/PresentationMessage.ts +++ b/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationMessage.ts @@ -1,11 +1,15 @@ +import type { ProofAttachmentFormat } from '../../../formats/models/ProofAttachmentFormat' import type { IndyProof } from 'indy-sdk' import { Expose, Type } from 'class-transformer' import { IsArray, IsString, ValidateNested, IsOptional, IsInstance } from 'class-validator' -import { AgentMessage } from '../../../agent/AgentMessage' -import { Attachment } from '../../../decorators/attachment/Attachment' -import { IsValidMessageType, parseMessageType } from '../../../utils/messageType' +import { AgentMessage } from '../../../../../agent/AgentMessage' +import { Attachment } from '../../../../../decorators/attachment/Attachment' +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { V2_INDY_PRESENTATION } from '../../../formats/ProofFormatConstants' +import { ProofFormatSpec } from '../../../models/ProofFormatSpec' export const INDY_PROOF_ATTACHMENT_ID = 'libindy-presentation-0' @@ -22,7 +26,7 @@ export interface PresentationOptions { * * @see https://github.com/hyperledger/aries-rfcs/blob/master/features/0037-present-proof/README.md#presentation */ -export class PresentationMessage extends AgentMessage { +export class V1PresentationMessage extends AgentMessage { public constructor(options: PresentationOptions) { super() @@ -34,8 +38,8 @@ export class PresentationMessage extends AgentMessage { } } - @IsValidMessageType(PresentationMessage.type) - public readonly type = PresentationMessage.type.messageTypeUri + @IsValidMessageType(V1PresentationMessage.type) + public readonly type = V1PresentationMessage.type.messageTypeUri public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/presentation') /** @@ -57,8 +61,27 @@ export class PresentationMessage extends AgentMessage { @IsInstance(Attachment, { each: true }) public presentationAttachments!: Attachment[] + public getAttachmentFormats(): ProofAttachmentFormat[] { + const attachment = this.indyAttachment + + if (!attachment) { + throw new AriesFrameworkError(`Could not find a presentation attachment`) + } + + return [ + { + format: new ProofFormatSpec({ format: V2_INDY_PRESENTATION }), + attachment: attachment, + }, + ] + } + + public get indyAttachment(): Attachment | null { + return this.presentationAttachments.find((attachment) => attachment.id === INDY_PROOF_ATTACHMENT_ID) ?? null + } + public get indyProof(): IndyProof | null { - const attachment = this.presentationAttachments.find((attachment) => attachment.id === INDY_PROOF_ATTACHMENT_ID) + const attachment = this.indyAttachment const proofJson = attachment?.getDataAsJson() ?? null diff --git a/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationProblemReportMessage.ts b/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationProblemReportMessage.ts new file mode 100644 index 0000000000..87901ce6a8 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/messages/V1PresentationProblemReportMessage.ts @@ -0,0 +1,23 @@ +import type { ProblemReportMessageOptions } from '../../../../problem-reports/messages/ProblemReportMessage' + +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { ProblemReportMessage } from '../../../../problem-reports/messages/ProblemReportMessage' + +export type V1PresentationProblemReportMessageOptions = ProblemReportMessageOptions + +/** + * @see https://github.com/hyperledger/aries-rfcs/blob/main/features/0035-report-problem/README.md + */ +export class V1PresentationProblemReportMessage extends ProblemReportMessage { + /** + * Create new PresentationProblemReportMessage instance. + * @param options description of error and multiple optional fields for reporting problem + */ + public constructor(options: V1PresentationProblemReportMessageOptions) { + super(options) + } + + @IsValidMessageType(V1PresentationProblemReportMessage.type) + public readonly type = V1PresentationProblemReportMessage.type.messageTypeUri + public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/problem-report') +} diff --git a/packages/core/src/modules/proofs/messages/ProposePresentationMessage.ts b/packages/core/src/modules/proofs/protocol/v1/messages/V1ProposePresentationMessage.ts similarity index 75% rename from packages/core/src/modules/proofs/messages/ProposePresentationMessage.ts rename to packages/core/src/modules/proofs/protocol/v1/messages/V1ProposePresentationMessage.ts index 409b1cfe23..d6392f5d61 100644 --- a/packages/core/src/modules/proofs/messages/ProposePresentationMessage.ts +++ b/packages/core/src/modules/proofs/protocol/v1/messages/V1ProposePresentationMessage.ts @@ -1,10 +1,9 @@ import { Expose, Type } from 'class-transformer' import { IsInstance, IsOptional, IsString, ValidateNested } from 'class-validator' -import { AgentMessage } from '../../../agent/AgentMessage' -import { IsValidMessageType, parseMessageType } from '../../../utils/messageType' - -import { PresentationPreview } from './PresentationPreview' +import { AgentMessage } from '../../../../../agent/AgentMessage' +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { PresentationPreview } from '../models/V1PresentationPreview' export interface ProposePresentationMessageOptions { id?: string @@ -17,7 +16,7 @@ export interface ProposePresentationMessageOptions { * * @see https://github.com/hyperledger/aries-rfcs/blob/master/features/0037-present-proof/README.md#propose-presentation */ -export class ProposePresentationMessage extends AgentMessage { +export class V1ProposePresentationMessage extends AgentMessage { public constructor(options: ProposePresentationMessageOptions) { super() @@ -28,8 +27,8 @@ export class ProposePresentationMessage extends AgentMessage { } } - @IsValidMessageType(ProposePresentationMessage.type) - public readonly type = ProposePresentationMessage.type.messageTypeUri + @IsValidMessageType(V1ProposePresentationMessage.type) + public readonly type = V1ProposePresentationMessage.type.messageTypeUri public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/propose-presentation') /** diff --git a/packages/core/src/modules/proofs/messages/RequestPresentationMessage.ts b/packages/core/src/modules/proofs/protocol/v1/messages/V1RequestPresentationMessage.ts similarity index 56% rename from packages/core/src/modules/proofs/messages/RequestPresentationMessage.ts rename to packages/core/src/modules/proofs/protocol/v1/messages/V1RequestPresentationMessage.ts index e03b4f2fa4..cf69dfbaee 100644 --- a/packages/core/src/modules/proofs/messages/RequestPresentationMessage.ts +++ b/packages/core/src/modules/proofs/protocol/v1/messages/V1RequestPresentationMessage.ts @@ -1,11 +1,16 @@ +import type { ProofAttachmentFormat } from '../../../formats/models/ProofAttachmentFormat' + import { Expose, Type } from 'class-transformer' import { IsArray, IsString, ValidateNested, IsOptional, IsInstance } from 'class-validator' -import { AgentMessage } from '../../../agent/AgentMessage' -import { Attachment } from '../../../decorators/attachment/Attachment' -import { JsonTransformer } from '../../../utils/JsonTransformer' -import { IsValidMessageType, parseMessageType } from '../../../utils/messageType' -import { ProofRequest } from '../models' +import { AgentMessage } from '../../../../../agent/AgentMessage' +import { Attachment } from '../../../../../decorators/attachment/Attachment' +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' +import { JsonTransformer } from '../../../../../utils/JsonTransformer' +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { V2_INDY_PRESENTATION_REQUEST } from '../../../formats/ProofFormatConstants' +import { ProofRequest } from '../../../formats/indy/models/ProofRequest' +import { ProofFormatSpec } from '../../../models/ProofFormatSpec' export interface RequestPresentationOptions { id?: string @@ -20,7 +25,7 @@ export const INDY_PROOF_REQUEST_ATTACHMENT_ID = 'libindy-request-presentation-0' * * @see https://github.com/hyperledger/aries-rfcs/blob/master/features/0037-present-proof/README.md#request-presentation */ -export class RequestPresentationMessage extends AgentMessage { +export class V1RequestPresentationMessage extends AgentMessage { public constructor(options: RequestPresentationOptions) { super() @@ -31,8 +36,8 @@ export class RequestPresentationMessage extends AgentMessage { } } - @IsValidMessageType(RequestPresentationMessage.type) - public readonly type = RequestPresentationMessage.type.messageTypeUri + @IsValidMessageType(V1RequestPresentationMessage.type) + public readonly type = V1RequestPresentationMessage.type.messageTypeUri public static readonly type = parseMessageType('https://didcomm.org/present-proof/1.0/request-presentation') /** @@ -64,4 +69,26 @@ export class RequestPresentationMessage extends AgentMessage { return proofRequest } + + public getAttachmentFormats(): ProofAttachmentFormat[] { + const attachment = this.indyAttachment + + if (!attachment) { + throw new AriesFrameworkError(`Could not find a request presentation attachment`) + } + + return [ + { + format: new ProofFormatSpec({ format: V2_INDY_PRESENTATION_REQUEST }), + attachment: attachment, + }, + ] + } + + public get indyAttachment(): Attachment | null { + return ( + this.requestPresentationAttachments.find((attachment) => attachment.id === INDY_PROOF_REQUEST_ATTACHMENT_ID) ?? + null + ) + } } diff --git a/packages/core/src/modules/proofs/protocol/v1/messages/index.ts b/packages/core/src/modules/proofs/protocol/v1/messages/index.ts new file mode 100644 index 0000000000..01d16d4e87 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/messages/index.ts @@ -0,0 +1,4 @@ +export * from './V1ProposePresentationMessage' +export * from './V1RequestPresentationMessage' +export * from './V1PresentationMessage' +export * from './V1PresentationAckMessage' diff --git a/packages/core/src/modules/proofs/models/PartialProof.ts b/packages/core/src/modules/proofs/protocol/v1/models/PartialProof.ts similarity index 100% rename from packages/core/src/modules/proofs/models/PartialProof.ts rename to packages/core/src/modules/proofs/protocol/v1/models/PartialProof.ts diff --git a/packages/core/src/modules/proofs/models/ProofAttribute.ts b/packages/core/src/modules/proofs/protocol/v1/models/ProofAttribute.ts similarity index 100% rename from packages/core/src/modules/proofs/models/ProofAttribute.ts rename to packages/core/src/modules/proofs/protocol/v1/models/ProofAttribute.ts diff --git a/packages/core/src/modules/proofs/models/ProofIdentifier.ts b/packages/core/src/modules/proofs/protocol/v1/models/ProofIdentifier.ts similarity index 92% rename from packages/core/src/modules/proofs/models/ProofIdentifier.ts rename to packages/core/src/modules/proofs/protocol/v1/models/ProofIdentifier.ts index 66f337e8b2..241ac74aaa 100644 --- a/packages/core/src/modules/proofs/models/ProofIdentifier.ts +++ b/packages/core/src/modules/proofs/protocol/v1/models/ProofIdentifier.ts @@ -1,7 +1,7 @@ import { Expose } from 'class-transformer' import { IsNumber, IsOptional, IsString, Matches } from 'class-validator' -import { credDefIdRegex } from '../../../utils' +import { credDefIdRegex } from '../../../../../utils/regex' export class ProofIdentifier { public constructor(options: ProofIdentifier) { diff --git a/packages/core/src/modules/proofs/models/RequestedProof.ts b/packages/core/src/modules/proofs/protocol/v1/models/RequestedProof.ts similarity index 100% rename from packages/core/src/modules/proofs/models/RequestedProof.ts rename to packages/core/src/modules/proofs/protocol/v1/models/RequestedProof.ts diff --git a/packages/core/src/modules/proofs/messages/PresentationPreview.ts b/packages/core/src/modules/proofs/protocol/v1/models/V1PresentationPreview.ts similarity index 93% rename from packages/core/src/modules/proofs/messages/PresentationPreview.ts rename to packages/core/src/modules/proofs/protocol/v1/models/V1PresentationPreview.ts index c309aaee85..2ac71e903e 100644 --- a/packages/core/src/modules/proofs/messages/PresentationPreview.ts +++ b/packages/core/src/modules/proofs/protocol/v1/models/V1PresentationPreview.ts @@ -11,10 +11,10 @@ import { ValidateNested, } from 'class-validator' -import { credDefIdRegex } from '../../../utils' -import { JsonTransformer } from '../../../utils/JsonTransformer' -import { IsValidMessageType, parseMessageType, replaceLegacyDidSovPrefix } from '../../../utils/messageType' -import { PredicateType } from '../models/PredicateType' +import { credDefIdRegex } from '../../../../../utils' +import { JsonTransformer } from '../../../../../utils/JsonTransformer' +import { IsValidMessageType, parseMessageType, replaceLegacyDidSovPrefix } from '../../../../../utils/messageType' +import { PredicateType } from '../../../formats/indy/models/PredicateType' export interface PresentationPreviewAttributeOptions { name: string diff --git a/packages/core/src/modules/proofs/protocol/v1/models/index.ts b/packages/core/src/modules/proofs/protocol/v1/models/index.ts new file mode 100644 index 0000000000..f9d9b12a47 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v1/models/index.ts @@ -0,0 +1,4 @@ +export * from './PartialProof' +export * from './ProofAttribute' +export * from './ProofIdentifier' +export * from './RequestedProof' diff --git a/packages/core/src/modules/proofs/protocol/v2/V2ProofService.ts b/packages/core/src/modules/proofs/protocol/v2/V2ProofService.ts new file mode 100644 index 0000000000..c49892447f --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/V2ProofService.ts @@ -0,0 +1,856 @@ +import type { AgentContext } from '../../../../agent' +import type { AgentMessage } from '../../../../agent/AgentMessage' +import type { Dispatcher } from '../../../../agent/Dispatcher' +import type { InboundMessageContext } from '../../../../agent/models/InboundMessageContext' +import type { MediationRecipientService } from '../../../routing/services/MediationRecipientService' +import type { RoutingService } from '../../../routing/services/RoutingService' +import type { ProofResponseCoordinator } from '../../ProofResponseCoordinator' +import type { ProofFormat } from '../../formats/ProofFormat' +import type { ProofFormatService } from '../../formats/ProofFormatService' +import type { CreateProblemReportOptions } from '../../formats/models/ProofFormatServiceOptions' +import type { ProofFormatSpec } from '../../models/ProofFormatSpec' +import type { + CreateAckOptions, + CreatePresentationOptions, + CreateProofRequestFromProposalOptions, + CreateProposalAsResponseOptions, + CreateProposalOptions, + CreateRequestAsResponseOptions, + CreateRequestOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, + GetRequestedCredentialsForProofRequestOptions, + ProofRequestFromProposalOptions, +} from '../../models/ProofServiceOptions' + +import { inject, Lifecycle, scoped } from 'tsyringe' + +import { AgentConfig } from '../../../../agent/AgentConfig' +import { EventEmitter } from '../../../../agent/EventEmitter' +import { InjectionSymbols } from '../../../../constants' +import { AriesFrameworkError } from '../../../../error' +import { DidCommMessageRepository, DidCommMessageRole } from '../../../../storage' +import { MessageValidator } from '../../../../utils/MessageValidator' +import { Wallet } from '../../../../wallet/Wallet' +import { AckStatus } from '../../../common' +import { ConnectionService } from '../../../connections' +import { ProofService } from '../../ProofService' +import { PresentationProblemReportReason } from '../../errors/PresentationProblemReportReason' +import { V2_INDY_PRESENTATION_REQUEST } from '../../formats/ProofFormatConstants' +import { IndyProofFormatService } from '../../formats/indy/IndyProofFormatService' +import { IndyProofUtils } from '../../formats/indy/IndyProofUtils' +import { ProofProtocolVersion } from '../../models/ProofProtocolVersion' +import { ProofState } from '../../models/ProofState' +import { PresentationRecordType, ProofRecord, ProofRepository } from '../../repository' + +import { V2PresentationProblemReportError } from './errors' +import { V2PresentationAckHandler } from './handlers/V2PresentationAckHandler' +import { V2PresentationHandler } from './handlers/V2PresentationHandler' +import { V2PresentationProblemReportHandler } from './handlers/V2PresentationProblemReportHandler' +import { V2ProposePresentationHandler } from './handlers/V2ProposePresentationHandler' +import { V2RequestPresentationHandler } from './handlers/V2RequestPresentationHandler' +import { V2PresentationAckMessage } from './messages' +import { V2PresentationMessage } from './messages/V2PresentationMessage' +import { V2PresentationProblemReportMessage } from './messages/V2PresentationProblemReportMessage' +import { V2ProposalPresentationMessage } from './messages/V2ProposalPresentationMessage' +import { V2RequestPresentationMessage } from './messages/V2RequestPresentationMessage' + +@scoped(Lifecycle.ContainerScoped) +// export class V2ProofService extends ProofService { +export class V2ProofService extends ProofService { + private formatServiceMap: { [key: string]: ProofFormatService } + + public constructor( + agentConfig: AgentConfig, + connectionService: ConnectionService, + proofRepository: ProofRepository, + didCommMessageRepository: DidCommMessageRepository, + eventEmitter: EventEmitter, + indyProofFormatService: IndyProofFormatService, + @inject(InjectionSymbols.Wallet) wallet: Wallet + ) { + super(agentConfig, proofRepository, connectionService, didCommMessageRepository, wallet, eventEmitter) + this.wallet = wallet + this.formatServiceMap = { + [PresentationRecordType.Indy]: indyProofFormatService, + // other format services to be added to the map + } + } + + /** + * The version of the issue credential protocol this service supports + */ + public readonly version = 'v2' as const + + public async createProposal( + agentContext: AgentContext, + options: CreateProposalOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const formats = [] + for (const key of Object.keys(options.proofFormats)) { + const service = this.formatServiceMap[key] + formats.push( + await service.createProposal({ + formats: + key === PresentationRecordType.Indy + ? await IndyProofUtils.createRequestFromPreview(options) + : options.proofFormats, + }) + ) + } + + const proposalMessage = new V2ProposalPresentationMessage({ + attachmentInfo: formats, + comment: options.comment, + willConfirm: options.willConfirm, + goalCode: options.goalCode, + }) + + const proofRecord = new ProofRecord({ + connectionId: options.connectionRecord.id, + threadId: proposalMessage.threadId, + state: ProofState.ProposalSent, + protocolVersion: ProofProtocolVersion.V2, + }) + + await this.proofRepository.save(agentContext, proofRecord) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: proposalMessage, + role: DidCommMessageRole.Sender, + associatedRecordId: proofRecord.id, + }) + + this.emitStateChangedEvent(agentContext, proofRecord, null) + + return { + proofRecord: proofRecord, + message: proposalMessage, + } + } + + public async createProposalAsResponse( + agentContext: AgentContext, + options: CreateProposalAsResponseOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + options.proofRecord.assertState(ProofState.RequestReceived) + + const formats = [] + for (const key of Object.keys(options.proofFormats)) { + const service = this.formatServiceMap[key] + formats.push( + await service.createProposal({ + formats: options.proofFormats, + }) + ) + } + + const proposalMessage = new V2ProposalPresentationMessage({ + attachmentInfo: formats, + comment: options.comment, + goalCode: options.goalCode, + willConfirm: options.willConfirm, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: proposalMessage, + role: DidCommMessageRole.Sender, + associatedRecordId: options.proofRecord.id, + }) + + await this.updateState(agentContext, options.proofRecord, ProofState.ProposalSent) + + return { message: proposalMessage, proofRecord: options.proofRecord } + } + + public async processProposal( + messageContext: InboundMessageContext + ): Promise { + const { message: proposalMessage, connection: connectionRecord } = messageContext + let proofRecord: ProofRecord + + const proposalAttachments = proposalMessage.getAttachmentFormats() + + for (const attachmentFormat of proposalAttachments) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + await service?.processProposal({ + proposal: attachmentFormat, + }) + } + + try { + proofRecord = await this.proofRepository.getSingleByQuery(messageContext.agentContext, { + threadId: proposalMessage.threadId, + connectionId: connectionRecord?.id, + }) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.RequestSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: proposalMessage, + previousSentMessage: requestMessage ?? undefined, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proposalMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + await this.updateState(messageContext.agentContext, proofRecord, ProofState.ProposalReceived) + } catch { + // No proof record exists with thread id + proofRecord = new ProofRecord({ + connectionId: connectionRecord?.id, + threadId: proposalMessage.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + // Assert + this.connectionService.assertConnectionOrServiceDecorator(messageContext) + + // Save record + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proposalMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + await this.proofRepository.save(messageContext.agentContext, proofRecord) + this.emitStateChangedEvent(messageContext.agentContext, proofRecord, null) + } + + return proofRecord + } + + public async createRequest( + agentContext: AgentContext, + options: CreateRequestOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + // create attachment formats + const formats = [] + for (const key of Object.keys(options.proofFormats)) { + const service = this.formatServiceMap[key] + formats.push( + await service.createRequest({ + formats: options.proofFormats, + }) + ) + } + + // create request message + const requestMessage = new V2RequestPresentationMessage({ + attachmentInfo: formats, + comment: options.comment, + willConfirm: options.willConfirm, + goalCode: options.goalCode, + }) + + // create & store proof record + const proofRecord = new ProofRecord({ + connectionId: options.connectionRecord?.id, + threadId: requestMessage.threadId, + state: ProofState.RequestSent, + protocolVersion: ProofProtocolVersion.V2, + }) + + await this.proofRepository.save(agentContext, proofRecord) + + // create DIDComm message + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: requestMessage, + role: DidCommMessageRole.Sender, + associatedRecordId: proofRecord.id, + }) + + this.emitStateChangedEvent(agentContext, proofRecord, null) + + return { + proofRecord: proofRecord, + message: requestMessage, + } + } + + public async createRequestAsResponse( + agentContext: AgentContext, + options: CreateRequestAsResponseOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + options.proofRecord.assertState(ProofState.ProposalReceived) + + const proposal = await this.didCommMessageRepository.getAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + if (!proposal) { + throw new AriesFrameworkError( + `Proof record with id ${options.proofRecord.id} is missing required presentation proposal` + ) + } + + // create attachment formats + const formats = [] + + for (const key of Object.keys(options.proofFormats)) { + const service = this.formatServiceMap[key] + const requestOptions: CreateRequestAsResponseOptions = { + proofFormats: options.proofFormats, + proofRecord: options.proofRecord, + } + formats.push(await service.createRequestAsResponse(requestOptions)) + } + + // create request message + const requestMessage = new V2RequestPresentationMessage({ + attachmentInfo: formats, + comment: options.comment, + willConfirm: options.willConfirm, + goalCode: options.goalCode, + }) + requestMessage.setThread({ threadId: options.proofRecord.threadId }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: requestMessage, + role: DidCommMessageRole.Sender, + associatedRecordId: options.proofRecord.id, + }) + + await this.updateState(agentContext, options.proofRecord, ProofState.RequestSent) + + return { message: requestMessage, proofRecord: options.proofRecord } + } + + public async processRequest( + messageContext: InboundMessageContext + ): Promise { + const { message: proofRequestMessage, connection: connectionRecord } = messageContext + + const requestAttachments = proofRequestMessage.getAttachmentFormats() + + for (const attachmentFormat of requestAttachments) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + service?.processRequest({ + requestAttachment: attachmentFormat, + }) + } + + // assert + if (proofRequestMessage.requestPresentationsAttach.length === 0) { + throw new V2PresentationProblemReportError( + `Missing required base64 or json encoded attachment data for presentation request with thread id ${proofRequestMessage.threadId}`, + { problemCode: PresentationProblemReportReason.Abandoned } + ) + } + + this.logger.debug(`Received proof request`, proofRequestMessage) + + let proofRecord: ProofRecord + + try { + proofRecord = await this.proofRepository.getSingleByQuery(messageContext.agentContext, { + threadId: proofRequestMessage.threadId, + connectionId: connectionRecord?.id, + }) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.ProposalSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: requestMessage ?? undefined, + previousSentMessage: proposalMessage ?? undefined, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proofRequestMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Update record + await this.updateState(messageContext.agentContext, proofRecord, ProofState.RequestReceived) + } catch { + // No proof record exists with thread id + proofRecord = new ProofRecord({ + connectionId: connectionRecord?.id, + threadId: proofRequestMessage.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: proofRequestMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Assert + this.connectionService.assertConnectionOrServiceDecorator(messageContext) + + // Save in repository + await this.proofRepository.save(messageContext.agentContext, proofRecord) + this.emitStateChangedEvent(messageContext.agentContext, proofRecord, null) + } + + return proofRecord + } + + public async createPresentation( + agentContext: AgentContext, + options: CreatePresentationOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + // assert state + options.proofRecord.assertState(ProofState.RequestReceived) + + const proofRequest = await this.didCommMessageRepository.getAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + const formats = [] + for (const key of Object.keys(options.proofFormats)) { + const service = this.formatServiceMap[key] + formats.push( + await service.createPresentation(agentContext, { + attachment: proofRequest.getAttachmentByFormatIdentifier(V2_INDY_PRESENTATION_REQUEST), + proofFormats: options.proofFormats, + }) + ) + } + + const presentationMessage = new V2PresentationMessage({ + comment: options.comment, + attachmentInfo: formats, + goalCode: options.goalCode, + lastPresentation: options.lastPresentation, + }) + presentationMessage.setThread({ threadId: options.proofRecord.threadId }) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(agentContext, { + agentMessage: presentationMessage, + associatedRecordId: options.proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + await this.updateState(agentContext, options.proofRecord, ProofState.PresentationSent) + + return { message: presentationMessage, proofRecord: options.proofRecord } + } + + public async processPresentation(messageContext: InboundMessageContext): Promise { + const { message: presentationMessage, connection: connectionRecord } = messageContext + + this.logger.debug(`Processing presentation with id ${presentationMessage.id}`) + + const proofRecord = await this.proofRepository.getSingleByQuery(messageContext.agentContext, { + threadId: presentationMessage.threadId, + connectionId: connectionRecord?.id, + }) + + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + const requestMessage = await this.didCommMessageRepository.getAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.RequestSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: proposalMessage ?? undefined, + previousSentMessage: requestMessage ?? undefined, + }) + + const formatVerificationResults = [] + for (const attachmentFormat of presentationMessage.getAttachmentFormats()) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + if (service) { + try { + formatVerificationResults.push( + await service.processPresentation(messageContext.agentContext, { + record: proofRecord, + formatAttachments: { + request: requestMessage?.getAttachmentFormats(), + presentation: presentationMessage.getAttachmentFormats(), + }, + }) + ) + } catch (e) { + if (e instanceof AriesFrameworkError) { + throw new V2PresentationProblemReportError(e.message, { + problemCode: PresentationProblemReportReason.Abandoned, + }) + } + throw e + } + } + } + if (formatVerificationResults.length === 0) { + throw new V2PresentationProblemReportError('None of the received formats are supported.', { + problemCode: PresentationProblemReportReason.Abandoned, + }) + } + + const isValid = formatVerificationResults.every((x) => x === true) + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: presentationMessage, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Receiver, + }) + + // Update record + proofRecord.isVerified = isValid + await this.updateState(messageContext.agentContext, proofRecord, ProofState.PresentationReceived) + + return proofRecord + } + + public async createAck( + agentContext: AgentContext, + options: CreateAckOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + // assert we've received the final presentation + const presentation = await this.didCommMessageRepository.getAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + messageClass: V2PresentationMessage, + }) + + if (!presentation.lastPresentation) { + throw new AriesFrameworkError( + `Trying to send an ack message while presentation with id ${presentation.id} indicates this is not the last presentation (presentation.lastPresentation is set to false)` + ) + } + + const msg = new V2PresentationAckMessage({ + threadId: options.proofRecord.threadId, + status: AckStatus.OK, + }) + + await this.updateState(agentContext, options.proofRecord, ProofState.Done) + + return { + message: msg, + proofRecord: options.proofRecord, + } + } + + public async processAck(messageContext: InboundMessageContext): Promise { + const { message: ackMessage, connection: connectionRecord } = messageContext + + const proofRecord = await this.proofRepository.getSingleByQuery(messageContext.agentContext, { + threadId: ackMessage.threadId, + connectionId: connectionRecord?.id, + }) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + const presentationMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2PresentationMessage, + }) + + // Assert + proofRecord.assertState(ProofState.PresentationSent) + this.connectionService.assertConnectionOrServiceDecorator(messageContext, { + previousReceivedMessage: requestMessage ?? undefined, + previousSentMessage: presentationMessage ?? undefined, + }) + + // Update record + await this.updateState(messageContext.agentContext, proofRecord, ProofState.Done) + + return proofRecord + } + + public async createProblemReport( + agentContext: AgentContext, + options: CreateProblemReportOptions + ): Promise<{ proofRecord: ProofRecord; message: AgentMessage }> { + const msg = new V2PresentationProblemReportMessage({ + description: { + code: PresentationProblemReportReason.Abandoned, + en: options.description, + }, + }) + + msg.setThread({ + threadId: options.proofRecord.threadId, + }) + + return { + proofRecord: options.proofRecord, + message: msg, + } + } + + public async processProblemReport( + messageContext: InboundMessageContext + ): Promise { + const { message: presentationProblemReportMessage } = messageContext + + const connectionRecord = messageContext.assertReadyConnection() + + this.logger.debug(`Processing problem report with id ${presentationProblemReportMessage.id}`) + + const proofRecord = await this.proofRepository.getSingleByQuery(messageContext.agentContext, { + threadId: presentationProblemReportMessage.threadId, + connectionId: connectionRecord?.id, + }) + + proofRecord.errorMessage = `${presentationProblemReportMessage.description.code}: ${presentationProblemReportMessage.description.en}` + await this.updateState(messageContext.agentContext, proofRecord, ProofState.Abandoned) + return proofRecord + } + + public async createProofRequestFromProposal( + agentContext: AgentContext, + options: CreateProofRequestFromProposalOptions + ): Promise> { + const proofRecordId = options.proofRecord.id + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V2ProposalPresentationMessage, + }) + + if (!proposalMessage) { + throw new AriesFrameworkError(`Proof record with id ${proofRecordId} is missing required presentation proposal`) + } + + const proposalAttachments = proposalMessage.getAttachmentFormats() + + let result = {} + + for (const attachmentFormat of proposalAttachments) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + + if (!service) { + throw new AriesFrameworkError('No format service found for getting requested.') + } + + result = { + ...result, + ...(await service.createProofRequestFromProposal({ + presentationAttachment: attachmentFormat.attachment, + })), + } + } + + const retVal: ProofRequestFromProposalOptions = { + proofRecord: options.proofRecord, + proofFormats: result, + } + return retVal + } + + public async shouldAutoRespondToProposal(agentContext: AgentContext, proofRecord: ProofRecord): Promise { + const proposal = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + if (!proposal) { + return false + } + const request = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + if (!request) { + return true + } + await MessageValidator.validateSync(proposal) + + const proposalAttachments = proposal.getAttachmentFormats() + const requestAttachments = request.getAttachmentFormats() + + const equalityResults = [] + for (const attachmentFormat of proposalAttachments) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + equalityResults.push(service?.proposalAndRequestAreEqual(proposalAttachments, requestAttachments)) + } + return true + } + + public async shouldAutoRespondToRequest(agentContext: AgentContext, proofRecord: ProofRecord): Promise { + const proposal = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + if (!proposal) { + return false + } + + const request = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + if (!request) { + throw new AriesFrameworkError(`Expected to find a request message for ProofRecord with id ${proofRecord.id}`) + } + + const proposalAttachments = proposal.getAttachmentFormats() + const requestAttachments = request.getAttachmentFormats() + + const equalityResults = [] + for (const attachmentFormat of proposalAttachments) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + equalityResults.push(service?.proposalAndRequestAreEqual(proposalAttachments, requestAttachments)) + } + + return equalityResults.every((x) => x === true) + } + + public async shouldAutoRespondToPresentation(agentContext: AgentContext, proofRecord: ProofRecord): Promise { + const request = await this.didCommMessageRepository.getAgentMessage(agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + return request.willConfirm + } + + public async findRequestMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise { + return await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V2RequestPresentationMessage, + }) + } + + public async findPresentationMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise { + return await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V2PresentationMessage, + }) + } + + public async findProposalMessage( + agentContext: AgentContext, + proofRecordId: string + ): Promise { + return await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: proofRecordId, + messageClass: V2ProposalPresentationMessage, + }) + } + + public async getRequestedCredentialsForProofRequest( + agentContext: AgentContext, + options: GetRequestedCredentialsForProofRequestOptions + ): Promise> { + const requestMessage = await this.didCommMessageRepository.findAgentMessage(agentContext, { + associatedRecordId: options.proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + if (!requestMessage) { + throw new AriesFrameworkError('No proof request found.') + } + + const requestAttachments = requestMessage.getAttachmentFormats() + + let result = { + proofFormats: {}, + } + for (const attachmentFormat of requestAttachments) { + const service = this.getFormatServiceForFormat(attachmentFormat.format) + + if (!service) { + throw new AriesFrameworkError('No format service found for getting requested.') + } + + result = { + ...result, + ...(await service.getRequestedCredentialsForProofRequest(agentContext, { + attachment: attachmentFormat.attachment, + presentationProposal: undefined, + config: options.config, + })), + } + } + + return result + } + + public async autoSelectCredentialsForProofRequest( + options: FormatRetrievedCredentialOptions + ): Promise> { + let returnValue = { + proofFormats: {}, + } + + for (const [id] of Object.entries(options.proofFormats)) { + const service = this.formatServiceMap[id] + const credentials = await service.autoSelectCredentialsForProofRequest(options) + returnValue = { ...returnValue, ...credentials } + } + + return returnValue + } + + public registerHandlers( + dispatcher: Dispatcher, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + mediationRecipientService: MediationRecipientService, + routingService: RoutingService + ): void { + dispatcher.registerHandler( + new V2ProposePresentationHandler(this, agentConfig, this.didCommMessageRepository, proofResponseCoordinator) + ) + + dispatcher.registerHandler( + new V2RequestPresentationHandler( + this, + agentConfig, + proofResponseCoordinator, + mediationRecipientService, + this.didCommMessageRepository, + routingService + ) + ) + + dispatcher.registerHandler( + new V2PresentationHandler(this, agentConfig, proofResponseCoordinator, this.didCommMessageRepository) + ) + dispatcher.registerHandler(new V2PresentationAckHandler(this)) + dispatcher.registerHandler(new V2PresentationProblemReportHandler(this)) + } + + private getFormatServiceForFormat(format: ProofFormatSpec) { + for (const service of Object.values(this.formatServiceMap)) { + if (service.supportsFormat(format.format)) { + return service + } + } + return null + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-presentation.test.ts b/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-presentation.test.ts new file mode 100644 index 0000000000..d02975e18b --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-presentation.test.ts @@ -0,0 +1,254 @@ +import type { Agent } from '../../../../../agent/Agent' +import type { ConnectionRecord } from '../../../../connections/repository/ConnectionRecord' +import type { ProposeProofOptions, AcceptProposalOptions } from '../../../ProofsApiOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { PresentationPreview } from '../../v1/models/V1PresentationPreview' + +import { setupProofsTest, waitForProofRecord } from '../../../../../../tests/helpers' +import testLogger from '../../../../../../tests/logger' +import { DidCommMessageRepository } from '../../../../../storage' +import { + V2_INDY_PRESENTATION_PROPOSAL, + V2_INDY_PRESENTATION_REQUEST, + V2_INDY_PRESENTATION, +} from '../../../formats/ProofFormatConstants' +import { ProofProtocolVersion } from '../../../models/ProofProtocolVersion' +import { ProofState } from '../../../models/ProofState' +import { V2PresentationMessage, V2RequestPresentationMessage } from '../messages' +import { V2ProposalPresentationMessage } from '../messages/V2ProposalPresentationMessage' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + let faberProofRecord: ProofRecord + let aliceProofRecord: ProofRecord + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, aliceConnection, presentationPreview } = await setupProofsTest( + 'Faber agent', + 'Alice agent' + )) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test(`Alice Creates and sends Proof Proposal to Faber`, async () => { + testLogger.test('Alice sends proof proposal to Faber') + + const proposeOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'ProofRequest', + nonce: '947121108704767252195126', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + comment: 'V2 propose proof test', + } + + const faberPresentationRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + aliceProofRecord = await aliceAgent.proofs.proposeProof(proposeOptions) + + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberPresentationRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/propose-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_PROPOSAL, + }, + ], + proposalsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + comment: 'V2 propose proof test', + }) + expect(faberProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + }) + + test(`Faber accepts the Proposal send by Alice`, async () => { + // Accept Proposal + const acceptProposalOptions: AcceptProposalOptions = { + proofRecordId: faberProofRecord.id, + } + + const alicePresentationRecordPromise = waitForProofRecord(aliceAgent, { + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + }) + + testLogger.test('Faber accepts presentation proposal from Alice') + faberProofRecord = await faberAgent.proofs.acceptProposal(acceptProposalOptions) + + testLogger.test('Alice waits for proof request from Faber') + aliceProofRecord = await alicePresentationRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/request-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_REQUEST, + }, + ], + requestPresentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(aliceProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + }) + + test(`Alice accepts presentation request from Faber`, async () => { + // Alice retrieves the requested credentials and accepts the presentation request + testLogger.test('Alice accepts presentation request from Faber') + + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + const faberPresentationRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + // Faber waits for the presentation from Alice + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberPresentationRecordPromise + + const presentation = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2PresentationMessage, + }) + + expect(presentation).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION, + }, + ], + presentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.PresentationReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + }) + + test(`Faber accepts the presentation provided by Alice`, async () => { + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts the presentation provided by Alice + testLogger.test('Faber accepts the presentation provided by Alice') + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits until she received a presentation acknowledgement + testLogger.test('Alice waits until she receives a presentation acknowledgement') + aliceProofRecord = await aliceProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: aliceProofRecord.threadId, + connectionId: expect.any(String), + isVerified: true, + state: ProofState.PresentationReceived, + }) + + expect(aliceProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: faberProofRecord.threadId, + connectionId: expect.any(String), + state: ProofState.Done, + }) + }) +}) diff --git a/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-proposal.test.ts b/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-proposal.test.ts new file mode 100644 index 0000000000..5bed51e09b --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-proposal.test.ts @@ -0,0 +1,100 @@ +import type { Agent } from '../../../../../agent/Agent' +import type { ConnectionRecord } from '../../../../connections/repository/ConnectionRecord' +import type { ProposeProofOptions } from '../../../ProofsApiOptions' +import type { ProofRecord } from '../../../repository' +import type { PresentationPreview } from '../../v1/models/V1PresentationPreview' + +import { setupProofsTest, waitForProofRecord } from '../../../../../../tests/helpers' +import testLogger from '../../../../../../tests/logger' +import { DidCommMessageRepository } from '../../../../../storage' +import { V2_INDY_PRESENTATION_PROPOSAL } from '../../../formats/ProofFormatConstants' +import { ProofProtocolVersion } from '../../../models/ProofProtocolVersion' +import { ProofState } from '../../../models/ProofState' +import { V2ProposalPresentationMessage } from '../messages/V2ProposalPresentationMessage' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + let faberPresentationRecord: ProofRecord + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, aliceConnection, presentationPreview } = await setupProofsTest( + 'Faber agent', + 'Alice agent' + )) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test(`Alice Creates and sends Proof Proposal to Faber`, async () => { + testLogger.test('Alice sends proof proposal to Faber') + + const proposeOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'ProofRequest', + nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + comment: 'V2 propose proof test', + } + + const faberPresentationRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + await aliceAgent.proofs.proposeProof(proposeOptions) + + testLogger.test('Faber waits for presentation from Alice') + faberPresentationRecord = await faberPresentationRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberPresentationRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/propose-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_PROPOSAL, + }, + ], + proposalsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + comment: 'V2 propose proof test', + }) + expect(faberPresentationRecord).toMatchObject({ + id: expect.anything(), + threadId: faberPresentationRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + }) +}) diff --git a/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-request.test.ts b/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-request.test.ts new file mode 100644 index 0000000000..9101a956f7 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/__tests__/indy-proof-request.test.ts @@ -0,0 +1,156 @@ +import type { Agent } from '../../../../../agent/Agent' +import type { ConnectionRecord } from '../../../../connections/repository/ConnectionRecord' +import type { ProposeProofOptions, AcceptProposalOptions } from '../../../ProofsApiOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { PresentationPreview } from '../../v1/models/V1PresentationPreview' + +import { setupProofsTest, waitForProofRecord } from '../../../../../../tests/helpers' +import testLogger from '../../../../../../tests/logger' +import { DidCommMessageRepository } from '../../../../../storage' +import { V2_INDY_PRESENTATION_PROPOSAL, V2_INDY_PRESENTATION_REQUEST } from '../../../formats/ProofFormatConstants' +import { ProofProtocolVersion } from '../../../models/ProofProtocolVersion' +import { ProofState } from '../../../models/ProofState' +import { V2RequestPresentationMessage } from '../messages' +import { V2ProposalPresentationMessage } from '../messages/V2ProposalPresentationMessage' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + let faberProofRecord: ProofRecord + let aliceProofRecord: ProofRecord + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, aliceConnection, presentationPreview } = await setupProofsTest( + 'Faber agent', + 'Alice agent' + )) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test(`Alice Creates and sends Proof Proposal to Faber`, async () => { + testLogger.test('Alice sends proof proposal to Faber') + + const proposeOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'ProofRequest', + nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + comment: 'V2 propose proof test', + } + + const faberPresentationRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + aliceProofRecord = await aliceAgent.proofs.proposeProof(proposeOptions) + + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberPresentationRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/propose-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_PROPOSAL, + }, + ], + proposalsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + comment: 'V2 propose proof test', + }) + expect(faberProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + }) + + test(`Faber accepts the Proposal send by Alice`, async () => { + // Accept Proposal + const acceptProposalOptions: AcceptProposalOptions = { + proofRecordId: faberProofRecord.id, + } + + const alicePresentationRecordPromise = waitForProofRecord(aliceAgent, { + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + }) + + testLogger.test('Faber accepts presentation proposal from Alice') + faberProofRecord = await faberAgent.proofs.acceptProposal(acceptProposalOptions) + + testLogger.test('Alice waits for proof request from Faber') + aliceProofRecord = await alicePresentationRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/request-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_REQUEST, + }, + ], + requestPresentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(aliceProofRecord).toMatchObject({ + id: expect.anything(), + threadId: faberProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + }) +}) diff --git a/packages/core/src/modules/proofs/protocol/v2/errors/V2PresentationProblemReportError.ts b/packages/core/src/modules/proofs/protocol/v2/errors/V2PresentationProblemReportError.ts new file mode 100644 index 0000000000..76fa789a6e --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/errors/V2PresentationProblemReportError.ts @@ -0,0 +1,23 @@ +import type { ProblemReportErrorOptions } from '../../../../problem-reports' +import type { PresentationProblemReportReason } from '../../../errors/PresentationProblemReportReason' + +import { ProblemReportError } from '../../../../problem-reports/errors/ProblemReportError' +import { V2PresentationProblemReportMessage } from '../messages' + +interface V2PresentationProblemReportErrorOptions extends ProblemReportErrorOptions { + problemCode: PresentationProblemReportReason +} + +export class V2PresentationProblemReportError extends ProblemReportError { + public problemReport: V2PresentationProblemReportMessage + + public constructor(public message: string, { problemCode }: V2PresentationProblemReportErrorOptions) { + super(message, { problemCode }) + this.problemReport = new V2PresentationProblemReportMessage({ + description: { + en: message, + code: problemCode, + }, + }) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/errors/index.ts b/packages/core/src/modules/proofs/protocol/v2/errors/index.ts new file mode 100644 index 0000000000..7064b070aa --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/errors/index.ts @@ -0,0 +1 @@ +export * from './V2PresentationProblemReportError' diff --git a/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationAckHandler.ts b/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationAckHandler.ts new file mode 100644 index 0000000000..9ffa2f32cc --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationAckHandler.ts @@ -0,0 +1,17 @@ +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { ProofService } from '../../../ProofService' + +import { V2PresentationAckMessage } from '../messages' + +export class V2PresentationAckHandler implements Handler { + private proofService: ProofService + public supportedMessages = [V2PresentationAckMessage] + + public constructor(proofService: ProofService) { + this.proofService = proofService + } + + public async handle(messageContext: HandlerInboundMessage) { + await this.proofService.processAck(messageContext) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationHandler.ts b/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationHandler.ts new file mode 100644 index 0000000000..d75a4a855c --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationHandler.ts @@ -0,0 +1,72 @@ +import type { AgentConfig } from '../../../../../agent/AgentConfig' +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { DidCommMessageRepository } from '../../../../../storage' +import type { ProofResponseCoordinator } from '../../../ProofResponseCoordinator' +import type { ProofRecord } from '../../../repository' +import type { V2ProofService } from '../V2ProofService' + +import { createOutboundMessage, createOutboundServiceMessage } from '../../../../../agent/helpers' +import { V2PresentationMessage, V2RequestPresentationMessage } from '../messages' + +export class V2PresentationHandler implements Handler { + private proofService: V2ProofService + private agentConfig: AgentConfig + private proofResponseCoordinator: ProofResponseCoordinator + private didCommMessageRepository: DidCommMessageRepository + public supportedMessages = [V2PresentationMessage] + + public constructor( + proofService: V2ProofService, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + didCommMessageRepository: DidCommMessageRepository + ) { + this.proofService = proofService + this.agentConfig = agentConfig + this.proofResponseCoordinator = proofResponseCoordinator + this.didCommMessageRepository = didCommMessageRepository + } + + public async handle(messageContext: HandlerInboundMessage) { + const proofRecord = await this.proofService.processPresentation(messageContext) + + if (this.proofResponseCoordinator.shouldAutoRespondToPresentation(messageContext.agentContext, proofRecord)) { + return await this.createAck(proofRecord, messageContext) + } + } + + private async createAck(record: ProofRecord, messageContext: HandlerInboundMessage) { + this.agentConfig.logger.info( + `Automatically sending acknowledgement with autoAccept on ${this.agentConfig.autoAcceptProofs}` + ) + + const { message, proofRecord } = await this.proofService.createAck(messageContext.agentContext, { + proofRecord: record, + }) + + const requestMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + const presentationMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2PresentationMessage, + }) + + if (messageContext.connection) { + return createOutboundMessage(messageContext.connection, message) + } else if (requestMessage?.service && presentationMessage?.service) { + const recipientService = presentationMessage?.service + const ourService = requestMessage?.service + + return createOutboundServiceMessage({ + payload: message, + service: recipientService.resolvedDidCommService, + senderKey: ourService.resolvedDidCommService.recipientKeys[0], + }) + } + + this.agentConfig.logger.error(`Could not automatically create presentation ack`) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationProblemReportHandler.ts b/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationProblemReportHandler.ts new file mode 100644 index 0000000000..77bdab2160 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/handlers/V2PresentationProblemReportHandler.ts @@ -0,0 +1,17 @@ +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { V2ProofService } from '../V2ProofService' + +import { V2PresentationProblemReportMessage } from '../messages' + +export class V2PresentationProblemReportHandler implements Handler { + private proofService: V2ProofService + public supportedMessages = [V2PresentationProblemReportMessage] + + public constructor(proofService: V2ProofService) { + this.proofService = proofService + } + + public async handle(messageContext: HandlerInboundMessage) { + await this.proofService.processProblemReport(messageContext) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/handlers/V2ProposePresentationHandler.ts b/packages/core/src/modules/proofs/protocol/v2/handlers/V2ProposePresentationHandler.ts new file mode 100644 index 0000000000..232065fd58 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/handlers/V2ProposePresentationHandler.ts @@ -0,0 +1,95 @@ +import type { AgentConfig } from '../../../../../agent/AgentConfig' +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { DidCommMessageRepository } from '../../../../../storage' +import type { ProofResponseCoordinator } from '../../../ProofResponseCoordinator' +import type { ProofFormat } from '../../../formats/ProofFormat' +import type { + CreateProofRequestFromProposalOptions, + CreateRequestAsResponseOptions, + ProofRequestFromProposalOptions, +} from '../../../models/ProofServiceOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { V2ProofService } from '../V2ProofService' + +import { createOutboundMessage } from '../../../../../agent/helpers' +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' +import { V2ProposalPresentationMessage } from '../messages/V2ProposalPresentationMessage' + +export class V2ProposePresentationHandler implements Handler { + private proofService: V2ProofService + private agentConfig: AgentConfig + private didCommMessageRepository: DidCommMessageRepository + private proofResponseCoordinator: ProofResponseCoordinator + public supportedMessages = [V2ProposalPresentationMessage] + + public constructor( + proofService: V2ProofService, + agentConfig: AgentConfig, + didCommMessageRepository: DidCommMessageRepository, + proofResponseCoordinator: ProofResponseCoordinator + ) { + this.proofService = proofService + this.agentConfig = agentConfig + this.didCommMessageRepository = didCommMessageRepository + this.proofResponseCoordinator = proofResponseCoordinator + } + + public async handle(messageContext: HandlerInboundMessage) { + const proofRecord = await this.proofService.processProposal(messageContext) + + if (this.proofResponseCoordinator.shouldAutoRespondToProposal(messageContext.agentContext, proofRecord)) { + return this.createRequest(proofRecord, messageContext) + } + } + + private async createRequest( + proofRecord: ProofRecord, + messageContext: HandlerInboundMessage + ) { + 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') + throw new AriesFrameworkError('No connection on the messageContext') + } + + const proposalMessage = await this.didCommMessageRepository.findAgentMessage(messageContext.agentContext, { + associatedRecordId: proofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + if (!proposalMessage) { + this.agentConfig.logger.error(`Proof record with id ${proofRecord.id} is missing required credential proposal`) + throw new AriesFrameworkError(`Proof record with id ${proofRecord.id} is missing required credential proposal`) + } + + const proofRequestFromProposalOptions: CreateProofRequestFromProposalOptions = { + proofRecord, + } + + const proofRequest: ProofRequestFromProposalOptions = await this.proofService.createProofRequestFromProposal( + messageContext.agentContext, + proofRequestFromProposalOptions + ) + + const indyProofRequest = proofRequest.proofFormats + + if (!indyProofRequest) { + this.agentConfig.logger.error('Failed to create proof request') + throw new AriesFrameworkError('Failed to create proof request.') + } + + const options: CreateRequestAsResponseOptions = { + proofRecord: proofRecord, + autoAcceptProof: proofRecord.autoAcceptProof, + proofFormats: indyProofRequest, + willConfirm: true, + } + + const { message } = await this.proofService.createRequestAsResponse(messageContext.agentContext, options) + + return createOutboundMessage(messageContext.connection, message) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/handlers/V2RequestPresentationHandler.ts b/packages/core/src/modules/proofs/protocol/v2/handlers/V2RequestPresentationHandler.ts new file mode 100644 index 0000000000..6f8e4ccd91 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/handlers/V2RequestPresentationHandler.ts @@ -0,0 +1,107 @@ +import type { AgentConfig } from '../../../../../agent/AgentConfig' +import type { Handler, HandlerInboundMessage } from '../../../../../agent/Handler' +import type { DidCommMessageRepository } from '../../../../../storage/didcomm/DidCommMessageRepository' +import type { MediationRecipientService, RoutingService } from '../../../../routing' +import type { ProofResponseCoordinator } from '../../../ProofResponseCoordinator' +import type { ProofFormat } from '../../../formats/ProofFormat' +import type { + CreatePresentationOptions, + FormatRequestedCredentialReturn, + FormatRetrievedCredentialOptions, +} from '../../../models/ProofServiceOptions' +import type { ProofRecord } from '../../../repository/ProofRecord' +import type { V2ProofService } from '../V2ProofService' + +import { createOutboundMessage, createOutboundServiceMessage } from '../../../../../agent/helpers' +import { ServiceDecorator } from '../../../../../decorators/service/ServiceDecorator' +import { DidCommMessageRole } from '../../../../../storage' +import { V2RequestPresentationMessage } from '../messages/V2RequestPresentationMessage' + +export class V2RequestPresentationHandler implements Handler { + private proofService: V2ProofService + private agentConfig: AgentConfig + private proofResponseCoordinator: ProofResponseCoordinator + private mediationRecipientService: MediationRecipientService + private didCommMessageRepository: DidCommMessageRepository + private routingService: RoutingService + public supportedMessages = [V2RequestPresentationMessage] + + public constructor( + proofService: V2ProofService, + agentConfig: AgentConfig, + proofResponseCoordinator: ProofResponseCoordinator, + mediationRecipientService: MediationRecipientService, + didCommMessageRepository: DidCommMessageRepository, + routingService: RoutingService + ) { + this.proofService = proofService + this.agentConfig = agentConfig + this.proofResponseCoordinator = proofResponseCoordinator + this.mediationRecipientService = mediationRecipientService + this.didCommMessageRepository = didCommMessageRepository + this.routingService = routingService + } + + public async handle(messageContext: HandlerInboundMessage) { + const proofRecord = await this.proofService.processRequest(messageContext) + if (this.proofResponseCoordinator.shouldAutoRespondToRequest(messageContext.agentContext, proofRecord)) { + return await this.createPresentation(proofRecord, messageContext) + } + } + + private async createPresentation( + record: ProofRecord, + messageContext: HandlerInboundMessage + ) { + const requestMessage = await this.didCommMessageRepository.getAgentMessage(messageContext.agentContext, { + associatedRecordId: record.id, + messageClass: V2RequestPresentationMessage, + }) + + this.agentConfig.logger.info( + `Automatically sending presentation with autoAccept on ${this.agentConfig.autoAcceptProofs}` + ) + + const retrievedCredentials: FormatRetrievedCredentialOptions = + await this.proofService.getRequestedCredentialsForProofRequest(messageContext.agentContext, { + proofRecord: record, + config: { + filterByPresentationPreview: false, + }, + }) + + const requestedCredentials: FormatRequestedCredentialReturn = + await this.proofService.autoSelectCredentialsForProofRequest(retrievedCredentials) + + const { message, proofRecord } = await this.proofService.createPresentation(messageContext.agentContext, { + proofRecord: record, + proofFormats: requestedCredentials.proofFormats, + }) + + if (messageContext.connection) { + return createOutboundMessage(messageContext.connection, message) + } else if (requestMessage.service) { + const routing = await this.routingService.getRouting(messageContext.agentContext) + message.service = new ServiceDecorator({ + serviceEndpoint: routing.endpoints[0], + recipientKeys: [routing.recipientKey.publicKeyBase58], + routingKeys: routing.routingKeys.map((key) => key.publicKeyBase58), + }) + const recipientService = requestMessage.service + + await this.didCommMessageRepository.saveOrUpdateAgentMessage(messageContext.agentContext, { + agentMessage: message, + associatedRecordId: proofRecord.id, + role: DidCommMessageRole.Sender, + }) + + return createOutboundServiceMessage({ + payload: message, + service: recipientService.resolvedDidCommService, + senderKey: message.service.resolvedDidCommService.recipientKeys[0], + }) + } + + this.agentConfig.logger.error(`Could not automatically create presentation`) + } +} diff --git a/packages/core/src/modules/proofs/protocol/v2/index.ts b/packages/core/src/modules/proofs/protocol/v2/index.ts new file mode 100644 index 0000000000..960bb99e85 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/index.ts @@ -0,0 +1 @@ +export * from './V2ProofService' diff --git a/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationAckMessage.ts b/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationAckMessage.ts new file mode 100644 index 0000000000..06918adb5b --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationAckMessage.ts @@ -0,0 +1,14 @@ +import type { PresentationAckMessageOptions } from '../../../messages/PresentationAckMessage' + +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { AckMessage } from '../../../../common/messages/AckMessage' + +export class V2PresentationAckMessage extends AckMessage { + public constructor(options: PresentationAckMessageOptions) { + super(options) + } + + @IsValidMessageType(V2PresentationAckMessage.type) + public readonly type = V2PresentationAckMessage.type.messageTypeUri + public static readonly type = parseMessageType('https://didcomm.org/present-proof/2.0/ack') +} diff --git a/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationMessage.ts b/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationMessage.ts new file mode 100644 index 0000000000..f13915bc25 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationMessage.ts @@ -0,0 +1,93 @@ +import type { ProofAttachmentFormat } from '../../../formats/models/ProofAttachmentFormat' + +import { Expose, Type } from 'class-transformer' +import { IsArray, IsBoolean, IsInstance, IsOptional, IsString, ValidateNested } from 'class-validator' + +import { AgentMessage } from '../../../../../agent/AgentMessage' +import { Attachment } from '../../../../../decorators/attachment/Attachment' +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { uuid } from '../../../../../utils/uuid' +import { ProofFormatSpec } from '../../../models/ProofFormatSpec' + +export interface V2PresentationMessageOptions { + id?: string + goalCode?: string + comment?: string + lastPresentation?: boolean + attachmentInfo: ProofAttachmentFormat[] +} + +export class V2PresentationMessage extends AgentMessage { + public constructor(options: V2PresentationMessageOptions) { + super() + + if (options) { + this.formats = [] + this.presentationsAttach = [] + this.id = options.id ?? uuid() + this.comment = options.comment + this.goalCode = options.goalCode + this.lastPresentation = options.lastPresentation ?? true + + for (const entry of options.attachmentInfo) { + this.addPresentationsAttachment(entry) + } + } + } + + public addPresentationsAttachment(attachment: ProofAttachmentFormat) { + this.formats.push(attachment.format) + this.presentationsAttach.push(attachment.attachment) + } + + /** + * Every attachment has a corresponding entry in the formats array. + * This method pairs those together in a {@link ProofAttachmentFormat} object. + */ + public getAttachmentFormats(): ProofAttachmentFormat[] { + const attachmentFormats: ProofAttachmentFormat[] = [] + + this.formats.forEach((format) => { + const attachment = this.presentationsAttach.find((attachment) => attachment.id === format.attachmentId) + + if (!attachment) { + throw new AriesFrameworkError(`Could not find a matching attachment with attachmentId: ${format.attachmentId}`) + } + + attachmentFormats.push({ format, attachment }) + }) + return attachmentFormats + } + + @IsValidMessageType(V2PresentationMessage.type) + public readonly type = V2PresentationMessage.type.messageTypeUri + public static readonly type = parseMessageType('https://didcomm.org/present-proof/2.0/presentation') + + @IsString() + @IsOptional() + public comment?: string + + @Expose({ name: 'goal_code' }) + @IsString() + @IsOptional() + public goalCode?: string + + @Expose({ name: 'last_presentation' }) + @IsBoolean() + public lastPresentation = true + + @Expose({ name: 'formats' }) + @Type(() => ProofFormatSpec) + @IsArray() + @ValidateNested({ each: true }) + @IsInstance(ProofFormatSpec, { each: true }) + public formats!: ProofFormatSpec[] + + @Expose({ name: 'presentations~attach' }) + @Type(() => Attachment) + @IsArray() + @ValidateNested({ each: true }) + @IsInstance(Attachment, { each: true }) + public presentationsAttach!: Attachment[] +} diff --git a/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationProblemReportMessage.ts b/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationProblemReportMessage.ts new file mode 100644 index 0000000000..b36a69a7fe --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/messages/V2PresentationProblemReportMessage.ts @@ -0,0 +1,23 @@ +import type { ProblemReportMessageOptions } from '../../../../problem-reports/messages/ProblemReportMessage' + +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { ProblemReportMessage } from '../../../../problem-reports/messages/ProblemReportMessage' + +export type V2PresentationProblemReportMessageOptions = ProblemReportMessageOptions + +/** + * @see https://github.com/hyperledger/aries-rfcs/blob/main/features/0035-report-problem/README.md + */ +export class V2PresentationProblemReportMessage extends ProblemReportMessage { + /** + * Create new PresentationProblemReportMessage instance. + * @param options + */ + public constructor(options: V2PresentationProblemReportMessageOptions) { + super(options) + } + + @IsValidMessageType(V2PresentationProblemReportMessage.type) + public readonly type = V2PresentationProblemReportMessage.type.messageTypeUri + public static readonly type = parseMessageType('https://didcomm.org/present-proof/2.0/problem-report') +} diff --git a/packages/core/src/modules/proofs/protocol/v2/messages/V2ProposalPresentationMessage.ts b/packages/core/src/modules/proofs/protocol/v2/messages/V2ProposalPresentationMessage.ts new file mode 100644 index 0000000000..6528e10f10 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/messages/V2ProposalPresentationMessage.ts @@ -0,0 +1,93 @@ +import type { ProofAttachmentFormat } from '../../../formats/models/ProofAttachmentFormat' + +import { Expose, Type } from 'class-transformer' +import { IsArray, IsBoolean, IsInstance, IsOptional, IsString, ValidateNested } from 'class-validator' + +import { AgentMessage } from '../../../../../agent/AgentMessage' +import { Attachment } from '../../../../../decorators/attachment/Attachment' +import { AriesFrameworkError } from '../../../../../error/AriesFrameworkError' +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { uuid } from '../../../../../utils/uuid' +import { ProofFormatSpec } from '../../../models/ProofFormatSpec' + +export interface V2ProposePresentationMessageOptions { + id?: string + comment?: string + goalCode?: string + willConfirm?: boolean + attachmentInfo: ProofAttachmentFormat[] +} + +export class V2ProposalPresentationMessage extends AgentMessage { + public constructor(options: V2ProposePresentationMessageOptions) { + super() + + if (options) { + this.formats = [] + this.proposalsAttach = [] + this.id = options.id ?? uuid() + this.comment = options.comment + this.goalCode = options.goalCode + this.willConfirm = options.willConfirm ?? false + + for (const entry of options.attachmentInfo) { + this.addProposalsAttachment(entry) + } + } + } + + public addProposalsAttachment(attachment: ProofAttachmentFormat) { + this.formats.push(attachment.format) + this.proposalsAttach.push(attachment.attachment) + } + + /** + * Every attachment has a corresponding entry in the formats array. + * This method pairs those together in a {@link ProofAttachmentFormat} object. + */ + public getAttachmentFormats(): ProofAttachmentFormat[] { + const attachmentFormats: ProofAttachmentFormat[] = [] + + this.formats.forEach((format) => { + const attachment = this.proposalsAttach.find((attachment) => attachment.id === format.attachmentId) + + if (!attachment) { + throw new AriesFrameworkError(`Could not find a matching attachment with attachmentId: ${format.attachmentId}`) + } + + attachmentFormats.push({ format, attachment }) + }) + return attachmentFormats + } + + @IsValidMessageType(V2ProposalPresentationMessage.type) + public readonly type = V2ProposalPresentationMessage.type.messageTypeUri + public static readonly type = parseMessageType(`https://didcomm.org/present-proof/2.0/propose-presentation`) + + @IsString() + @IsOptional() + public comment?: string + + @Expose({ name: 'goal_code' }) + @IsString() + @IsOptional() + public goalCode?: string + + @Expose({ name: 'will_confirm' }) + @IsBoolean() + public willConfirm = false + + @Expose({ name: 'formats' }) + @Type(() => ProofFormatSpec) + @IsArray() + @ValidateNested({ each: true }) + @IsInstance(ProofFormatSpec, { each: true }) + public formats!: ProofFormatSpec[] + + @Expose({ name: 'proposals~attach' }) + @Type(() => Attachment) + @IsArray() + @ValidateNested({ each: true }) + @IsInstance(Attachment, { each: true }) + public proposalsAttach!: Attachment[] +} diff --git a/packages/core/src/modules/proofs/protocol/v2/messages/V2RequestPresentationMessage.ts b/packages/core/src/modules/proofs/protocol/v2/messages/V2RequestPresentationMessage.ts new file mode 100644 index 0000000000..16c6c22339 --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/messages/V2RequestPresentationMessage.ts @@ -0,0 +1,117 @@ +import type { ProofAttachmentFormat } from '../../../formats/models/ProofAttachmentFormat' + +import { Expose, Type } from 'class-transformer' +import { IsArray, IsBoolean, IsInstance, IsOptional, IsString, ValidateNested } from 'class-validator' + +import { AgentMessage } from '../../../../../agent/AgentMessage' +import { Attachment } from '../../../../../decorators/attachment/Attachment' +import { AriesFrameworkError } from '../../../../../error' +import { IsValidMessageType, parseMessageType } from '../../../../../utils/messageType' +import { uuid } from '../../../../../utils/uuid' +import { ProofFormatSpec } from '../../../models/ProofFormatSpec' + +export interface V2RequestPresentationMessageOptions { + id?: string + comment?: string + goalCode?: string + presentMultiple?: boolean + willConfirm?: boolean + attachmentInfo: ProofAttachmentFormat[] +} + +export class V2RequestPresentationMessage extends AgentMessage { + public constructor(options: V2RequestPresentationMessageOptions) { + super() + + if (options) { + this.formats = [] + this.requestPresentationsAttach = [] + this.id = options.id ?? uuid() + this.comment = options.comment + this.goalCode = options.goalCode + this.willConfirm = options.willConfirm ?? true + this.presentMultiple = options.presentMultiple ?? false + for (const entry of options.attachmentInfo) { + this.addRequestPresentationsAttachment(entry) + } + } + } + + public addRequestPresentationsAttachment(attachment: ProofAttachmentFormat) { + this.formats.push(attachment.format) + this.requestPresentationsAttach.push(attachment.attachment) + } + + public getAttachmentByFormatIdentifier(formatIdentifier: string) { + const format = this.formats.find((x) => x.format === formatIdentifier) + if (!format) { + throw new AriesFrameworkError( + `Expected to find a format entry of type: ${formatIdentifier}, but none could be found.` + ) + } + + const attachment = this.requestPresentationsAttach.find((x) => x.id === format.attachmentId) + + if (!attachment) { + throw new AriesFrameworkError( + `Expected to find an attachment entry with id: ${format.attachmentId}, but none could be found.` + ) + } + + return attachment + } + + /** + * Every attachment has a corresponding entry in the formats array. + * This method pairs those together in a {@link ProofAttachmentFormat} object. + */ + public getAttachmentFormats(): ProofAttachmentFormat[] { + const attachmentFormats: ProofAttachmentFormat[] = [] + + this.formats.forEach((format) => { + const attachment = this.requestPresentationsAttach.find((attachment) => attachment.id === format.attachmentId) + + if (!attachment) { + throw new AriesFrameworkError(`Could not find a matching attachment with attachmentId: ${format.attachmentId}`) + } + + attachmentFormats.push({ format, attachment }) + }) + return attachmentFormats + } + + @IsValidMessageType(V2RequestPresentationMessage.type) + public readonly type = V2RequestPresentationMessage.type.messageTypeUri + public static readonly type = parseMessageType('https://didcomm.org/present-proof/2.0/request-presentation') + + @IsString() + @IsOptional() + public comment?: string + + @Expose({ name: 'goal_code' }) + @IsString() + @IsOptional() + public goalCode?: string + + @Expose({ name: 'will_confirm' }) + @IsBoolean() + public willConfirm = false + + @Expose({ name: 'present_multiple' }) + @IsBoolean() + public presentMultiple = false + + @Expose({ name: 'formats' }) + @Type(() => ProofFormatSpec) + @IsArray() + @ValidateNested({ each: true }) + @IsInstance(ProofFormatSpec, { each: true }) + public formats!: ProofFormatSpec[] + + @Expose({ name: 'request_presentations~attach' }) + @Type(() => Attachment) + @IsArray() + @ValidateNested({ each: true }) + @IsInstance(Attachment, { each: true }) + public requestPresentationsAttach!: Attachment[] +} diff --git a/packages/core/src/modules/proofs/protocol/v2/messages/index.ts b/packages/core/src/modules/proofs/protocol/v2/messages/index.ts new file mode 100644 index 0000000000..8b0c4a005d --- /dev/null +++ b/packages/core/src/modules/proofs/protocol/v2/messages/index.ts @@ -0,0 +1,5 @@ +export * from './V2PresentationAckMessage' +export * from './V2PresentationMessage' +export * from './V2PresentationProblemReportMessage' +export * from './V2ProposalPresentationMessage' +export * from './V2RequestPresentationMessage' diff --git a/packages/core/src/modules/proofs/repository/PresentationExchangeRecord.ts b/packages/core/src/modules/proofs/repository/PresentationExchangeRecord.ts new file mode 100644 index 0000000000..f9fa20f6b9 --- /dev/null +++ b/packages/core/src/modules/proofs/repository/PresentationExchangeRecord.ts @@ -0,0 +1,4 @@ +export enum PresentationRecordType { + Indy = 'indy', + PresentationExchange = 'presentationExchange', +} diff --git a/packages/core/src/modules/proofs/repository/ProofRecord.ts b/packages/core/src/modules/proofs/repository/ProofRecord.ts index bf4faa5435..9f3442cf6b 100644 --- a/packages/core/src/modules/proofs/repository/ProofRecord.ts +++ b/packages/core/src/modules/proofs/repository/ProofRecord.ts @@ -1,31 +1,23 @@ import type { TagsBase } from '../../../storage/BaseRecord' -import type { AutoAcceptProof } from '../ProofAutoAcceptType' -import type { ProofState } from '../ProofState' - -import { Type } from 'class-transformer' +import type { AutoAcceptProof } from '../models/ProofAutoAcceptType' +import type { ProofProtocolVersion } from '../models/ProofProtocolVersion' +import type { ProofState } from '../models/ProofState' import { AriesFrameworkError } from '../../../error' import { BaseRecord } from '../../../storage/BaseRecord' import { uuid } from '../../../utils/uuid' -import { ProposePresentationMessage, RequestPresentationMessage, PresentationMessage } from '../messages' export interface ProofRecordProps { id?: string createdAt?: Date - + protocolVersion: ProofProtocolVersion isVerified?: boolean state: ProofState connectionId?: string threadId: string - presentationId?: string tags?: CustomProofTags autoAcceptProof?: AutoAcceptProof errorMessage?: string - - // message data - proposalMessage?: ProposePresentationMessage - requestMessage?: RequestPresentationMessage - presentationMessage?: PresentationMessage } export type CustomProofTags = TagsBase @@ -35,23 +27,17 @@ export type DefaultProofTags = { state: ProofState } +// T-TODO: rename to proof exchange record + export class ProofRecord extends BaseRecord { public connectionId?: string public threadId!: string + public protocolVersion!: ProofProtocolVersion public isVerified?: boolean - public presentationId?: string public state!: ProofState public autoAcceptProof?: AutoAcceptProof public errorMessage?: string - // message data - @Type(() => ProposePresentationMessage) - public proposalMessage?: ProposePresentationMessage - @Type(() => RequestPresentationMessage) - public requestMessage?: RequestPresentationMessage - @Type(() => PresentationMessage) - public presentationMessage?: PresentationMessage - public static readonly type = 'ProofRecord' public readonly type = ProofRecord.type @@ -61,14 +47,13 @@ export class ProofRecord extends BaseRecord { if (props) { this.id = props.id ?? uuid() this.createdAt = props.createdAt ?? new Date() - this.proposalMessage = props.proposalMessage - this.requestMessage = props.requestMessage - this.presentationMessage = props.presentationMessage + this.protocolVersion = props.protocolVersion + this.isVerified = props.isVerified this.state = props.state this.connectionId = props.connectionId this.threadId = props.threadId - this.presentationId = props.presentationId + this.autoAcceptProof = props.autoAcceptProof this._tags = props.tags ?? {} this.errorMessage = props.errorMessage diff --git a/packages/core/src/modules/proofs/repository/index.ts b/packages/core/src/modules/proofs/repository/index.ts index 23ca5ba9a3..8c1bf5235e 100644 --- a/packages/core/src/modules/proofs/repository/index.ts +++ b/packages/core/src/modules/proofs/repository/index.ts @@ -1,2 +1,3 @@ export * from './ProofRecord' export * from './ProofRepository' +export * from './PresentationExchangeRecord' diff --git a/packages/core/src/modules/proofs/services/ProofService.ts b/packages/core/src/modules/proofs/services/ProofService.ts deleted file mode 100644 index 809035067a..0000000000 --- a/packages/core/src/modules/proofs/services/ProofService.ts +++ /dev/null @@ -1,1199 +0,0 @@ -import type { AgentContext } from '../../../agent' -import type { AgentMessage } from '../../../agent/AgentMessage' -import type { InboundMessageContext } from '../../../agent/models/InboundMessageContext' -import type { ConnectionRecord } from '../../connections' -import type { AutoAcceptProof } from '../ProofAutoAcceptType' -import type { ProofStateChangedEvent } from '../ProofEvents' -import type { PresentationPreview, PresentationPreviewAttribute } from '../messages' -import type { PresentationProblemReportMessage } from './../messages/PresentationProblemReportMessage' -import type { CredDef, IndyProof, Schema } from 'indy-sdk' - -import { validateOrReject } from 'class-validator' - -import { EventEmitter } from '../../../agent/EventEmitter' -import { InjectionSymbols } from '../../../constants' -import { Attachment, AttachmentData } from '../../../decorators/attachment/Attachment' -import { AriesFrameworkError } from '../../../error' -import { Logger } from '../../../logger' -import { inject, injectable } from '../../../plugins' -import { JsonEncoder } from '../../../utils/JsonEncoder' -import { JsonTransformer } from '../../../utils/JsonTransformer' -import { checkProofRequestForDuplicates } from '../../../utils/indyProofRequest' -import { uuid } from '../../../utils/uuid' -import { AckStatus } from '../../common' -import { ConnectionService } from '../../connections' -import { CredentialRepository, IndyCredential, IndyCredentialInfo } from '../../credentials' -import { IndyCredentialUtils } from '../../credentials/formats/indy/IndyCredentialUtils' -import { IndyHolderService, IndyRevocationService, IndyVerifierService } from '../../indy' -import { IndyLedgerService } from '../../ledger/services/IndyLedgerService' -import { ProofEventTypes } from '../ProofEvents' -import { ProofState } from '../ProofState' -import { PresentationProblemReportError, PresentationProblemReportReason } from '../errors' -import { - INDY_PROOF_ATTACHMENT_ID, - INDY_PROOF_REQUEST_ATTACHMENT_ID, - PresentationAckMessage, - PresentationMessage, - ProposePresentationMessage, - RequestPresentationMessage, -} from '../messages' -import { - AttributeFilter, - PartialProof, - ProofAttributeInfo, - ProofPredicateInfo, - ProofRequest, - RequestedAttribute, - RequestedCredentials, - RequestedPredicate, - RetrievedCredentials, -} from '../models' -import { ProofRepository } from '../repository' -import { ProofRecord } from '../repository/ProofRecord' - -/** - * @todo add method to check if request matches proposal. Useful to see if a request I received is the same as the proposal I sent. - * @todo add method to reject / revoke messages - * @todo validate attachments / messages - */ -@injectable() -export class ProofService { - private proofRepository: ProofRepository - private credentialRepository: CredentialRepository - private ledgerService: IndyLedgerService - private logger: Logger - private indyHolderService: IndyHolderService - private indyVerifierService: IndyVerifierService - private indyRevocationService: IndyRevocationService - private connectionService: ConnectionService - private eventEmitter: EventEmitter - - public constructor( - proofRepository: ProofRepository, - ledgerService: IndyLedgerService, - indyHolderService: IndyHolderService, - indyVerifierService: IndyVerifierService, - indyRevocationService: IndyRevocationService, - connectionService: ConnectionService, - eventEmitter: EventEmitter, - credentialRepository: CredentialRepository, - @inject(InjectionSymbols.Logger) logger: Logger - ) { - this.proofRepository = proofRepository - this.credentialRepository = credentialRepository - this.ledgerService = ledgerService - this.logger = logger - this.indyHolderService = indyHolderService - this.indyVerifierService = indyVerifierService - this.indyRevocationService = indyRevocationService - this.connectionService = connectionService - this.eventEmitter = eventEmitter - } - - /** - * Create a {@link ProposePresentationMessage} not bound to an existing presentation exchange. - * To create a proposal as response to an existing presentation exchange, use {@link ProofService.createProposalAsResponse}. - * - * @param connectionRecord The connection for which to create the presentation proposal - * @param presentationProposal The presentation proposal to include in the message - * @param config Additional configuration to use for the proposal - * @returns Object containing proposal message and associated proof record - * - */ - public async createProposal( - agentContext: AgentContext, - connectionRecord: ConnectionRecord, - presentationProposal: PresentationPreview, - config?: { - comment?: string - autoAcceptProof?: AutoAcceptProof - } - ): Promise> { - // Assert - connectionRecord.assertReady() - - // Create message - const proposalMessage = new ProposePresentationMessage({ - comment: config?.comment, - presentationProposal, - }) - - // Create record - const proofRecord = new ProofRecord({ - connectionId: connectionRecord.id, - threadId: proposalMessage.threadId, - state: ProofState.ProposalSent, - proposalMessage, - autoAcceptProof: config?.autoAcceptProof, - }) - await this.proofRepository.save(agentContext, proofRecord) - this.emitStateChangedEvent(agentContext, proofRecord, null) - - return { message: proposalMessage, proofRecord } - } - - /** - * Create a {@link ProposePresentationMessage} as response to a received presentation request. - * To create a proposal not bound to an existing presentation exchange, use {@link ProofService.createProposal}. - * - * @param proofRecord The proof record for which to create the presentation proposal - * @param presentationProposal The presentation proposal to include in the message - * @param config Additional configuration to use for the proposal - * @returns Object containing proposal message and associated proof record - * - */ - public async createProposalAsResponse( - agentContext: AgentContext, - proofRecord: ProofRecord, - presentationProposal: PresentationPreview, - config?: { - comment?: string - } - ): Promise> { - // Assert - proofRecord.assertState(ProofState.RequestReceived) - - // Create message - const proposalMessage = new ProposePresentationMessage({ - comment: config?.comment, - presentationProposal, - }) - proposalMessage.setThread({ threadId: proofRecord.threadId }) - - // Update record - proofRecord.proposalMessage = proposalMessage - await this.updateState(agentContext, proofRecord, ProofState.ProposalSent) - - return { message: proposalMessage, proofRecord } - } - - /** - * Decline a proof request - * @param proofRecord The proof request to be declined - */ - public async declineRequest(agentContext: AgentContext, proofRecord: ProofRecord): Promise { - proofRecord.assertState(ProofState.RequestReceived) - - await this.updateState(agentContext, proofRecord, ProofState.Declined) - - return proofRecord - } - - /** - * Process a received {@link ProposePresentationMessage}. This will not accept the presentation proposal - * or send a presentation request. It will only create a new, or update the existing proof record with - * the information from the presentation proposal message. Use {@link ProofService.createRequestAsResponse} - * after calling this method to create a presentation request. - * - * @param messageContext The message context containing a presentation proposal message - * @returns proof record associated with the presentation proposal message - * - */ - public async processProposal( - messageContext: InboundMessageContext - ): Promise { - let proofRecord: ProofRecord - const { message: proposalMessage, connection } = messageContext - - this.logger.debug(`Processing presentation proposal with id ${proposalMessage.id}`) - - try { - // Proof record already exists - proofRecord = await this.getByThreadAndConnectionId( - messageContext.agentContext, - proposalMessage.threadId, - connection?.id - ) - - // Assert - proofRecord.assertState(ProofState.RequestSent) - this.connectionService.assertConnectionOrServiceDecorator(messageContext, { - previousReceivedMessage: proofRecord.proposalMessage, - previousSentMessage: proofRecord.requestMessage, - }) - - // Update record - proofRecord.proposalMessage = proposalMessage - await this.updateState(messageContext.agentContext, proofRecord, ProofState.ProposalReceived) - } catch { - // No proof record exists with thread id - proofRecord = new ProofRecord({ - connectionId: connection?.id, - threadId: proposalMessage.threadId, - proposalMessage, - state: ProofState.ProposalReceived, - }) - - // Assert - this.connectionService.assertConnectionOrServiceDecorator(messageContext) - - // Save record - await this.proofRepository.save(messageContext.agentContext, proofRecord) - this.emitStateChangedEvent(messageContext.agentContext, proofRecord, null) - } - - return proofRecord - } - - /** - * Create a {@link RequestPresentationMessage} as response to a received presentation proposal. - * To create a request not bound to an existing presentation exchange, use {@link ProofService.createRequest}. - * - * @param proofRecord The proof record for which to create the presentation request - * @param proofRequest The proof request to include in the message - * @param config Additional configuration to use for the request - * @returns Object containing request message and associated proof record - * - */ - public async createRequestAsResponse( - agentContext: AgentContext, - proofRecord: ProofRecord, - proofRequest: ProofRequest, - config?: { - comment?: string - } - ): Promise> { - // Assert attribute and predicate (group) names do not match - checkProofRequestForDuplicates(proofRequest) - - // Assert - proofRecord.assertState(ProofState.ProposalReceived) - - // Create message - const attachment = new Attachment({ - id: INDY_PROOF_REQUEST_ATTACHMENT_ID, - mimeType: 'application/json', - data: new AttachmentData({ - base64: JsonEncoder.toBase64(proofRequest), - }), - }) - const requestPresentationMessage = new RequestPresentationMessage({ - comment: config?.comment, - requestPresentationAttachments: [attachment], - }) - requestPresentationMessage.setThread({ - threadId: proofRecord.threadId, - }) - - // Update record - proofRecord.requestMessage = requestPresentationMessage - await this.updateState(agentContext, proofRecord, ProofState.RequestSent) - - return { message: requestPresentationMessage, proofRecord } - } - - /** - * Create a {@link RequestPresentationMessage} not bound to an existing presentation exchange. - * To create a request as response to an existing presentation exchange, use {@link ProofService#createRequestAsResponse}. - * - * @param proofRequestTemplate The proof request template - * @param connectionRecord The connection for which to create the presentation request - * @returns Object containing request message and associated proof record - * - */ - public async createRequest( - agentContext: AgentContext, - proofRequest: ProofRequest, - connectionRecord?: ConnectionRecord, - config?: { - comment?: string - autoAcceptProof?: AutoAcceptProof - } - ): Promise> { - this.logger.debug(`Creating proof request`) - - // Assert attribute and predicate (group) names do not match - checkProofRequestForDuplicates(proofRequest) - - // Assert - connectionRecord?.assertReady() - - // Create message - const attachment = new Attachment({ - id: INDY_PROOF_REQUEST_ATTACHMENT_ID, - mimeType: 'application/json', - data: new AttachmentData({ - base64: JsonEncoder.toBase64(proofRequest), - }), - }) - const requestPresentationMessage = new RequestPresentationMessage({ - comment: config?.comment, - requestPresentationAttachments: [attachment], - }) - - // Create record - const proofRecord = new ProofRecord({ - connectionId: connectionRecord?.id, - threadId: requestPresentationMessage.threadId, - requestMessage: requestPresentationMessage, - state: ProofState.RequestSent, - autoAcceptProof: config?.autoAcceptProof, - }) - - await this.proofRepository.save(agentContext, proofRecord) - this.emitStateChangedEvent(agentContext, proofRecord, null) - - return { message: requestPresentationMessage, proofRecord } - } - - /** - * Process a received {@link RequestPresentationMessage}. This will not accept the presentation request - * or send a presentation. It will only create a new, or update the existing proof record with - * the information from the presentation request message. Use {@link ProofService.createPresentation} - * after calling this method to create a presentation. - * - * @param messageContext The message context containing a presentation request message - * @returns proof record associated with the presentation request message - * - */ - public async processRequest(messageContext: InboundMessageContext): Promise { - let proofRecord: ProofRecord - const { message: proofRequestMessage, connection } = messageContext - - this.logger.debug(`Processing presentation request with id ${proofRequestMessage.id}`) - - const proofRequest = proofRequestMessage.indyProofRequest - - // Assert attachment - if (!proofRequest) { - throw new PresentationProblemReportError( - `Missing required base64 or json encoded attachment data for presentation request with thread id ${proofRequestMessage.threadId}`, - { problemCode: PresentationProblemReportReason.Abandoned } - ) - } - await validateOrReject(proofRequest) - - // Assert attribute and predicate (group) names do not match - checkProofRequestForDuplicates(proofRequest) - - this.logger.debug('received proof request', proofRequest) - - try { - // Proof record already exists - proofRecord = await this.getByThreadAndConnectionId( - messageContext.agentContext, - proofRequestMessage.threadId, - connection?.id - ) - - // Assert - proofRecord.assertState(ProofState.ProposalSent) - this.connectionService.assertConnectionOrServiceDecorator(messageContext, { - previousReceivedMessage: proofRecord.requestMessage, - previousSentMessage: proofRecord.proposalMessage, - }) - - // Update record - proofRecord.requestMessage = proofRequestMessage - await this.updateState(messageContext.agentContext, proofRecord, ProofState.RequestReceived) - } catch { - // No proof record exists with thread id - proofRecord = new ProofRecord({ - connectionId: connection?.id, - threadId: proofRequestMessage.threadId, - requestMessage: proofRequestMessage, - state: ProofState.RequestReceived, - }) - - // Assert - this.connectionService.assertConnectionOrServiceDecorator(messageContext) - - // Save in repository - await this.proofRepository.save(messageContext.agentContext, proofRecord) - this.emitStateChangedEvent(messageContext.agentContext, proofRecord, null) - } - - return proofRecord - } - - /** - * Create a {@link PresentationMessage} as response to a received presentation request. - * - * @param proofRecord The proof record for which to create the presentation - * @param requestedCredentials The requested credentials object specifying which credentials to use for the proof - * @param config Additional configuration to use for the presentation - * @returns Object containing presentation message and associated proof record - * - */ - public async createPresentation( - agentContext: AgentContext, - proofRecord: ProofRecord, - requestedCredentials: RequestedCredentials, - config?: { - comment?: string - } - ): Promise> { - this.logger.debug(`Creating presentation for proof record with id ${proofRecord.id}`) - - // Assert - proofRecord.assertState(ProofState.RequestReceived) - - const indyProofRequest = proofRecord.requestMessage?.indyProofRequest - if (!indyProofRequest) { - throw new PresentationProblemReportError( - `Missing required base64 or json encoded attachment data for presentation with thread id ${proofRecord.threadId}`, - { problemCode: PresentationProblemReportReason.Abandoned } - ) - } - - // Get the matching attachments to the requested credentials - const attachments = await this.getRequestedAttachmentsForRequestedCredentials( - agentContext, - indyProofRequest, - requestedCredentials - ) - - // Create proof - const proof = await this.createProof(agentContext, indyProofRequest, requestedCredentials) - - // Create message - const attachment = new Attachment({ - id: INDY_PROOF_ATTACHMENT_ID, - mimeType: 'application/json', - data: new AttachmentData({ - base64: JsonEncoder.toBase64(proof), - }), - }) - - const presentationMessage = new PresentationMessage({ - comment: config?.comment, - presentationAttachments: [attachment], - attachments, - }) - presentationMessage.setThread({ threadId: proofRecord.threadId }) - - // Update record - proofRecord.presentationMessage = presentationMessage - await this.updateState(agentContext, proofRecord, ProofState.PresentationSent) - - return { message: presentationMessage, proofRecord } - } - - /** - * Process a received {@link PresentationMessage}. This will not accept the presentation - * or send a presentation acknowledgement. It will only update the existing proof record with - * the information from the presentation message. Use {@link ProofService.createAck} - * after calling this method to create a presentation acknowledgement. - * - * @param messageContext The message context containing a presentation message - * @returns proof record associated with the presentation message - * - */ - public async processPresentation(messageContext: InboundMessageContext): Promise { - const { message: presentationMessage, connection } = messageContext - - this.logger.debug(`Processing presentation with id ${presentationMessage.id}`) - - const proofRecord = await this.getByThreadAndConnectionId( - messageContext.agentContext, - presentationMessage.threadId, - connection?.id - ) - - // Assert - proofRecord.assertState(ProofState.RequestSent) - this.connectionService.assertConnectionOrServiceDecorator(messageContext, { - previousReceivedMessage: proofRecord.proposalMessage, - previousSentMessage: proofRecord.requestMessage, - }) - - // TODO: add proof class with validator - const indyProofJson = presentationMessage.indyProof - const indyProofRequest = proofRecord.requestMessage?.indyProofRequest - - if (!indyProofJson) { - throw new PresentationProblemReportError( - `Missing required base64 or json encoded attachment data for presentation with thread id ${presentationMessage.threadId}`, - { problemCode: PresentationProblemReportReason.Abandoned } - ) - } - - if (!indyProofRequest) { - throw new PresentationProblemReportError( - `Missing required base64 or json encoded attachment data for presentation request with thread id ${presentationMessage.threadId}`, - { problemCode: PresentationProblemReportReason.Abandoned } - ) - } - - const isValid = await this.verifyProof(messageContext.agentContext, indyProofJson, indyProofRequest) - - // Update record - proofRecord.isVerified = isValid - proofRecord.presentationMessage = presentationMessage - await this.updateState(messageContext.agentContext, proofRecord, ProofState.PresentationReceived) - - return proofRecord - } - - /** - * Create a {@link PresentationAckMessage} as response to a received presentation. - * - * @param proofRecord The proof record for which to create the presentation acknowledgement - * @returns Object containing presentation acknowledgement message and associated proof record - * - */ - public async createAck( - agentContext: AgentContext, - proofRecord: ProofRecord - ): Promise> { - this.logger.debug(`Creating presentation ack for proof record with id ${proofRecord.id}`) - - // Assert - proofRecord.assertState(ProofState.PresentationReceived) - - // Create message - const ackMessage = new PresentationAckMessage({ - status: AckStatus.OK, - threadId: proofRecord.threadId, - }) - - // Update record - await this.updateState(agentContext, proofRecord, ProofState.Done) - - return { message: ackMessage, proofRecord } - } - - /** - * Process a received {@link PresentationAckMessage}. - * - * @param messageContext The message context containing a presentation acknowledgement message - * @returns proof record associated with the presentation acknowledgement message - * - */ - public async processAck(messageContext: InboundMessageContext): Promise { - const { message: presentationAckMessage, connection } = messageContext - - this.logger.debug(`Processing presentation ack with id ${presentationAckMessage.id}`) - - const proofRecord = await this.getByThreadAndConnectionId( - messageContext.agentContext, - presentationAckMessage.threadId, - connection?.id - ) - - // Assert - proofRecord.assertState(ProofState.PresentationSent) - this.connectionService.assertConnectionOrServiceDecorator(messageContext, { - previousReceivedMessage: proofRecord.requestMessage, - previousSentMessage: proofRecord.presentationMessage, - }) - - // Update record - await this.updateState(messageContext.agentContext, proofRecord, ProofState.Done) - - return proofRecord - } - - /** - * Process a received {@link PresentationProblemReportMessage}. - * - * @param messageContext The message context containing a presentation problem report message - * @returns proof record associated with the presentation acknowledgement message - * - */ - public async processProblemReport( - messageContext: InboundMessageContext - ): Promise { - const { message: presentationProblemReportMessage } = messageContext - - const connection = messageContext.assertReadyConnection() - - this.logger.debug(`Processing problem report with id ${presentationProblemReportMessage.id}`) - - const proofRecord = await this.getByThreadAndConnectionId( - messageContext.agentContext, - presentationProblemReportMessage.threadId, - connection?.id - ) - - proofRecord.errorMessage = `${presentationProblemReportMessage.description.code}: ${presentationProblemReportMessage.description.en}` - await this.update(messageContext.agentContext, proofRecord) - return proofRecord - } - - public async generateProofRequestNonce(agentContext: AgentContext) { - return agentContext.wallet.generateNonce() - } - - /** - * Create a {@link ProofRequest} from a presentation proposal. This method can be used to create the - * proof request from a received proposal for use in {@link ProofService.createRequestAsResponse} - * - * @param presentationProposal The presentation proposal to create a proof request from - * @param config Additional configuration to use for the proof request - * @returns proof request object - * - */ - public async createProofRequestFromProposal( - agentContext: AgentContext, - presentationProposal: PresentationPreview, - config: { name: string; version: string; nonce?: string } - ): Promise { - const nonce = config.nonce ?? (await this.generateProofRequestNonce(agentContext)) - - const proofRequest = new ProofRequest({ - name: config.name, - version: config.version, - nonce, - }) - - /** - * Create mapping of attributes by referent. This required the - * attributes to come from the same credential. - * @see https://github.com/hyperledger/aries-rfcs/blob/master/features/0037-present-proof/README.md#referent - * - * { - * "referent1": [Attribute1, Attribute2], - * "referent2": [Attribute3] - * } - */ - const attributesByReferent: Record = {} - for (const proposedAttributes of presentationProposal.attributes) { - if (!proposedAttributes.referent) proposedAttributes.referent = uuid() - - const referentAttributes = attributesByReferent[proposedAttributes.referent] - - // Referent key already exist, add to list - if (referentAttributes) { - referentAttributes.push(proposedAttributes) - } - // Referent key does not exist yet, create new entry - else { - attributesByReferent[proposedAttributes.referent] = [proposedAttributes] - } - } - - // Transform attributes by referent to requested attributes - for (const [referent, proposedAttributes] of Object.entries(attributesByReferent)) { - // Either attributeName or attributeNames will be undefined - const attributeName = proposedAttributes.length == 1 ? proposedAttributes[0].name : undefined - const attributeNames = proposedAttributes.length > 1 ? proposedAttributes.map((a) => a.name) : undefined - - const requestedAttribute = new ProofAttributeInfo({ - name: attributeName, - names: attributeNames, - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: proposedAttributes[0].credentialDefinitionId, - }), - ], - }) - - proofRequest.requestedAttributes.set(referent, requestedAttribute) - } - - this.logger.debug('proposal predicates', presentationProposal.predicates) - // Transform proposed predicates to requested predicates - for (const proposedPredicate of presentationProposal.predicates) { - const requestedPredicate = new ProofPredicateInfo({ - name: proposedPredicate.name, - predicateType: proposedPredicate.predicate, - predicateValue: proposedPredicate.threshold, - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: proposedPredicate.credentialDefinitionId, - }), - ], - }) - - proofRequest.requestedPredicates.set(uuid(), requestedPredicate) - } - - return proofRequest - } - - /** - * Retrieves the linked attachments for an {@link indyProofRequest} - * @param indyProofRequest The proof request for which the linked attachments have to be found - * @param requestedCredentials The requested credentials - * @returns a list of attachments that are linked to the requested credentials - */ - public async getRequestedAttachmentsForRequestedCredentials( - agentContext: AgentContext, - indyProofRequest: ProofRequest, - requestedCredentials: RequestedCredentials - ): Promise { - const attachments: Attachment[] = [] - const credentialIds = new Set() - const requestedAttributesNames: (string | undefined)[] = [] - - // Get the credentialIds if it contains a hashlink - for (const [referent, requestedAttribute] of Object.entries(requestedCredentials.requestedAttributes)) { - // Find the requested Attributes - const requestedAttributes = indyProofRequest.requestedAttributes.get(referent) as ProofAttributeInfo - - // List the requested attributes - requestedAttributesNames.push(...(requestedAttributes.names ?? [requestedAttributes.name])) - - //Get credentialInfo - if (!requestedAttribute.credentialInfo) { - const indyCredentialInfo = await this.indyHolderService.getCredential( - agentContext, - requestedAttribute.credentialId - ) - requestedAttribute.credentialInfo = JsonTransformer.fromJSON(indyCredentialInfo, IndyCredentialInfo) - } - - // Find the attributes that have a hashlink as a value - for (const attribute of Object.values(requestedAttribute.credentialInfo.attributes)) { - if (attribute.toLowerCase().startsWith('hl:')) { - credentialIds.add(requestedAttribute.credentialId) - } - } - } - - // Only continues if there is an attribute value that contains a hashlink - for (const credentialId of credentialIds) { - // Get the credentialRecord that matches the ID - - const credentialRecord = await this.credentialRepository.getSingleByQuery(agentContext, { - credentialIds: [credentialId], - }) - - if (credentialRecord.linkedAttachments) { - // Get the credentials that have a hashlink as value and are requested - const requestedCredentials = credentialRecord.credentialAttributes?.filter( - (credential) => - credential.value.toLowerCase().startsWith('hl:') && requestedAttributesNames.includes(credential.name) - ) - - // Get the linked attachments that match the requestedCredentials - const linkedAttachments = credentialRecord.linkedAttachments.filter((attachment) => - requestedCredentials?.map((credential) => credential.value.split(':')[1]).includes(attachment.id) - ) - - if (linkedAttachments) { - attachments.push(...linkedAttachments) - } - } - } - - return attachments.length ? attachments : undefined - } - - /** - * Create a {@link RetrievedCredentials} object. Given input proof request and presentation proposal, - * use credentials in the wallet to build indy requested credentials object for input to proof creation. - * If restrictions allow, self attested attributes will be used. - * - * - * @param proofRequest The proof request to build the requested credentials object from - * @param presentationProposal Optional presentation proposal to improve credential selection algorithm - * @returns RetrievedCredentials object - */ - public async getRequestedCredentialsForProofRequest( - agentContext: AgentContext, - proofRequest: ProofRequest, - config: { - presentationProposal?: PresentationPreview - filterByNonRevocationRequirements?: boolean - } = {} - ): Promise { - const retrievedCredentials = new RetrievedCredentials({}) - - for (const [referent, requestedAttribute] of proofRequest.requestedAttributes.entries()) { - let credentialMatch: IndyCredential[] = [] - const credentials = await this.getCredentialsForProofRequest(agentContext, proofRequest, referent) - - // If we have exactly one credential, or no proposal to pick preferences - // on the credentials to use, we will use the first one - if (credentials.length === 1 || !config.presentationProposal) { - credentialMatch = credentials - } - // If we have a proposal we will use that to determine the credentials to use - else { - const names = requestedAttribute.names ?? [requestedAttribute.name] - - // Find credentials that matches all parameters from the proposal - credentialMatch = credentials.filter((credential) => { - const { attributes, credentialDefinitionId } = credential.credentialInfo - - // Check if credentials matches all parameters from proposal - return names.every((name) => - config.presentationProposal?.attributes.find( - (a) => - a.name === name && - a.credentialDefinitionId === credentialDefinitionId && - (!a.value || a.value === attributes[name]) - ) - ) - }) - } - - retrievedCredentials.requestedAttributes[referent] = await Promise.all( - credentialMatch.map(async (credential: IndyCredential) => { - const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, { - proofRequest, - requestedItem: requestedAttribute, - credential, - }) - - return new RequestedAttribute({ - credentialId: credential.credentialInfo.referent, - revealed: true, - credentialInfo: credential.credentialInfo, - timestamp: deltaTimestamp, - revoked, - }) - }) - ) - - // We only attach revoked state if non-revocation is requested. So if revoked is true it means - // the credential is not applicable to the proof request - if (config.filterByNonRevocationRequirements) { - retrievedCredentials.requestedAttributes[referent] = retrievedCredentials.requestedAttributes[referent].filter( - (r) => !r.revoked - ) - } - } - - for (const [referent, requestedPredicate] of proofRequest.requestedPredicates.entries()) { - const credentials = await this.getCredentialsForProofRequest(agentContext, proofRequest, referent) - - retrievedCredentials.requestedPredicates[referent] = await Promise.all( - credentials.map(async (credential) => { - const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, { - proofRequest, - requestedItem: requestedPredicate, - credential, - }) - - return new RequestedPredicate({ - credentialId: credential.credentialInfo.referent, - credentialInfo: credential.credentialInfo, - timestamp: deltaTimestamp, - revoked, - }) - }) - ) - - // We only attach revoked state if non-revocation is requested. So if revoked is true it means - // the credential is not applicable to the proof request - if (config.filterByNonRevocationRequirements) { - retrievedCredentials.requestedPredicates[referent] = retrievedCredentials.requestedPredicates[referent].filter( - (r) => !r.revoked - ) - } - } - - return retrievedCredentials - } - - /** - * Takes a RetrievedCredentials object and auto selects credentials in a RequestedCredentials object - * - * Use the return value of this method as input to {@link ProofService.createPresentation} to - * automatically accept a received presentation request. - * - * @param retrievedCredentials The retrieved credentials object to get credentials from - * - * @returns RequestedCredentials - */ - public autoSelectCredentialsForProofRequest(retrievedCredentials: RetrievedCredentials): RequestedCredentials { - const requestedCredentials = new RequestedCredentials({}) - - Object.keys(retrievedCredentials.requestedAttributes).forEach((attributeName) => { - const attributeArray = retrievedCredentials.requestedAttributes[attributeName] - - if (attributeArray.length === 0) { - throw new AriesFrameworkError('Unable to automatically select requested attributes.') - } else { - requestedCredentials.requestedAttributes[attributeName] = attributeArray[0] - } - }) - - Object.keys(retrievedCredentials.requestedPredicates).forEach((attributeName) => { - if (retrievedCredentials.requestedPredicates[attributeName].length === 0) { - throw new AriesFrameworkError('Unable to automatically select requested predicates.') - } else { - requestedCredentials.requestedPredicates[attributeName] = - retrievedCredentials.requestedPredicates[attributeName][0] - } - }) - - return requestedCredentials - } - - /** - * Verify an indy proof object. Will also verify raw values against encodings. - * - * @param proofRequest The proof request to use for proof verification - * @param proofJson The proof object to verify - * @throws {Error} If the raw values do not match the encoded values - * @returns Boolean whether the proof is valid - * - */ - public async verifyProof( - agentContext: AgentContext, - proofJson: IndyProof, - proofRequest: ProofRequest - ): Promise { - const proof = JsonTransformer.fromJSON(proofJson, PartialProof) - - for (const [referent, attribute] of proof.requestedProof.revealedAttributes.entries()) { - if (!IndyCredentialUtils.checkValidEncoding(attribute.raw, attribute.encoded)) { - throw new PresentationProblemReportError( - `The encoded value for '${referent}' is invalid. ` + - `Expected '${IndyCredentialUtils.encode(attribute.raw)}'. ` + - `Actual '${attribute.encoded}'`, - { problemCode: PresentationProblemReportReason.Abandoned } - ) - } - } - - // TODO: pre verify proof json - // I'm not 100% sure how much indy does. Also if it checks whether the proof requests matches the proof - // @see https://github.com/hyperledger/aries-cloudagent-python/blob/master/aries_cloudagent/indy/sdk/verifier.py#L79-L164 - - const schemas = await this.getSchemas(agentContext, new Set(proof.identifiers.map((i) => i.schemaId))) - const credentialDefinitions = await this.getCredentialDefinitions( - agentContext, - new Set(proof.identifiers.map((i) => i.credentialDefinitionId)) - ) - - return await this.indyVerifierService.verifyProof(agentContext, { - proofRequest: proofRequest.toJSON(), - proof: proofJson, - schemas, - credentialDefinitions, - }) - } - - /** - * Retrieve all proof records - * - * @returns List containing all proof records - */ - public async getAll(agentContext: AgentContext): Promise { - return this.proofRepository.getAll(agentContext) - } - - /** - * Retrieve a proof record by id - * - * @param proofRecordId The proof record id - * @throws {RecordNotFoundError} If no record is found - * @return The proof record - * - */ - public async getById(agentContext: AgentContext, proofRecordId: string): Promise { - return this.proofRepository.getById(agentContext, proofRecordId) - } - - /** - * Retrieve a proof record by id - * - * @param proofRecordId The proof record id - * @return The proof record or null if not found - * - */ - public async findById(agentContext: AgentContext, proofRecordId: string): Promise { - return this.proofRepository.findById(agentContext, proofRecordId) - } - - /** - * Delete a proof record by id - * - * @param proofId the proof record id - */ - public async deleteById(agentContext: AgentContext, proofId: string) { - const proofRecord = await this.getById(agentContext, proofId) - return this.proofRepository.delete(agentContext, proofRecord) - } - - /** - * Retrieve a proof record by connection id and thread id - * - * @param connectionId The connection id - * @param threadId The thread id - * @throws {RecordNotFoundError} If no record is found - * @throws {RecordDuplicateError} If multiple records are found - * @returns The proof record - */ - public async getByThreadAndConnectionId( - agentContext: AgentContext, - threadId: string, - connectionId?: string - ): Promise { - return this.proofRepository.getSingleByQuery(agentContext, { threadId, connectionId }) - } - - public update(agentContext: AgentContext, proofRecord: ProofRecord) { - return this.proofRepository.update(agentContext, proofRecord) - } - - /** - * Create indy proof from a given proof request and requested credential object. - * - * @param proofRequest The proof request to create the proof for - * @param requestedCredentials The requested credentials object specifying which credentials to use for the proof - * @returns indy proof object - */ - private async createProof( - agentContext: AgentContext, - proofRequest: ProofRequest, - requestedCredentials: RequestedCredentials - ): Promise { - const credentialObjects = await Promise.all( - [ - ...Object.values(requestedCredentials.requestedAttributes), - ...Object.values(requestedCredentials.requestedPredicates), - ].map(async (c) => { - if (c.credentialInfo) { - return c.credentialInfo - } - const credentialInfo = await this.indyHolderService.getCredential(agentContext, c.credentialId) - return JsonTransformer.fromJSON(credentialInfo, IndyCredentialInfo) - }) - ) - - const schemas = await this.getSchemas(agentContext, new Set(credentialObjects.map((c) => c.schemaId))) - const credentialDefinitions = await this.getCredentialDefinitions( - agentContext, - new Set(credentialObjects.map((c) => c.credentialDefinitionId)) - ) - - return this.indyHolderService.createProof(agentContext, { - proofRequest: proofRequest.toJSON(), - requestedCredentials: requestedCredentials, - schemas, - credentialDefinitions, - }) - } - - private async getCredentialsForProofRequest( - agentContext: AgentContext, - proofRequest: ProofRequest, - attributeReferent: string - ): Promise { - const credentialsJson = await this.indyHolderService.getCredentialsForProofRequest(agentContext, { - proofRequest: proofRequest.toJSON(), - attributeReferent, - }) - - return JsonTransformer.fromJSON(credentialsJson, IndyCredential) as unknown as IndyCredential[] - } - - private async getRevocationStatusForRequestedItem( - agentContext: AgentContext, - { - proofRequest, - requestedItem, - credential, - }: { - proofRequest: ProofRequest - requestedItem: ProofAttributeInfo | ProofPredicateInfo - credential: IndyCredential - } - ) { - const requestNonRevoked = requestedItem.nonRevoked ?? proofRequest.nonRevoked - const credentialRevocationId = credential.credentialInfo.credentialRevocationId - const revocationRegistryId = credential.credentialInfo.revocationRegistryId - - // If revocation interval is present and the credential is revocable then fetch the revocation status of credentials for display - if (requestNonRevoked && credentialRevocationId && revocationRegistryId) { - this.logger.trace( - `Presentation is requesting proof of non revocation, getting revocation status for credential`, - { - requestNonRevoked, - credentialRevocationId, - revocationRegistryId, - } - ) - - // Note presentation from-to's vs ledger from-to's: https://github.com/hyperledger/indy-hipe/blob/master/text/0011-cred-revocation/README.md#indy-node-revocation-registry-intervals - const status = await this.indyRevocationService.getRevocationStatus( - agentContext, - credentialRevocationId, - revocationRegistryId, - requestNonRevoked - ) - - return status - } - - return { revoked: undefined, deltaTimestamp: undefined } - } - - /** - * Update the record to a new state and emit an state changed event. Also updates the record - * in storage. - * - * @param proofRecord The proof record to update the state for - * @param newState The state to update to - * - */ - private async updateState(agentContext: AgentContext, proofRecord: ProofRecord, newState: ProofState) { - const previousState = proofRecord.state - proofRecord.state = newState - await this.proofRepository.update(agentContext, proofRecord) - - this.emitStateChangedEvent(agentContext, proofRecord, previousState) - } - - private emitStateChangedEvent( - agentContext: AgentContext, - proofRecord: ProofRecord, - previousState: ProofState | null - ) { - const clonedProof = JsonTransformer.clone(proofRecord) - - this.eventEmitter.emit(agentContext, { - type: ProofEventTypes.ProofStateChanged, - payload: { - proofRecord: clonedProof, - previousState: previousState, - }, - }) - } - - /** - * Build schemas object needed to create and verify proof objects. - * - * Creates object with `{ schemaId: Schema }` mapping - * - * @param schemaIds List of schema ids - * @returns Object containing schemas for specified schema ids - * - */ - private async getSchemas(agentContext: AgentContext, schemaIds: Set) { - const schemas: { [key: string]: Schema } = {} - - for (const schemaId of schemaIds) { - const schema = await this.ledgerService.getSchema(agentContext, schemaId) - schemas[schemaId] = schema - } - - return schemas - } - - /** - * Build credential definitions object needed to create and verify proof objects. - * - * Creates object with `{ credentialDefinitionId: CredentialDefinition }` mapping - * - * @param credentialDefinitionIds List of credential definition ids - * @returns Object containing credential definitions for specified credential definition ids - * - */ - private async getCredentialDefinitions(agentContext: AgentContext, credentialDefinitionIds: Set) { - const credentialDefinitions: { [key: string]: CredDef } = {} - - for (const credDefId of credentialDefinitionIds) { - const credDef = await this.ledgerService.getCredentialDefinition(agentContext, credDefId) - credentialDefinitions[credDefId] = credDef - } - - return credentialDefinitions - } -} - -export interface ProofRequestTemplate { - proofRequest: ProofRequest - comment?: string -} - -export interface ProofProtocolMsgReturnType { - message: MessageType - proofRecord: ProofRecord -} diff --git a/packages/core/src/modules/proofs/services/index.ts b/packages/core/src/modules/proofs/services/index.ts deleted file mode 100644 index 0233c56665..0000000000 --- a/packages/core/src/modules/proofs/services/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ProofService' diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 5c2f404260..587443ea2d 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -82,6 +82,7 @@ export interface InitConfig { autoUpdateStorageOnStartup?: boolean } +export type ProtocolVersion = `${number}.${number}` export interface PlaintextMessage { '@type': string '@id': string diff --git a/packages/core/src/utils/__tests__/objectCheck.test.ts b/packages/core/src/utils/__tests__/objectCheck.test.ts new file mode 100644 index 0000000000..d2517c2d0e --- /dev/null +++ b/packages/core/src/utils/__tests__/objectCheck.test.ts @@ -0,0 +1,34 @@ +import { objectEquals } from '../objectCheck' + +describe('objectEquals', () => { + it('correctly evaluates whether two map objects are equal', () => { + const mapA: Map = new Map([ + ['foo', 1], + ['bar', 2], + ['baz', 3], + ]) + const mapB: Map = new Map([ + ['foo', 1], + ['bar', 2], + ['baz', 3], + ]) + let retVal = objectEquals(mapA, mapB) + + // if the order is different, maps still equal + const mapC: Map = new Map([ + ['foo', 1], + ['baz', 3], + ['bar', 2], + ]) + retVal = objectEquals(mapA, mapC) + expect(retVal).toBe(true) + + const mapD: Map = new Map([ + ['foo', 1], + ['bar', 2], + ['qux', 3], + ]) + retVal = objectEquals(mapA, mapD) + expect(retVal).toBe(false) + }) +}) diff --git a/packages/core/src/utils/indyProofRequest.ts b/packages/core/src/utils/indyProofRequest.ts index 6f128b4849..853bf4f742 100644 --- a/packages/core/src/utils/indyProofRequest.ts +++ b/packages/core/src/utils/indyProofRequest.ts @@ -1,4 +1,4 @@ -import type { ProofRequest } from '../modules/proofs/models/ProofRequest' +import type { ProofRequest } from '../modules/proofs/formats/indy/models/ProofRequest' import { AriesFrameworkError } from '../error/AriesFrameworkError' diff --git a/packages/core/src/utils/objectCheck.ts b/packages/core/src/utils/objectCheck.ts new file mode 100644 index 0000000000..fb02022690 --- /dev/null +++ b/packages/core/src/utils/objectCheck.ts @@ -0,0 +1,72 @@ +import { map } from 'rxjs' + +export function objectEquals(x: Map, y: Map): boolean { + if (x === null || x === undefined || y === null || y === undefined) { + return x === y + } + + // after this just checking type of one would be enough + if (x.constructor !== y.constructor) { + return false + } + // if they are functions, they should exactly refer to same one (because of closures) + if (x instanceof Function) { + return x === y + } + // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES) + if (x instanceof RegExp) { + return x === y + } + if (x === y || x.valueOf() === y.valueOf()) { + return true + } + + // if they are dates, they must had equal valueOf + if (x instanceof Date) { + return false + } + + // if they are strictly equal, they both need to be object at least + if (!(x instanceof Object)) { + return false + } + if (!(y instanceof Object)) { + return false + } + + const xkeys = Array.from(x.keys()) + const ykeys = Array.from(y.keys()) + if (!equalsIgnoreOrder(xkeys, ykeys)) { + return false + } + return ( + xkeys.every(function (i) { + return xkeys.indexOf(i) !== -1 + }) && + xkeys.every(function (xkey) { + // get the x map entries for this key + + const xval: any = x.get(xkey) + const yval: any = y.get(xkey) + + const a: Map = new Map([[xkey, xval]]) + if (a.size === 1) { + return xval === yval + } + // get the y map entries for this key + const b: Map = new Map([[xkey, yval]]) + return objectEquals(a, b) + }) + ) +} + +function equalsIgnoreOrder(a: string[], b: string[]): boolean { + if (a.length !== b.length) return false + const uniqueValues = new Set([...a, ...b]) + for (const v of uniqueValues) { + const aCount = a.filter((e) => e === v).length + const bCount = b.filter((e) => e === v).length + if (aCount !== bCount) return false + } + return true +} diff --git a/packages/core/tests/helpers.ts b/packages/core/tests/helpers.ts index 106d265949..69311c74ae 100644 --- a/packages/core/tests/helpers.ts +++ b/packages/core/tests/helpers.ts @@ -1,21 +1,21 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' import type { - AutoAcceptProof, + AcceptOfferOptions, BasicMessage, BasicMessageStateChangedEvent, ConnectionRecordProps, CredentialDefinitionTemplate, CredentialStateChangedEvent, InitConfig, - ProofAttributeInfo, - ProofPredicateInfo, ProofStateChangedEvent, SchemaTemplate, Wallet, } from '../src' -import type { AcceptOfferOptions } from '../src/modules/credentials' import type { IndyOfferCredentialFormat } from '../src/modules/credentials/formats/indy/IndyCredentialFormat' +import type { RequestProofOptions } from '../src/modules/proofs/ProofsApiOptions' +import type { ProofAttributeInfo, ProofPredicateInfo } from '../src/modules/proofs/formats/indy/models' +import type { AutoAcceptProof } from '../src/modules/proofs/models/ProofAutoAcceptType' import type { CredDef, Schema } from 'indy-sdk' import type { Observable } from 'rxjs' @@ -41,12 +41,7 @@ import { HandshakeProtocol, InjectionSymbols, LogLevel, - PredicateType, - PresentationPreview, - PresentationPreviewAttribute, - PresentationPreviewPredicate, ProofEventTypes, - ProofState, } from '../src' import { Key, KeyType } from '../src/crypto' import { Attachment, AttachmentData } from '../src/decorators/attachment/Attachment' @@ -57,6 +52,14 @@ import { OutOfBandRole } from '../src/modules/oob/domain/OutOfBandRole' import { OutOfBandState } from '../src/modules/oob/domain/OutOfBandState' import { OutOfBandInvitation } from '../src/modules/oob/messages' import { OutOfBandRecord } from '../src/modules/oob/repository' +import { PredicateType } from '../src/modules/proofs/formats/indy/models' +import { ProofProtocolVersion } from '../src/modules/proofs/models/ProofProtocolVersion' +import { ProofState } from '../src/modules/proofs/models/ProofState' +import { + PresentationPreview, + PresentationPreviewAttribute, + PresentationPreviewPredicate, +} from '../src/modules/proofs/protocol/v1/models/V1PresentationPreview' import { LinkedAttachment } from '../src/utils/LinkedAttachment' import { uuid } from '../src/utils/uuid' @@ -562,35 +565,58 @@ export async function presentProof({ verifierAgent.events.observable(ProofEventTypes.ProofStateChanged).subscribe(verifierReplay) holderAgent.events.observable(ProofEventTypes.ProofStateChanged).subscribe(holderReplay) - let verifierRecord = await verifierAgent.proofs.requestProof(verifierConnectionId, { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, - }) + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V1, + connectionId: verifierConnectionId, + proofFormats: { + indy: { + name: 'test-proof-request', + requestedAttributes: attributes, + requestedPredicates: predicates, + version: '1.0', + nonce: '947121108704767252195123', + }, + }, + } - let holderRecord = await waitForProofRecordSubject(holderReplay, { - threadId: verifierRecord.threadId, + let holderProofRecordPromise = waitForProofRecordSubject(holderReplay, { state: ProofState.RequestReceived, }) - const retrievedCredentials = await holderAgent.proofs.getRequestedCredentialsForProofRequest(holderRecord.id) - const requestedCredentials = holderAgent.proofs.autoSelectCredentialsForProofRequest(retrievedCredentials) - await holderAgent.proofs.acceptRequest(holderRecord.id, requestedCredentials) + let verifierRecord = await verifierAgent.proofs.requestProof(requestProofsOptions) + + let holderRecord = await holderProofRecordPromise + + const requestedCredentials = await holderAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: holderRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) - verifierRecord = await waitForProofRecordSubject(verifierReplay, { + const verifierProofRecordPromise = waitForProofRecordSubject(verifierReplay, { threadId: holderRecord.threadId, state: ProofState.PresentationReceived, }) + await holderAgent.proofs.acceptRequest({ + proofRecordId: holderRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + verifierRecord = await verifierProofRecordPromise + // assert presentation is valid expect(verifierRecord.isVerified).toBe(true) - verifierRecord = await verifierAgent.proofs.acceptPresentation(verifierRecord.id) - holderRecord = await waitForProofRecordSubject(holderReplay, { + holderProofRecordPromise = waitForProofRecordSubject(holderReplay, { threadId: holderRecord.threadId, state: ProofState.Done, }) + verifierRecord = await verifierAgent.proofs.acceptPresentation(verifierRecord.id) + holderRecord = await holderProofRecordPromise + return { verifierProof: verifierRecord, holderProof: holderRecord, diff --git a/packages/core/tests/proofs.test.ts b/packages/core/tests/proofs.test.ts deleted file mode 100644 index a09784167d..0000000000 --- a/packages/core/tests/proofs.test.ts +++ /dev/null @@ -1,370 +0,0 @@ -import type { Agent, ConnectionRecord, PresentationPreview } from '../src' -import type { CredDefId } from 'indy-sdk' - -import { - AttributeFilter, - JsonTransformer, - PredicateType, - PresentationMessage, - ProofAttributeInfo, - ProofPredicateInfo, - ProofRecord, - ProofState, - ProposePresentationMessage, - RequestPresentationMessage, -} from '../src' - -import { setupProofsTest, waitForProofRecord } from './helpers' -import testLogger from './logger' - -describe('Present Proof', () => { - let faberAgent: Agent - let aliceAgent: Agent - let credDefId: CredDefId - let faberConnection: ConnectionRecord - let aliceConnection: ConnectionRecord - let presentationPreview: PresentationPreview - - beforeAll(async () => { - testLogger.test('Initializing the agents') - ;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } = - await setupProofsTest('Faber agent', 'Alice agent')) - testLogger.test('Issuing second credential') - }) - - afterAll(async () => { - testLogger.test('Shutting down both agents') - await faberAgent.shutdown() - await faberAgent.wallet.delete() - await aliceAgent.shutdown() - await aliceAgent.wallet.delete() - }) - - test('Alice starts with proof proposal to Faber', async () => { - // Alice sends a presentation proposal to Faber - testLogger.test('Alice sends a presentation proposal to Faber') - let aliceProofRecord = await aliceAgent.proofs.proposeProof(aliceConnection.id, presentationPreview) - - // Faber waits for a presentation proposal from Alice - testLogger.test('Faber waits for a presentation proposal from Alice') - let faberProofRecord = await waitForProofRecord(faberAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.ProposalReceived, - }) - - expect(JsonTransformer.toJSON(aliceProofRecord)).toMatchObject({ - createdAt: expect.any(String), - id: expect.any(String), - proposalMessage: { - '@type': 'https://didcomm.org/present-proof/1.0/propose-presentation', - '@id': expect.any(String), - presentation_proposal: { - '@type': 'https://didcomm.org/present-proof/1.0/presentation-preview', - attributes: [ - { - name: 'name', - value: 'John', - }, - { - name: 'image_0', - value: undefined, - }, - ], - predicates: [ - { - name: 'age', - predicate: '>=', - threshold: 50, - }, - ], - }, - }, - }) - - // Faber accepts the presentation proposal from Alice - testLogger.test('Faber accepts the presentation proposal from Alice') - faberProofRecord = await faberAgent.proofs.acceptProposal(faberProofRecord.id) - - // Alice waits for presentation request from Faber - testLogger.test('Alice waits for presentation request from Faber') - aliceProofRecord = await waitForProofRecord(aliceAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.RequestReceived, - }) - - // Alice retrieves the requested credentials and accepts the presentation request - testLogger.test('Alice accepts presentation request from Faber') - const retrievedCredentials = await aliceAgent.proofs.getRequestedCredentialsForProofRequest(aliceProofRecord.id, { - filterByPresentationPreview: true, - }) - const requestedCredentials = aliceAgent.proofs.autoSelectCredentialsForProofRequest(retrievedCredentials) - await aliceAgent.proofs.acceptRequest(aliceProofRecord.id, requestedCredentials) - - // Faber waits for the presentation from Alice - testLogger.test('Faber waits for presentation from Alice') - faberProofRecord = await waitForProofRecord(faberAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.PresentationReceived, - }) - expect(JsonTransformer.toJSON(faberProofRecord)).toMatchObject({ - createdAt: expect.any(String), - state: ProofState.PresentationReceived, - isVerified: true, - presentationMessage: { - '@id': expect.any(String), - '@type': 'https://didcomm.org/present-proof/1.0/presentation', - 'presentations~attach': [ - { - '@id': 'libindy-presentation-0', - 'mime-type': 'application/json', - }, - ], - '~attach': [ - { - '@id': expect.any(String), - filename: 'picture-of-a-cat.png', - }, - ], - }, - }) - - expect(aliceProofRecord).toMatchObject({ - type: ProofRecord.name, - id: expect.any(String), - _tags: { - threadId: faberProofRecord.threadId, - connectionId: aliceProofRecord.connectionId, - state: ProofState.ProposalSent, - }, - }) - - // Faber accepts the presentation provided by Alice - testLogger.test('Faber accepts the presentation provided by Alice') - await faberAgent.proofs.acceptPresentation(faberProofRecord.id) - - // Alice waits until she received a presentation acknowledgement - testLogger.test('Alice waits until she receives a presentation acknowledgement') - aliceProofRecord = await waitForProofRecord(aliceAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.Done, - }) - - expect(faberProofRecord).toMatchObject({ - type: ProofRecord.name, - id: expect.any(String), - createdAt: expect.any(Date), - threadId: aliceProofRecord.threadId, - connectionId: expect.any(String), - isVerified: true, - state: ProofState.PresentationReceived, - proposalMessage: expect.any(ProposePresentationMessage), - requestMessage: expect.any(RequestPresentationMessage), - presentationMessage: expect.any(PresentationMessage), - }) - - expect(aliceProofRecord).toMatchObject({ - type: ProofRecord.name, - id: expect.any(String), - createdAt: expect.any(Date), - threadId: faberProofRecord.threadId, - connectionId: expect.any(String), - state: ProofState.Done, - proposalMessage: expect.any(ProposePresentationMessage), - requestMessage: expect.any(RequestPresentationMessage), - presentationMessage: expect.any(PresentationMessage), - }) - }) - - test('Faber starts with proof request to Alice', async () => { - // Sample attributes - const attributes = { - name: new ProofAttributeInfo({ - name: 'name', - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: credDefId, - }), - ], - }), - image_0: new ProofAttributeInfo({ - name: 'image_0', - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: credDefId, - }), - ], - }), - image_1: new ProofAttributeInfo({ - name: 'image_1', - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: credDefId, - }), - ], - }), - } - - // Sample predicates - const predicates = { - age: new ProofPredicateInfo({ - name: 'age', - predicateType: PredicateType.GreaterThanOrEqualTo, - predicateValue: 50, - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: credDefId, - }), - ], - }), - } - - // Faber sends a presentation request to Alice - testLogger.test('Faber sends a presentation request to Alice') - let faberProofRecord = await faberAgent.proofs.requestProof(faberConnection.id, { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, - }) - - // Alice waits for presentation request from Faber - testLogger.test('Alice waits for presentation request from Faber') - let aliceProofRecord = await waitForProofRecord(aliceAgent, { - threadId: faberProofRecord.threadId, - state: ProofState.RequestReceived, - }) - - expect(JsonTransformer.toJSON(aliceProofRecord)).toMatchObject({ - id: expect.any(String), - createdAt: expect.any(String), - requestMessage: { - '@id': expect.any(String), - '@type': 'https://didcomm.org/present-proof/1.0/request-presentation', - 'request_presentations~attach': [ - { - '@id': 'libindy-request-presentation-0', - 'mime-type': 'application/json', - }, - ], - }, - }) - - // Alice retrieves the requested credentials and accepts the presentation request - testLogger.test('Alice accepts presentation request from Faber') - const retrievedCredentials = await aliceAgent.proofs.getRequestedCredentialsForProofRequest(aliceProofRecord.id, { - filterByPresentationPreview: true, - }) - const requestedCredentials = aliceAgent.proofs.autoSelectCredentialsForProofRequest(retrievedCredentials) - await aliceAgent.proofs.acceptRequest(aliceProofRecord.id, requestedCredentials) - - // Faber waits until it receives a presentation from Alice - testLogger.test('Faber waits for presentation from Alice') - faberProofRecord = await waitForProofRecord(faberAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.PresentationReceived, - }) - - expect(faberProofRecord).toMatchObject({ - id: expect.any(String), - createdAt: expect.any(Date), - state: ProofState.PresentationReceived, - requestMessage: expect.any(RequestPresentationMessage), - isVerified: true, - presentationMessage: { - type: 'https://didcomm.org/present-proof/1.0/presentation', - id: expect.any(String), - presentationAttachments: [ - { - id: 'libindy-presentation-0', - mimeType: 'application/json', - }, - ], - appendedAttachments: [ - { - id: 'zQmfDXo7T3J43j3CTkEZaz7qdHuABhWktksZ7JEBueZ5zUS', - filename: 'picture-of-a-cat.png', - data: { - base64: expect.any(String), - }, - }, - { - id: 'zQmRHBT9rDs5QhsnYuPY3mNpXxgLcnNXkhjWJvTSAPMmcVd', - filename: 'picture-of-a-dog.png', - }, - ], - thread: { - threadId: aliceProofRecord.threadId, - }, - }, - }) - - // Faber accepts the presentation - testLogger.test('Faber accept the presentation from Alice') - await faberAgent.proofs.acceptPresentation(faberProofRecord.id) - - // Alice waits until she receives a presentation acknowledgement - testLogger.test('Alice waits for acceptance by Faber') - aliceProofRecord = await waitForProofRecord(aliceAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.Done, - }) - - expect(faberProofRecord).toMatchObject({ - type: ProofRecord.name, - id: expect.any(String), - createdAt: expect.any(Date), - threadId: aliceProofRecord.threadId, - connectionId: expect.any(String), - isVerified: true, - state: ProofState.PresentationReceived, - requestMessage: expect.any(RequestPresentationMessage), - presentationMessage: expect.any(PresentationMessage), - }) - - expect(aliceProofRecord).toMatchObject({ - type: ProofRecord.name, - id: expect.any(String), - createdAt: expect.any(Date), - threadId: faberProofRecord.threadId, - connectionId: expect.any(String), - state: ProofState.Done, - requestMessage: expect.any(RequestPresentationMessage), - presentationMessage: expect.any(PresentationMessage), - }) - }) - - test('an attribute group name matches with a predicate group name so an error is thrown', async () => { - // Age attribute - const attributes = { - age: new ProofAttributeInfo({ - name: 'age', - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: credDefId, - }), - ], - }), - } - - // Age predicate - const predicates = { - age: new ProofPredicateInfo({ - name: 'age', - predicateType: PredicateType.GreaterThanOrEqualTo, - predicateValue: 50, - restrictions: [ - new AttributeFilter({ - credentialDefinitionId: credDefId, - }), - ], - }), - } - - await expect( - faberAgent.proofs.requestProof(faberConnection.id, { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, - }) - ).rejects.toThrowError('The proof request contains duplicate predicates and attributes: age') - }) -}) diff --git a/packages/core/tests/connectionless-proofs.test.ts b/packages/core/tests/v1-connectionless-proofs.test.ts similarity index 75% rename from packages/core/tests/connectionless-proofs.test.ts rename to packages/core/tests/v1-connectionless-proofs.test.ts index ab49b8c838..f95f70ce04 100644 --- a/packages/core/tests/connectionless-proofs.test.ts +++ b/packages/core/tests/v1-connectionless-proofs.test.ts @@ -1,5 +1,8 @@ import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' import type { ProofStateChangedEvent } from '../src/modules/proofs' +import type { AcceptPresentationOptions, OutOfBandRequestOptions } from '../src/modules/proofs/ProofsApiOptions' +import type { IndyProofFormat } from '../src/modules/proofs/formats/indy/IndyProofFormat' +import type { V1ProofService } from '../src/modules/proofs/protocol/v1' import { Subject, ReplaySubject } from 'rxjs' @@ -11,6 +14,7 @@ import { Attachment, AttachmentData } from '../src/decorators/attachment/Attachm import { HandshakeProtocol } from '../src/modules/connections' import { V1CredentialPreview } from '../src/modules/credentials' import { + ProofProtocolVersion, PredicateType, ProofState, ProofAttributeInfo, @@ -77,45 +81,67 @@ describe('Present Proof', () => { }), } - // eslint-disable-next-line prefer-const - let { proofRecord: faberProofRecord, requestMessage } = await faberAgent.proofs.createOutOfBandRequest({ - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, + const outOfBandRequestOptions: OutOfBandRequestOptions<[IndyProofFormat], [V1ProofService]> = { + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'test-proof-request', + version: '1.0', + nonce: '12345678901', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + let aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + state: ProofState.RequestReceived, }) - await aliceAgent.receiveMessage(requestMessage.toJSON()) + // eslint-disable-next-line prefer-const + let { proofRecord: faberProofRecord, message } = await faberAgent.proofs.createOutOfBandRequest( + outOfBandRequestOptions + ) + + await aliceAgent.receiveMessage(message.toJSON()) testLogger.test('Alice waits for presentation request from Faber') - let aliceProofRecord = await waitForProofRecordSubject(aliceReplay, { - threadId: faberProofRecord.threadId, - state: ProofState.RequestReceived, - }) + let aliceProofRecord = await aliceProofRecordPromise testLogger.test('Alice accepts presentation request from Faber') - const retrievedCredentials = await aliceAgent.proofs.getRequestedCredentialsForProofRequest(aliceProofRecord.id, { - filterByPresentationPreview: true, + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, }) - const requestedCredentials = aliceAgent.proofs.autoSelectCredentialsForProofRequest(retrievedCredentials) - await aliceAgent.proofs.acceptRequest(aliceProofRecord.id, requestedCredentials) - testLogger.test('Faber waits for presentation from Alice') - faberProofRecord = await waitForProofRecordSubject(faberReplay, { + const faberProofRecordPromise = waitForProofRecordSubject(faberReplay, { threadId: aliceProofRecord.threadId, state: ProofState.PresentationReceived, }) + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + // assert presentation is valid expect(faberProofRecord.isVerified).toBe(true) + aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + // Faber accepts presentation await faberAgent.proofs.acceptPresentation(faberProofRecord.id) // Alice waits till it receives presentation ack - aliceProofRecord = await waitForProofRecordSubject(aliceReplay, { - threadId: aliceProofRecord.threadId, - state: ProofState.Done, - }) + aliceProofRecord = await aliceProofRecordPromise }) test('Faber starts with connection-less proof requests to Alice with auto-accept enabled', async () => { @@ -153,29 +179,36 @@ describe('Present Proof', () => { }), } - // eslint-disable-next-line prefer-const - let { proofRecord: faberProofRecord, requestMessage } = await faberAgent.proofs.createOutOfBandRequest( - { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, + const outOfBandRequestOptions: OutOfBandRequestOptions<[IndyProofFormat], [V1ProofService]> = { + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'test-proof-request', + version: '1.0', + nonce: '12345678901', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, }, - { - autoAcceptProof: AutoAcceptProof.ContentApproved, - } - ) - - await aliceAgent.receiveMessage(requestMessage.toJSON()) + autoAcceptProof: AutoAcceptProof.ContentApproved, + } - await waitForProofRecordSubject(aliceReplay, { - threadId: faberProofRecord.threadId, + const aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { state: ProofState.Done, }) - await waitForProofRecordSubject(faberReplay, { - threadId: faberProofRecord.threadId, + const faberProofRecordPromise = waitForProofRecordSubject(faberReplay, { state: ProofState.Done, }) + + // eslint-disable-next-line prefer-const + let { message } = await faberAgent.proofs.createOutOfBandRequest(outOfBandRequestOptions) + + await aliceAgent.receiveMessage(message.toJSON()) + + await aliceProofRecordPromise + + await faberProofRecordPromise }) test('Faber starts with connection-less proof requests to Alice with auto-accept enabled and both agents having a mediator', async () => { @@ -306,24 +339,37 @@ describe('Present Proof', () => { }), } - // eslint-disable-next-line prefer-const - let { proofRecord: faberProofRecord, requestMessage } = await faberAgent.proofs.createOutOfBandRequest( - { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, + const outOfBandRequestOptions: OutOfBandRequestOptions<[IndyProofFormat], [V1ProofService]> = { + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'test-proof-request', + version: '1.0', + nonce: '12345678901', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, }, - { - autoAcceptProof: AutoAcceptProof.ContentApproved, - } - ) + autoAcceptProof: AutoAcceptProof.ContentApproved, + } + + const aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + state: ProofState.Done, + }) + + const faberProofRecordPromise = waitForProofRecordSubject(faberReplay, { + state: ProofState.Done, + }) + + // eslint-disable-next-line prefer-const + let { message } = await faberAgent.proofs.createOutOfBandRequest(outOfBandRequestOptions) const mediationRecord = await faberAgent.mediationRecipient.findDefaultMediator() if (!mediationRecord) { throw new Error('Faber agent has no default mediator') } - expect(requestMessage).toMatchObject({ + expect(message).toMatchObject({ service: { recipientKeys: [expect.any(String)], routingKeys: mediationRecord.routingKeys, @@ -331,17 +377,11 @@ describe('Present Proof', () => { }, }) - await aliceAgent.receiveMessage(requestMessage.toJSON()) + await aliceAgent.receiveMessage(message.toJSON()) - await waitForProofRecordSubject(aliceReplay, { - threadId: faberProofRecord.threadId, - state: ProofState.Done, - }) + await aliceProofRecordPromise - await waitForProofRecordSubject(faberReplay, { - threadId: faberProofRecord.threadId, - state: ProofState.Done, - }) + await faberProofRecordPromise // We want to stop the mediator polling before the agent is shutdown. // FIXME: add a way to stop mediator polling from the public api, and make sure this is diff --git a/packages/core/tests/v1-indy-proofs.test.ts b/packages/core/tests/v1-indy-proofs.test.ts new file mode 100644 index 0000000000..85e694ead1 --- /dev/null +++ b/packages/core/tests/v1-indy-proofs.test.ts @@ -0,0 +1,589 @@ +import type { Agent, ConnectionRecord, ProofRecord } from '../src' +import type { + AcceptProposalOptions, + ProposeProofOptions, + RequestProofOptions, +} from '../src/modules/proofs/ProofsApiOptions' +import type { PresentationPreview } from '../src/modules/proofs/protocol/v1/models/V1PresentationPreview' +import type { CredDefId } from 'indy-sdk' + +import { + ProofAttributeInfo, + AttributeFilter, + ProofPredicateInfo, + PredicateType, +} from '../src/modules/proofs/formats/indy/models' +import { ProofProtocolVersion } from '../src/modules/proofs/models/ProofProtocolVersion' +import { ProofState } from '../src/modules/proofs/models/ProofState' +import { + V1ProposePresentationMessage, + V1RequestPresentationMessage, + V1PresentationMessage, +} from '../src/modules/proofs/protocol/v1/messages' +import { DidCommMessageRepository } from '../src/storage/didcomm' + +import { setupProofsTest, waitForProofRecord } from './helpers' +import testLogger from './logger' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let credDefId: CredDefId + let faberConnection: ConnectionRecord + let aliceConnection: ConnectionRecord + let faberProofRecord: ProofRecord + let aliceProofRecord: ProofRecord + let presentationPreview: PresentationPreview + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } = + await setupProofsTest('Faber agent', 'Alice agent')) + testLogger.test('Issuing second credential') + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test('Alice starts with proof proposal to Faber', async () => { + // Alice sends a presentation proposal to Faber + testLogger.test('Alice sends a presentation proposal to Faber') + + const proposeProofOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + name: 'abc', + version: '1.0', + nonce: '947121108704767252195126', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + } + + let faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + aliceProofRecord = await aliceAgent.proofs.proposeProof(proposeProofOptions) + + // Faber waits for a presentation proposal from Alice + testLogger.test('Faber waits for a presentation proposal from Alice') + faberProofRecord = await faberProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1ProposePresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/propose-presentation', + id: expect.any(String), + presentationProposal: { + type: 'https://didcomm.org/present-proof/1.0/presentation-preview', + attributes: [ + { + name: 'name', + credentialDefinitionId: presentationPreview.attributes[0].credentialDefinitionId, + value: 'John', + referent: '0', + }, + { + name: 'image_0', + credentialDefinitionId: presentationPreview.attributes[1].credentialDefinitionId, + }, + ], + predicates: [ + { + name: 'age', + credentialDefinitionId: presentationPreview.predicates[0].credentialDefinitionId, + predicate: '>=', + threshold: 50, + }, + ], + }, + }) + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + const acceptProposalOptions: AcceptProposalOptions = { + proofRecordId: faberProofRecord.id, + } + + let aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.RequestReceived, + }) + + // Faber accepts the presentation proposal from Alice + testLogger.test('Faber accepts presentation proposal from Alice') + faberProofRecord = await faberAgent.proofs.acceptProposal(acceptProposalOptions) + + // Alice waits for presentation request from Faber + testLogger.test('Alice waits for presentation request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/request-presentation', + id: expect.any(String), + requestPresentationAttachments: [ + { + id: 'libindy-request-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + thread: { + threadId: faberProofRecord.threadId, + }, + }) + + // Alice retrieves the requested credentials and accepts the presentation request + testLogger.test('Alice accepts presentation request from Faber') + + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + // Faber waits for the presentation from Alice + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + const presentation = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1PresentationMessage, + }) + + expect(presentation).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/presentation', + id: expect.any(String), + presentationAttachments: [ + { + id: 'libindy-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + appendedAttachments: [ + { + id: expect.any(String), + filename: expect.any(String), + data: { + base64: expect.any(String), + }, + }, + ], + thread: { + threadId: expect.any(String), + }, + }) + + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.PresentationReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts the presentation provided by Alice + testLogger.test('Faber accepts the presentation provided by Alice') + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits until she received a presentation acknowledgement + testLogger.test('Alice waits until she receives a presentation acknowledgement') + aliceProofRecord = await aliceProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: aliceProofRecord.threadId, + connectionId: expect.any(String), + isVerified: true, + state: ProofState.PresentationReceived, + }) + + expect(aliceProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: faberProofRecord.threadId, + connectionId: expect.any(String), + state: ProofState.Done, + }) + }) + + test('Faber starts with proof request to Alice', async () => { + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + image_0: new ProofAttributeInfo({ + name: 'image_0', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + // Sample predicates + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V1, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + let aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.RequestReceived, + }) + + // Faber sends a presentation request to Alice + testLogger.test('Faber sends a presentation request to Alice') + faberProofRecord = await faberAgent.proofs.requestProof(requestProofsOptions) + + // Alice waits for presentation request from Faber + testLogger.test('Alice waits for presentation request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/request-presentation', + id: expect.any(String), + requestPresentationAttachments: [ + { + id: 'libindy-request-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + }) + + expect(aliceProofRecord.id).not.toBeNull() + expect(aliceProofRecord).toMatchObject({ + threadId: aliceProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + // Alice retrieves the requested credentials and accepts the presentation request + testLogger.test('Alice accepts presentation request from Faber') + + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + // Faber waits until it receives a presentation from Alice + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + const presentation = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1PresentationMessage, + }) + + expect(presentation).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/presentation', + id: expect.any(String), + presentationAttachments: [ + { + id: 'libindy-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + appendedAttachments: [ + { + id: expect.any(String), + filename: expect.any(String), + data: { + base64: expect.any(String), + }, + }, + ], + thread: { + threadId: expect.any(String), + }, + }) + + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.PresentationReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts the presentation + testLogger.test('Faber accept the presentation from Alice') + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits until she receives a presentation acknowledgement + testLogger.test('Alice waits for acceptance by Faber') + aliceProofRecord = await aliceProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: aliceProofRecord.threadId, + connectionId: expect.any(String), + isVerified: true, + state: ProofState.PresentationReceived, + }) + + expect(aliceProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: faberProofRecord.threadId, + connectionId: expect.any(String), + state: ProofState.Done, + }) + }) + + test('an attribute group name matches with a predicate group name so an error is thrown', async () => { + // Age attribute + const attributes = { + age: new ProofAttributeInfo({ + name: 'age', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + // Age predicate + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V1, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + await expect(faberAgent.proofs.requestProof(requestProofsOptions)).rejects.toThrowError( + `The proof request contains duplicate predicates and attributes: age` + ) + }) + + test('Faber starts with proof request to Alice but gets Problem Reported', async () => { + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + image_0: new ProofAttributeInfo({ + name: 'image_0', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + // Sample predicates + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V1, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.RequestReceived, + }) + + // Faber sends a presentation request to Alice + testLogger.test('Faber sends a presentation request to Alice') + faberProofRecord = await faberAgent.proofs.requestProof(requestProofsOptions) + + // Alice waits for presentation request from Faber + testLogger.test('Alice waits for presentation request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V1RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/1.0/request-presentation', + id: expect.any(String), + requestPresentationAttachments: [ + { + id: 'libindy-request-presentation-0', + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + }) + + expect(aliceProofRecord.id).not.toBeNull() + expect(aliceProofRecord).toMatchObject({ + threadId: aliceProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V1, + }) + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Abandoned, + }) + + aliceProofRecord = await aliceAgent.proofs.sendProblemReport(aliceProofRecord.id, 'Problem inside proof request') + + faberProofRecord = await faberProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + threadId: aliceProofRecord.threadId, + state: ProofState.Abandoned, + protocolVersion: ProofProtocolVersion.V1, + }) + }) +}) diff --git a/packages/core/tests/v1-proofs-auto-accept.test.ts b/packages/core/tests/v1-proofs-auto-accept.test.ts new file mode 100644 index 0000000000..6b74330c4f --- /dev/null +++ b/packages/core/tests/v1-proofs-auto-accept.test.ts @@ -0,0 +1,253 @@ +import type { Agent, ConnectionRecord } from '../src' +import type { ProposeProofOptions, RequestProofOptions } from '../src/modules/proofs/ProofsApiOptions' +import type { PresentationPreview } from '../src/modules/proofs/protocol/v1/models/V1PresentationPreview' + +import { + AutoAcceptProof, + ProofState, + ProofAttributeInfo, + AttributeFilter, + ProofPredicateInfo, + PredicateType, +} from '../src' +import { ProofProtocolVersion } from '../src/modules/proofs/models/ProofProtocolVersion' + +import { setupProofsTest, waitForProofRecord } from './helpers' +import testLogger from './logger' + +describe('Auto accept present proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let credDefId: string + let faberConnection: ConnectionRecord + let aliceConnection: ConnectionRecord + let presentationPreview: PresentationPreview + + describe('Auto accept on `always`', () => { + beforeAll(async () => { + ;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } = + await setupProofsTest( + 'Faber Auto Accept Always Proofs', + 'Alice Auto Accept Always Proofs', + AutoAcceptProof.Always + )) + }) + afterAll(async () => { + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test('Alice starts with proof proposal to Faber, both with autoAcceptProof on `always`', async () => { + testLogger.test('Alice sends presentation proposal to Faber') + + const proposeProofOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + nonce: '58d223e5-fc4d-4448-b74c-5eb11c6b558f', + name: 'abc', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + } + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.Done, + }) + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.Done, + }) + + await aliceAgent.proofs.proposeProof(proposeProofOptions) + + testLogger.test('Faber waits for presentation from Alice') + await faberProofRecordPromise + + testLogger.test('Alice waits till it receives presentation ack') + await aliceProofRecordPromise + }) + + test('Faber starts with proof requests to Alice, both with autoAcceptProof on `always`', async () => { + testLogger.test('Faber sends presentation request to Alice') + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V1, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.Done, + }) + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.Done, + }) + + await faberAgent.proofs.requestProof(requestProofsOptions) + + testLogger.test('Faber waits for presentation from Alice') + + await faberProofRecordPromise + + // Alice waits till it receives presentation ack + await aliceProofRecordPromise + }) + }) + + describe('Auto accept on `contentApproved`', () => { + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } = + await setupProofsTest( + 'Faber Auto Accept Content Approved Proofs', + 'Alice Auto Accept Content Approved Proofs', + AutoAcceptProof.ContentApproved + )) + }) + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test('Alice starts with proof proposal to Faber, both with autoacceptproof on `contentApproved`', async () => { + testLogger.test('Alice sends presentation proposal to Faber') + + const proposal: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V1, + proofFormats: { + indy: { + nonce: '1298236324864', + name: 'abc', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + } + + let faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + const aliceProofRecord = await aliceAgent.proofs.proposeProof(proposal) + + testLogger.test('Faber waits for presentation proposal from Alice') + + await faberProofRecordPromise + + testLogger.test('Faber accepts presentation proposal from Alice') + + faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + testLogger.test('Faber waits for presentation from Alice') + + await faberProofRecordPromise + // Alice waits till it receives presentation ack + await aliceProofRecordPromise + }) + + test('Faber starts with proof requests to Alice, both with autoacceptproof on `contentApproved`', async () => { + testLogger.test('Faber sends presentation request to Alice') + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V1, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324866', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.Done, + }) + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.Done, + }) + + await faberAgent.proofs.requestProof(requestProofsOptions) + + testLogger.test('Faber waits for presentation from Alice') + await faberProofRecordPromise + + // Alice waits till it receives presentation ack + await aliceProofRecordPromise + }) + }) +}) diff --git a/packages/core/tests/v2-connectionless-proofs.test.ts b/packages/core/tests/v2-connectionless-proofs.test.ts new file mode 100644 index 0000000000..b426713e3e --- /dev/null +++ b/packages/core/tests/v2-connectionless-proofs.test.ts @@ -0,0 +1,386 @@ +import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' +import type { ProofStateChangedEvent } from '../src/modules/proofs' +import type { OutOfBandRequestOptions } from '../src/modules/proofs/ProofsApiOptions' +import type { IndyProofFormat } from '../src/modules/proofs/formats/indy/IndyProofFormat' +import type { V2ProofService } from '../src/modules/proofs/protocol/v2' + +import { Subject, ReplaySubject } from 'rxjs' + +import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' +import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' +import { V1CredentialPreview } from '../src' +import { Agent } from '../src/agent/Agent' +import { Attachment, AttachmentData } from '../src/decorators/attachment/Attachment' +import { HandshakeProtocol } from '../src/modules/connections/models/HandshakeProtocol' +import { + PredicateType, + ProofState, + ProofAttributeInfo, + AttributeFilter, + ProofPredicateInfo, + AutoAcceptProof, + ProofEventTypes, +} from '../src/modules/proofs' +import { ProofProtocolVersion } from '../src/modules/proofs/models/ProofProtocolVersion' +import { MediatorPickupStrategy } from '../src/modules/routing/MediatorPickupStrategy' +import { LinkedAttachment } from '../src/utils/LinkedAttachment' +import { uuid } from '../src/utils/uuid' + +import { + getBaseConfig, + issueCredential, + makeConnection, + prepareForIssuance, + setupProofsTest, + waitForProofRecordSubject, +} from './helpers' +import testLogger from './logger' + +describe('Present Proof', () => { + let agents: Agent[] + + afterEach(async () => { + for (const agent of agents) { + await agent.shutdown() + await agent.wallet.delete() + } + }) + + test('Faber starts with connection-less proof requests to Alice', async () => { + const { aliceAgent, faberAgent, aliceReplay, credDefId, faberReplay } = await setupProofsTest( + 'Faber connection-less Proofs', + 'Alice connection-less Proofs', + AutoAcceptProof.Never + ) + agents = [aliceAgent, faberAgent] + testLogger.test('Faber sends presentation request to Alice') + + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const outOfBandRequestOptions: OutOfBandRequestOptions<[IndyProofFormat], [V2ProofService]> = { + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'test-proof-request', + version: '1.0', + nonce: '12345678901', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + let aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + state: ProofState.RequestReceived, + }) + + // eslint-disable-next-line prefer-const + let { proofRecord: faberProofRecord, message } = await faberAgent.proofs.createOutOfBandRequest( + outOfBandRequestOptions + ) + + await aliceAgent.receiveMessage(message.toJSON()) + + testLogger.test('Alice waits for presentation request from Faber') + let aliceProofRecord = await aliceProofRecordPromise + + testLogger.test('Alice accepts presentation request from Faber') + + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + const faberProofRecordPromise = waitForProofRecordSubject(faberReplay, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + // assert presentation is valid + expect(faberProofRecord.isVerified).toBe(true) + + aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts presentation + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits till it receives presentation ack + aliceProofRecord = await aliceProofRecordPromise + }) + + test('Faber starts with connection-less proof requests to Alice with auto-accept enabled', async () => { + testLogger.test('Faber sends presentation request to Alice') + + const { aliceAgent, faberAgent, aliceReplay, credDefId, faberReplay } = await setupProofsTest( + 'Faber connection-less Proofs - Auto Accept', + 'Alice connection-less Proofs - Auto Accept', + AutoAcceptProof.Always + ) + + agents = [aliceAgent, faberAgent] + + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const outOfBandRequestOptions: OutOfBandRequestOptions<[IndyProofFormat], [V2ProofService]> = { + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'test-proof-request', + version: '1.0', + nonce: '12345678901', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + autoAcceptProof: AutoAcceptProof.ContentApproved, + } + + const aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + state: ProofState.Done, + }) + + const faberProofRecordPromise = waitForProofRecordSubject(faberReplay, { + state: ProofState.Done, + }) + + // eslint-disable-next-line prefer-const + let { message } = await faberAgent.proofs.createOutOfBandRequest(outOfBandRequestOptions) + + await aliceAgent.receiveMessage(message.toJSON()) + + await aliceProofRecordPromise + + await faberProofRecordPromise + }) + + test('Faber starts with connection-less proof requests to Alice with auto-accept enabled and both agents having a mediator', async () => { + testLogger.test('Faber sends presentation request to Alice') + + const credentialPreview = V1CredentialPreview.fromRecord({ + name: 'John', + age: '99', + }) + + const unique = uuid().substring(0, 4) + + const mediatorConfig = getBaseConfig(`Connectionless proofs with mediator Mediator-${unique}`, { + autoAcceptMediationRequests: true, + endpoints: ['rxjs:mediator'], + }) + + const faberMessages = new Subject() + const aliceMessages = new Subject() + const mediatorMessages = new Subject() + + const subjectMap = { + 'rxjs:mediator': mediatorMessages, + } + + // Initialize mediator + const mediatorAgent = new Agent(mediatorConfig.config, mediatorConfig.agentDependencies) + mediatorAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) + mediatorAgent.registerInboundTransport(new SubjectInboundTransport(mediatorMessages)) + await mediatorAgent.initialize() + + const faberMediationOutOfBandRecord = await mediatorAgent.oob.createInvitation({ + label: 'faber invitation', + handshakeProtocols: [HandshakeProtocol.Connections], + }) + + const aliceMediationOutOfBandRecord = await mediatorAgent.oob.createInvitation({ + label: 'alice invitation', + handshakeProtocols: [HandshakeProtocol.Connections], + }) + + const faberConfig = getBaseConfig(`Connectionless proofs with mediator Faber-${unique}`, { + autoAcceptProofs: AutoAcceptProof.Always, + mediatorConnectionsInvite: faberMediationOutOfBandRecord.outOfBandInvitation.toUrl({ + domain: 'https://example.com', + }), + mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, + }) + + const aliceConfig = getBaseConfig(`Connectionless proofs with mediator Alice-${unique}`, { + autoAcceptProofs: AutoAcceptProof.Always, + // logger: new TestLogger(LogLevel.test), + mediatorConnectionsInvite: aliceMediationOutOfBandRecord.outOfBandInvitation.toUrl({ + domain: 'https://example.com', + }), + mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, + }) + + const faberAgent = new Agent(faberConfig.config, faberConfig.agentDependencies) + faberAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) + faberAgent.registerInboundTransport(new SubjectInboundTransport(faberMessages)) + await faberAgent.initialize() + + const aliceAgent = new Agent(aliceConfig.config, aliceConfig.agentDependencies) + aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) + aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) + await aliceAgent.initialize() + + agents = [aliceAgent, faberAgent, mediatorAgent] + + const { definition } = await prepareForIssuance(faberAgent, ['name', 'age', 'image_0', 'image_1']) + + const [faberConnection, aliceConnection] = await makeConnection(faberAgent, aliceAgent) + expect(faberConnection.isReady).toBe(true) + expect(aliceConnection.isReady).toBe(true) + + await issueCredential({ + issuerAgent: faberAgent, + issuerConnectionId: faberConnection.id, + holderAgent: aliceAgent, + credentialTemplate: { + credentialDefinitionId: definition.id, + attributes: credentialPreview.attributes, + linkedAttachments: [ + new LinkedAttachment({ + name: 'image_0', + attachment: new Attachment({ + filename: 'picture-of-a-cat.png', + data: new AttachmentData({ base64: 'cGljdHVyZSBvZiBhIGNhdA==' }), + }), + }), + new LinkedAttachment({ + name: 'image_1', + attachment: new Attachment({ + filename: 'picture-of-a-dog.png', + data: new AttachmentData({ base64: 'UGljdHVyZSBvZiBhIGRvZw==' }), + }), + }), + ], + }, + }) + const faberReplay = new ReplaySubject() + const aliceReplay = new ReplaySubject() + + faberAgent.events.observable(ProofEventTypes.ProofStateChanged).subscribe(faberReplay) + aliceAgent.events.observable(ProofEventTypes.ProofStateChanged).subscribe(aliceReplay) + + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: definition.id, + }), + ], + }), + } + + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: definition.id, + }), + ], + }), + } + + const outOfBandRequestOptions: OutOfBandRequestOptions<[IndyProofFormat], [V2ProofService]> = { + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'test-proof-request', + version: '1.0', + nonce: '12345678901', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + autoAcceptProof: AutoAcceptProof.ContentApproved, + } + + const aliceProofRecordPromise = waitForProofRecordSubject(aliceReplay, { + state: ProofState.Done, + }) + + const faberProofRecordPromise = waitForProofRecordSubject(faberReplay, { + state: ProofState.Done, + }) + + // eslint-disable-next-line prefer-const + let { message } = await faberAgent.proofs.createOutOfBandRequest(outOfBandRequestOptions) + + const mediationRecord = await faberAgent.mediationRecipient.findDefaultMediator() + if (!mediationRecord) { + throw new Error('Faber agent has no default mediator') + } + + expect(message).toMatchObject({ + service: { + recipientKeys: [expect.any(String)], + routingKeys: mediationRecord.routingKeys, + serviceEndpoint: mediationRecord.endpoint, + }, + }) + + await aliceAgent.receiveMessage(message.toJSON()) + + await aliceProofRecordPromise + + await faberProofRecordPromise + }) +}) diff --git a/packages/core/tests/v2-indy-proofs.test.ts b/packages/core/tests/v2-indy-proofs.test.ts new file mode 100644 index 0000000000..4bfac719ec --- /dev/null +++ b/packages/core/tests/v2-indy-proofs.test.ts @@ -0,0 +1,538 @@ +import type { Agent, ConnectionRecord, ProofRecord } from '../src' +import type { + AcceptProposalOptions, + ProposeProofOptions, + RequestProofOptions, +} from '../src/modules/proofs/ProofsApiOptions' +import type { PresentationPreview } from '../src/modules/proofs/protocol/v1/models/V1PresentationPreview' +import type { CredDefId } from 'indy-sdk' + +import { AttributeFilter, PredicateType, ProofAttributeInfo, ProofPredicateInfo, ProofState } from '../src' +import { + V2_INDY_PRESENTATION_PROPOSAL, + V2_INDY_PRESENTATION_REQUEST, + V2_INDY_PRESENTATION, +} from '../src/modules/proofs/formats/ProofFormatConstants' +import { ProofProtocolVersion } from '../src/modules/proofs/models/ProofProtocolVersion' +import { + V2PresentationMessage, + V2ProposalPresentationMessage, + V2RequestPresentationMessage, +} from '../src/modules/proofs/protocol/v2/messages' +import { DidCommMessageRepository } from '../src/storage/didcomm' + +import { setupProofsTest, waitForProofRecord } from './helpers' +import testLogger from './logger' + +describe('Present Proof', () => { + let faberAgent: Agent + let aliceAgent: Agent + let credDefId: CredDefId + let aliceConnection: ConnectionRecord + let faberConnection: ConnectionRecord + let faberProofRecord: ProofRecord + let aliceProofRecord: ProofRecord + let presentationPreview: PresentationPreview + let didCommMessageRepository: DidCommMessageRepository + + beforeAll(async () => { + testLogger.test('Initializing the agents') + ;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } = + await setupProofsTest('Faber agent', 'Alice agent')) + }) + + afterAll(async () => { + testLogger.test('Shutting down both agents') + await faberAgent.shutdown() + await faberAgent.wallet.delete() + await aliceAgent.shutdown() + await aliceAgent.wallet.delete() + }) + + test('Alice starts with proof proposal to Faber', async () => { + // Alice sends a presentation proposal to Faber + testLogger.test('Alice sends a presentation proposal to Faber') + + const proposeProofOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + name: 'abc', + version: '1.0', + nonce: '947121108704767252195126', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + } + + let faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.ProposalReceived, + }) + + aliceProofRecord = await aliceAgent.proofs.proposeProof(proposeProofOptions) + + // Faber waits for a presentation proposal from Alice + testLogger.test('Faber waits for a presentation proposal from Alice') + faberProofRecord = await faberProofRecordPromise + + didCommMessageRepository = faberAgent.injectionContainer.resolve(DidCommMessageRepository) + + const proposal = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2ProposalPresentationMessage, + }) + + expect(proposal).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/propose-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_PROPOSAL, + }, + ], + proposalsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + }) + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.ProposalReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + const acceptProposalOptions: AcceptProposalOptions = { + proofRecordId: faberProofRecord.id, + } + + let aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.RequestReceived, + }) + + // Faber accepts the presentation proposal from Alice + testLogger.test('Faber accepts presentation proposal from Alice') + faberProofRecord = await faberAgent.proofs.acceptProposal(acceptProposalOptions) + + // Alice waits for presentation request from Faber + testLogger.test('Alice waits for presentation request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/request-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_REQUEST, + }, + ], + requestPresentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + thread: { + threadId: faberProofRecord.threadId, + }, + }) + + // Alice retrieves the requested credentials and accepts the presentation request + testLogger.test('Alice accepts presentation request from Faber') + + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + // Faber waits for the presentation from Alice + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + const presentation = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2PresentationMessage, + }) + + expect(presentation).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION, + }, + ], + presentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.PresentationReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts the presentation provided by Alice + testLogger.test('Faber accepts the presentation provided by Alice') + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits until she received a presentation acknowledgement + testLogger.test('Alice waits until she receives a presentation acknowledgement') + aliceProofRecord = await aliceProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: aliceProofRecord.threadId, + connectionId: expect.any(String), + isVerified: true, + state: ProofState.PresentationReceived, + }) + + expect(aliceProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: faberProofRecord.threadId, + connectionId: expect.any(String), + state: ProofState.Done, + }) + }) + + test('Faber starts with proof request to Alice', async () => { + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + image_0: new ProofAttributeInfo({ + name: 'image_0', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + // Sample predicates + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V2, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + let aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.RequestReceived, + }) + + // Faber sends a presentation request to Alice + testLogger.test('Faber sends a presentation request to Alice') + faberProofRecord = await faberAgent.proofs.requestProof(requestProofsOptions) + + // Alice waits for presentation request from Faber + testLogger.test('Alice waits for presentation request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/request-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_REQUEST, + }, + ], + requestPresentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + }) + + expect(aliceProofRecord.id).not.toBeNull() + expect(aliceProofRecord).toMatchObject({ + threadId: aliceProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + // Alice retrieves the requested credentials and accepts the presentation request + testLogger.test('Alice accepts presentation request from Faber') + + const requestedCredentials = await aliceAgent.proofs.autoSelectCredentialsForProofRequest({ + proofRecordId: aliceProofRecord.id, + config: { + filterByPresentationPreview: true, + }, + }) + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.PresentationReceived, + }) + + await aliceAgent.proofs.acceptRequest({ + proofRecordId: aliceProofRecord.id, + proofFormats: { indy: requestedCredentials.proofFormats.indy }, + }) + + // Faber waits until it receives a presentation from Alice + testLogger.test('Faber waits for presentation from Alice') + faberProofRecord = await faberProofRecordPromise + + const presentation = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2PresentationMessage, + }) + + expect(presentation).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION, + }, + ], + presentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + thread: { + threadId: faberProofRecord.threadId, + }, + }) + expect(faberProofRecord.id).not.toBeNull() + expect(faberProofRecord).toMatchObject({ + threadId: faberProofRecord.threadId, + state: ProofState.PresentationReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Done, + }) + + // Faber accepts the presentation + testLogger.test('Faber accept the presentation from Alice') + await faberAgent.proofs.acceptPresentation(faberProofRecord.id) + + // Alice waits until she receives a presentation acknowledgement + testLogger.test('Alice waits for acceptance by Faber') + aliceProofRecord = await aliceProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: aliceProofRecord.threadId, + connectionId: expect.any(String), + isVerified: true, + state: ProofState.PresentationReceived, + }) + + expect(aliceProofRecord).toMatchObject({ + // type: ProofRecord.name, + id: expect.any(String), + createdAt: expect.any(Date), + threadId: faberProofRecord.threadId, + connectionId: expect.any(String), + state: ProofState.Done, + }) + }) + + test('Faber starts with proof request to Alice but gets Problem Reported', async () => { + const attributes = { + name: new ProofAttributeInfo({ + name: 'name', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + image_0: new ProofAttributeInfo({ + name: 'image_0', + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + // Sample predicates + const predicates = { + age: new ProofPredicateInfo({ + name: 'age', + predicateType: PredicateType.GreaterThanOrEqualTo, + predicateValue: 50, + restrictions: [ + new AttributeFilter({ + credentialDefinitionId: credDefId, + }), + ], + }), + } + + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V2, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } + + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.RequestReceived, + }) + + // Faber sends a presentation request to Alice + testLogger.test('Faber sends a presentation request to Alice') + faberProofRecord = await faberAgent.proofs.requestProof(requestProofsOptions) + + // Alice waits for presentation request from Faber + testLogger.test('Alice waits for presentation request from Faber') + aliceProofRecord = await aliceProofRecordPromise + + const request = await didCommMessageRepository.findAgentMessage(faberAgent.context, { + associatedRecordId: faberProofRecord.id, + messageClass: V2RequestPresentationMessage, + }) + + expect(request).toMatchObject({ + type: 'https://didcomm.org/present-proof/2.0/request-presentation', + formats: [ + { + attachmentId: expect.any(String), + format: V2_INDY_PRESENTATION_REQUEST, + }, + ], + requestPresentationsAttach: [ + { + id: expect.any(String), + mimeType: 'application/json', + data: { + base64: expect.any(String), + }, + }, + ], + id: expect.any(String), + }) + + expect(aliceProofRecord.id).not.toBeNull() + expect(aliceProofRecord).toMatchObject({ + threadId: aliceProofRecord.threadId, + state: ProofState.RequestReceived, + protocolVersion: ProofProtocolVersion.V2, + }) + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + threadId: aliceProofRecord.threadId, + state: ProofState.Abandoned, + }) + + aliceProofRecord = await aliceAgent.proofs.sendProblemReport(aliceProofRecord.id, 'Problem inside proof request') + + faberProofRecord = await faberProofRecordPromise + + expect(faberProofRecord).toMatchObject({ + threadId: aliceProofRecord.threadId, + state: ProofState.Abandoned, + protocolVersion: ProofProtocolVersion.V2, + }) + }) +}) diff --git a/packages/core/tests/proofs-auto-accept.test.ts b/packages/core/tests/v2-proofs-auto-accept.test.ts similarity index 58% rename from packages/core/tests/proofs-auto-accept.test.ts rename to packages/core/tests/v2-proofs-auto-accept.test.ts index a990c3d070..9104d20bc0 100644 --- a/packages/core/tests/proofs-auto-accept.test.ts +++ b/packages/core/tests/v2-proofs-auto-accept.test.ts @@ -1,4 +1,6 @@ -import type { Agent, ConnectionRecord, PresentationPreview } from '../src' +import type { Agent, ConnectionRecord } from '../src' +import type { ProposeProofOptions, RequestProofOptions } from '../src/modules/proofs/ProofsApiOptions' +import type { PresentationPreview } from '../src/modules/proofs/protocol/v1/models/V1PresentationPreview' import { AutoAcceptProof, @@ -8,6 +10,7 @@ import { ProofPredicateInfo, PredicateType, } from '../src' +import { ProofProtocolVersion } from '../src/modules/proofs/models/ProofProtocolVersion' import { setupProofsTest, waitForProofRecord } from './helpers' import testLogger from './logger' @@ -29,7 +32,6 @@ describe('Auto accept present proof', () => { AutoAcceptProof.Always )) }) - afterAll(async () => { await faberAgent.shutdown() await faberAgent.wallet.delete() @@ -39,24 +41,40 @@ describe('Auto accept present proof', () => { test('Alice starts with proof proposal to Faber, both with autoAcceptProof on `always`', async () => { testLogger.test('Alice sends presentation proposal to Faber') - const aliceProofRecord = await aliceAgent.proofs.proposeProof(aliceConnection.id, presentationPreview) - testLogger.test('Faber waits for presentation from Alice') - await waitForProofRecord(faberAgent, { - threadId: aliceProofRecord.threadId, + const proposeProofOptions: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + nonce: '1298236324864', + name: 'abc', + version: '1.0', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + }, + }, + } + + const faberProofRecordPromise = waitForProofRecord(faberAgent, { state: ProofState.Done, }) - testLogger.test('Alice waits till it receives presentation ack') - await waitForProofRecord(aliceAgent, { - threadId: aliceProofRecord.threadId, + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { state: ProofState.Done, }) + + await aliceAgent.proofs.proposeProof(proposeProofOptions) + + testLogger.test('Faber waits for presentation from Alice') + await faberProofRecordPromise + + testLogger.test('Alice waits till it receives presentation ack') + await aliceProofRecordPromise }) test('Faber starts with proof requests to Alice, both with autoAcceptProof on `always`', async () => { testLogger.test('Faber sends presentation request to Alice') - const attributes = { name: new ProofAttributeInfo({ name: 'name', @@ -67,7 +85,6 @@ describe('Auto accept present proof', () => { ], }), } - const predicates = { age: new ProofPredicateInfo({ name: 'age', @@ -81,28 +98,40 @@ describe('Auto accept present proof', () => { }), } - const faberProofRecord = await faberAgent.proofs.requestProof(faberConnection.id, { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, - }) + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V2, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324864', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } - testLogger.test('Faber waits for presentation from Alice') - await waitForProofRecord(faberAgent, { - threadId: faberProofRecord.threadId, + const faberProofRecordPromise = waitForProofRecord(faberAgent, { state: ProofState.Done, }) - // Alice waits till it receives presentation ack - await waitForProofRecord(aliceAgent, { - threadId: faberProofRecord.threadId, + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { state: ProofState.Done, }) + + await faberAgent.proofs.requestProof(requestProofsOptions) + + testLogger.test('Faber waits for presentation from Alice') + await faberProofRecordPromise + // Alice waits till it receives presentation ack + await aliceProofRecordPromise }) }) describe('Auto accept on `contentApproved`', () => { beforeAll(async () => { + testLogger.test('Initializing the agents') ;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } = await setupProofsTest( 'Faber Auto Accept Content Approved Proofs', @@ -110,8 +139,8 @@ describe('Auto accept present proof', () => { AutoAcceptProof.ContentApproved )) }) - afterAll(async () => { + testLogger.test('Shutting down both agents') await faberAgent.shutdown() await faberAgent.wallet.delete() await aliceAgent.shutdown() @@ -120,33 +149,52 @@ describe('Auto accept present proof', () => { test('Alice starts with proof proposal to Faber, both with autoacceptproof on `contentApproved`', async () => { testLogger.test('Alice sends presentation proposal to Faber') - const aliceProofRecord = await aliceAgent.proofs.proposeProof(aliceConnection.id, presentationPreview) - testLogger.test('Faber waits for presentation proposal from Alice') - const faberProofRecord = await waitForProofRecord(faberAgent, { - threadId: aliceProofRecord.threadId, + const proposal: ProposeProofOptions = { + connectionId: aliceConnection.id, + protocolVersion: ProofProtocolVersion.V2, + proofFormats: { + indy: { + nonce: '1298236324864', + attributes: presentationPreview.attributes, + predicates: presentationPreview.predicates, + name: 'abc', + version: '1.0', + }, + }, + } + + let faberProofRecordPromise = waitForProofRecord(faberAgent, { state: ProofState.ProposalReceived, }) + const aliceProofRecord = await aliceAgent.proofs.proposeProof(proposal) + + testLogger.test('Faber waits for presentation proposal from Alice') + + await faberProofRecordPromise + testLogger.test('Faber accepts presentation proposal from Alice') - await faberAgent.proofs.acceptProposal(faberProofRecord.id) - testLogger.test('Faber waits for presentation from Alice') - await waitForProofRecord(faberAgent, { + faberProofRecordPromise = waitForProofRecord(faberAgent, { threadId: aliceProofRecord.threadId, state: ProofState.Done, }) - // Alice waits till it receives presentation ack - await waitForProofRecord(aliceAgent, { + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { threadId: aliceProofRecord.threadId, state: ProofState.Done, }) + + testLogger.test('Faber waits for presentation from Alice') + + await faberProofRecordPromise + // Alice waits till it receives presentation ack + await aliceProofRecordPromise }) test('Faber starts with proof requests to Alice, both with autoacceptproof on `contentApproved`', async () => { testLogger.test('Faber sends presentation request to Alice') - const attributes = { name: new ProofAttributeInfo({ name: 'name', @@ -157,7 +205,6 @@ describe('Auto accept present proof', () => { ], }), } - const predicates = { age: new ProofPredicateInfo({ name: 'age', @@ -171,36 +218,35 @@ describe('Auto accept present proof', () => { }), } - const faberProofRecord = await faberAgent.proofs.requestProof(faberConnection.id, { - name: 'test-proof-request', - requestedAttributes: attributes, - requestedPredicates: predicates, - }) + const requestProofsOptions: RequestProofOptions = { + protocolVersion: ProofProtocolVersion.V2, + connectionId: faberConnection.id, + proofFormats: { + indy: { + name: 'proof-request', + version: '1.0', + nonce: '1298236324866', + requestedAttributes: attributes, + requestedPredicates: predicates, + }, + }, + } - testLogger.test('Alice waits for presentation request from Faber') - const aliceProofRecord = await waitForProofRecord(aliceAgent, { - threadId: faberProofRecord.threadId, - state: ProofState.RequestReceived, + const faberProofRecordPromise = waitForProofRecord(faberAgent, { + state: ProofState.Done, }) - testLogger.test('Alice accepts presentation request from Faber') - const retrievedCredentials = await aliceAgent.proofs.getRequestedCredentialsForProofRequest(aliceProofRecord.id, { - filterByPresentationPreview: true, + const aliceProofRecordPromise = waitForProofRecord(aliceAgent, { + state: ProofState.Done, }) - const requestedCredentials = aliceAgent.proofs.autoSelectCredentialsForProofRequest(retrievedCredentials) - await aliceAgent.proofs.acceptRequest(aliceProofRecord.id, requestedCredentials) + + await faberAgent.proofs.requestProof(requestProofsOptions) testLogger.test('Faber waits for presentation from Alice') - await waitForProofRecord(faberAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.Done, - }) + await faberProofRecordPromise // Alice waits till it receives presentation ack - await waitForProofRecord(aliceAgent, { - threadId: aliceProofRecord.threadId, - state: ProofState.Done, - }) + await aliceProofRecordPromise }) }) }) diff --git a/yarn.lock b/yarn.lock index a40ba06ff4..45e32f5b8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,292 +27,288 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: - "@babel/highlight" "^7.16.7" + "@babel/highlight" "^7.18.6" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" - integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== "@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.12.tgz#b4eb2d7ebc3449b062381644c93050db545b70ee" - integrity sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59" + integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g== dependencies: "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.12" - "@babel/helper-compilation-targets" "^7.17.10" - "@babel/helper-module-transforms" "^7.17.12" - "@babel/helpers" "^7.17.9" - "@babel/parser" "^7.17.12" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.12" - "@babel/types" "^7.17.12" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.9" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.9" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.1" semver "^6.3.0" -"@babel/generator@^7.17.12", "@babel/generator@^7.5.0", "@babel/generator@^7.7.2": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.12.tgz#5970e6160e9be0428e02f4aba62d8551ec366cc8" - integrity sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw== +"@babel/generator@^7.18.9", "@babel/generator@^7.5.0", "@babel/generator@^7.7.2": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5" + integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug== dependencies: - "@babel/types" "^7.17.12" - "@jridgewell/gen-mapping" "^0.3.0" + "@babel/types" "^7.18.9" + "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" - integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz#09c63106d47af93cf31803db6bc49fef354e2ebe" - integrity sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ== +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-validator-option" "^7.16.7" + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" browserslist "^4.20.2" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz#d4f8393fc4838cbff6b7c199af5229aee16d07cf" - integrity sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew== +"@babel/helper-create-class-features-plugin@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz#d802ee16a64a9e824fcbf0a2ffc92f19d58550ce" + integrity sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-member-expression-to-functions" "^7.17.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" -"@babel/helper-create-regexp-features-plugin@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz#bb37ca467f9694bbe55b884ae7a5cc1e0084e4fd" - integrity sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw== +"@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c" + integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - regexpu-core "^5.0.1" + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.1.0" -"@babel/helper-define-polyfill-provider@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" - integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== +"@babel/helper-define-polyfill-provider@^0.3.1", "@babel/helper-define-polyfill-provider@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073" + integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg== dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" debug "^4.1.1" lodash.debounce "^4.0.8" resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-explode-assignable-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" - integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" - integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/types" "^7.17.0" - -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-member-expression-to-functions@^7.16.7", "@babel/helper-member-expression-to-functions@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" - integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== - dependencies: - "@babel/types" "^7.17.0" - -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-transforms@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz#bec00139520cb3feb078ef7a4578562480efb77e" - integrity sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.12" - "@babel/types" "^7.17.12" - -"@babel/helper-optimise-call-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" - integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" - integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== - -"@babel/helper-replace-supers@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" - integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-simple-access@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" - integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== dependencies: - "@babel/types" "^7.17.0" - -"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - -"@babel/helpers@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a" - integrity sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.9" - "@babel/types" "^7.17.0" - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" - integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" + integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6" + integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818" + integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.12.tgz#36c2ed06944e3691ba82735fc4cf62d12d491a23" - integrity sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539" + integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg== "@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.1.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz#84f65c0cc247d46f40a6da99aadd6438315d80a4" - integrity sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-proposal-export-default-from@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.17.12.tgz#df785e638618d8ffa14e08c78c44d9695d083b73" - integrity sha512-LpsTRw725eBAXXKUOnJJct+SEaOzwR78zahcLuripD2+dKc2Sj+8Q2DzA+GC/jOpOu/KlDXuxrzG214o1zTauQ== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.9.tgz#9dfad26452e53cae8f045c6153e82dc50e9bee89" + integrity sha512-1qtsLNCDm5awHLIt+2qAFDi31XC94r4QepMQcOosC7FpY6O+Bgay5f2IyAQt2wvm1TARumpFprnQt5pTIJ9nUg== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-export-default-from" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-default-from" "^7.18.6" "@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.1.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz#1e93079bbc2cbc756f6db6a1925157c4a92b94be" - integrity sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" "@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz#f94a91715a7f2f8cfb3c06af820c776440bc0148" - integrity sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7" + integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-compilation-targets" "^7.17.10" - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/compat-data" "^7.18.8" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.17.12" + "@babel/plugin-transform-parameters" "^7.18.8" "@babel/plugin-proposal-optional-catch-binding@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" - integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-proposal-optional-chaining@^7.0.0", "@babel/plugin-proposal-optional-chaining@^7.1.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz#f96949e9bacace3a9066323a5cf90cfb9de67174" - integrity sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993" + integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-async-generators@^7.8.4": @@ -343,19 +339,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-default-from@^7.0.0", "@babel/plugin-syntax-export-default-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.7.tgz#fa89cf13b60de2c3f79acdc2b52a21174c6de060" - integrity sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA== +"@babel/plugin-syntax-export-default-from@^7.0.0", "@babel/plugin-syntax-export-default-from@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz#8df076711a4818c4ce4f23e61d622b0ba2ff84bc" + integrity sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.17.12", "@babel/plugin-syntax-flow@^7.2.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.17.12.tgz#23d852902acd19f42923fca9d0f196984d124e73" - integrity sha512-B8QIgBvkIG6G2jgsOHQUist7Sm0EBLDCx8sen072IwqNuzMegZNXrYnSv77cYzA8mLDZAfQYqsLIhimiP1s2HQ== +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.18.6", "@babel/plugin-syntax-flow@^7.2.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz#774d825256f2379d06139be0c723c4dd444f3ca1" + integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" @@ -371,12 +367,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47" - integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog== +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -427,266 +423,267 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.17.12", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz#b54fc3be6de734a56b87508f99d6428b5b605a7b" - integrity sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw== +"@babel/plugin-syntax-typescript@^7.18.6", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-arrow-functions@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz#dddd783b473b1b1537ef46423e3944ff24898c45" - integrity sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe" + integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-block-scoped-functions@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" - integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-block-scoping@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz#68fc3c4b3bb7dfd809d97b7ed19a584052a2725c" - integrity sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d" + integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-transform-classes@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz#da889e89a4d38375eeb24985218edeab93af4f29" - integrity sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz#90818efc5b9746879b869d5ce83eb2aa48bbc3da" + integrity sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz#bca616a83679698f3258e892ed422546e531387f" - integrity sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e" + integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-transform-destructuring@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz#0861d61e75e2401aca30f2570d46dfc85caacf35" - integrity sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz#68906549c021cb231bee1db21d3b5b095f8ee292" + integrity sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-transform-exponentiation-operator@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" - integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.17.12.tgz#5e070f99a4152194bd9275de140e83a92966cab3" - integrity sha512-g8cSNt+cHCpG/uunPQELdq/TeV3eg1OLJYwxypwHtAWo9+nErH3lQx9CSO2uI9lF74A0mR0t4KoMjs1snSgnTw== +"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.18.9.tgz#5b4cc521426263b5ce08893a2db41097ceba35bf" + integrity sha512-+G6rp2zRuOAInY5wcggsx4+QVao1qPM0osC9fTUVlAV3zOrzTCnrMAFVnR6+a3T8wz1wFIH7KhYMcMB3u1n80A== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-flow" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-flow" "^7.18.6" "@babel/plugin-transform-for-of@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz#5397c22554ec737a27918e7e7e0e7b679b05f5ec" - integrity sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg== + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-function-name@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" - integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== dependencies: - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-transform-literals@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz#97131fbc6bbb261487105b4b3edbf9ebf9c830ae" - integrity sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" "@babel/plugin-transform-member-expression-literals@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" - integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.1.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz#37691c7404320d007288edd5a2d8600bcef61c34" - integrity sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883" + integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== dependencies: - "@babel/helper-module-transforms" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-object-assign@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.16.7.tgz#5fe08d63dccfeb6a33aa2638faf98e5c584100f8" - integrity sha512-R8mawvm3x0COTJtveuoqZIjNypn2FjfvXZr4pSQ8VhEFBuQGBz4XhHasZtHXjgXU4XptZ4HtGof3NoYc93ZH9Q== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.18.6.tgz#7830b4b6f83e1374a5afb9f6111bcfaea872cdd2" + integrity sha512-mQisZ3JfqWh2gVXvfqYCAAyRs6+7oev+myBsTwW5RnPhYXOTuCEw2oe3YgxlXMViXUS53lG8koulI7mJ+8JE+A== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-object-super@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" - integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766" - integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA== +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" + integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-property-literals@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" - integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-react-display-name@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" - integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-react-jsx-self@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.17.12.tgz#7f2e9b8c08d6a4204733138d8c29d4dba4bb66c2" - integrity sha512-7S9G2B44EnYOx74mue02t1uD8ckWZ/ee6Uz/qfdzc35uWHX5NgRy9i+iJSb2LFRgMd+QV9zNcStQaazzzZ3n3Q== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7" + integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-react-jsx-source@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz#1879c3f23629d287cc6186a6c683154509ec70c0" - integrity sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz#06e9ae8a14d2bc19ce6e3c447d842032a50598fc" + integrity sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-react-jsx@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.12.tgz#2aa20022709cd6a3f40b45d60603d5f269586dba" - integrity sha512-Lcaw8bxd1DKht3thfD4A12dqo1X16he1Lm8rIv8sTwjAYNInRS1qHa9aJoqvzpscItXvftKDCfaEQzwoVyXpEQ== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz#2721e96d31df96e3b7ad48ff446995d26bc028ff" + integrity sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-jsx" "^7.17.12" - "@babel/types" "^7.17.12" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.18.6" "@babel/plugin-transform-regenerator@^7.0.0": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz#0a33c3a61cf47f45ed3232903683a0afd2d3460c" - integrity sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73" + integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== dependencies: + "@babel/helper-plugin-utils" "^7.18.6" regenerator-transform "^0.15.0" "@babel/plugin-transform-runtime@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.12.tgz#5dc79735c4038c6f4fc0490f68f2798ce608cadd" - integrity sha512-xsl5MeGjWnmV6Ui9PfILM2+YRpa3GqLOrczPpXV3N2KCgQGU+sU8OfzuMbjkIdfvZEZIm+3y0V7w58sk0SGzlw== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.17.12" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz#d9e4b1b25719307bfafbf43065ed7fb3a83adb8f" + integrity sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.9" + babel-plugin-polyfill-corejs2 "^0.3.1" + babel-plugin-polyfill-corejs3 "^0.5.2" + babel-plugin-polyfill-regenerator "^0.3.1" semver "^6.3.0" "@babel/plugin-transform-shorthand-properties@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" - integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-spread@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz#c112cad3064299f03ea32afed1d659223935d1f5" - integrity sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz#6ea7a6297740f381c540ac56caf75b05b74fb664" + integrity sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" "@babel/plugin-transform-sticky-regex@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" - integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-template-literals@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz#4aec0a18f39dd86c442e1d077746df003e362c6e" - integrity sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-typescript@^7.17.12", "@babel/plugin-transform-typescript@^7.5.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.17.12.tgz#9654587131bc776ff713218d929fa9a2e98ca16d" - integrity sha512-ICbXZqg6hgenjmwciVI/UfqZtExBrZOrS8sLB5mTHGO/j08Io3MmooULBiijWk9JBknjM3CbbtTc/0ZsqLrjXQ== +"@babel/plugin-transform-typescript@^7.18.6", "@babel/plugin-transform-typescript@^7.5.0": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.8.tgz#303feb7a920e650f2213ef37b36bbf327e6fa5a0" + integrity sha512-p2xM8HI83UObjsZGofMV/EdYjamsDm6MoN3hXPYIT0+gxIoopE+B7rPYKAxfrz9K9PK7JafTTjqYC6qipLExYA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.12" - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/plugin-syntax-typescript" "^7.17.12" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-typescript" "^7.18.6" "@babel/plugin-transform-unicode-regex@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" - integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/preset-flow@^7.0.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.17.12.tgz#664a5df59190260939eee862800a255bef3bd66f" - integrity sha512-7QDz7k4uiaBdu7N89VKjUn807pJRXmdirQu0KyR9LXnQrr5Jt41eIMKTS7ljej+H29erwmMrwq9Io9mJHLI3Lw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.18.6.tgz#83f7602ba566e72a9918beefafef8ef16d2810cb" + integrity sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-flow-strip-types" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-flow-strip-types" "^7.18.6" "@babel/preset-typescript@^7.1.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.17.12.tgz#40269e0a0084d56fc5731b6c40febe1c9a4a3e8c" - integrity sha512-S1ViF8W2QwAKUGJXxP9NAfNaqGDdEBJKpYkxHf5Yy2C4NPPzXGeR3Lhk7G8xJaaLcFTRfNjVbtbVtm8Gb0mqvg== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399" + integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ== dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-typescript" "^7.17.12" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-typescript" "^7.18.6" "@babel/register@^7.0.0": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.17.7.tgz#5eef3e0f4afc07e25e847720e7b987ae33f08d0b" - integrity sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.18.9.tgz#1888b24bc28d5cc41c412feb015e9ff6b96e439c" + integrity sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw== dependencies: clone-deep "^4.0.1" find-cache-dir "^2.0.0" @@ -695,43 +692,43 @@ source-map-support "^0.5.16" "@babel/runtime@^7.8.4": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" - integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.3.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/traverse@^7.0.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.17.12", "@babel/traverse@^7.17.9", "@babel/traverse@^7.7.2": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.12.tgz#011874d2abbca0ccf1adbe38f6f7a4ff1747599c" - integrity sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.12" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.12" - "@babel/types" "^7.17.12" +"@babel/template@^7.0.0", "@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98" + integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.9" + "@babel/types" "^7.18.9" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.12.tgz#1210690a516489c0200f355d87619157fbbd69a0" - integrity sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg== +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f" + integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg== dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -747,17 +744,12 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" - integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: - "@cspotcode/source-map-consumer" "0.8.0" + "@jridgewell/trace-mapping" "0.3.9" "@digitalbazaar/security-context@^1.0.0": version "1.0.0" @@ -1072,34 +1064,42 @@ "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" - integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== dependencies: - "@jridgewell/set-array" "^1.0.0" + "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/resolve-uri@^3.0.3": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/set-array@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.13" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" - integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping@^0.3.9": - version "0.3.13" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" - integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" @@ -1775,7 +1775,22 @@ npmlog "^4.1.2" write-file-atomic "^3.0.3" -"@mattrglobal/bbs-signatures@1.0.0", "@mattrglobal/bbs-signatures@^1.0.0": +"@mapbox/node-pre-gyp@1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + +"@mattrglobal/bbs-signatures@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@mattrglobal/bbs-signatures/-/bbs-signatures-1.0.0.tgz#8ff272c6d201aadab7e08bd84dbfd6e0d48ba12d" integrity sha512-FFzybdKqSCrS/e7pl5s6Tl/m/x8ZD5EMBbcTBQaqSOms/lebm91lFukYOIe2qc0a5o+gLhtRKye8OfKwD1Ex/g== @@ -1784,6 +1799,15 @@ optionalDependencies: "@mattrglobal/node-bbs-signatures" "0.13.0" +"@mattrglobal/bbs-signatures@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@mattrglobal/bbs-signatures/-/bbs-signatures-1.1.0.tgz#031418c6a003d1782e3aff95995bda6a0605f9f1" + integrity sha512-uf74y3S7kAxL3FZrva6u+BF3VY3El5QI9IMkyBCoNoJvO+nWJewmTqLMLWEh6QJ1N5egZfDCI4PuS9ISrZJTZg== + dependencies: + "@stablelib/random" "1.0.0" + optionalDependencies: + "@mattrglobal/node-bbs-signatures" "0.15.0" + "@mattrglobal/bls12381-key-pair@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@mattrglobal/bls12381-key-pair/-/bls12381-key-pair-1.0.0.tgz#2959f8663595de0209bebe88517235ae34f1e2b1" @@ -1801,6 +1825,14 @@ neon-cli "0.8.2" node-pre-gyp "0.17.0" +"@mattrglobal/node-bbs-signatures@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@mattrglobal/node-bbs-signatures/-/node-bbs-signatures-0.15.0.tgz#acbe578253fa95d96141bd44cb65e75cd0b79c67" + integrity sha512-ipIwL1neAW/gwC0jg0aOFWiIipdvn6kq0Ta2ccSgc1pZUg6xPYj7dRMEaR6QJ9zV6qOBe7awETd1CoLunwwsLA== + dependencies: + "@mapbox/node-pre-gyp" "1.0.9" + neon-cli "0.10.1" + "@multiformats/base-x@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121" @@ -1930,10 +1962,10 @@ "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^11.2.0": - version "11.2.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" - integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== +"@octokit/openapi-types@^12.11.0": + version "12.11.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" + integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -1941,11 +1973,11 @@ integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== "@octokit/plugin-paginate-rest@^2.16.8": - version "2.17.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" - integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== + version "2.21.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" + integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw== dependencies: - "@octokit/types" "^6.34.0" + "@octokit/types" "^6.40.0" "@octokit/plugin-request-log@^1.0.4": version "1.0.4" @@ -1953,11 +1985,11 @@ integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== "@octokit/plugin-rest-endpoint-methods@^5.12.0": - version "5.13.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" - integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== + version "5.16.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" + integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw== dependencies: - "@octokit/types" "^6.34.0" + "@octokit/types" "^6.39.0" deprecation "^2.3.1" "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": @@ -1991,19 +2023,19 @@ "@octokit/plugin-request-log" "^1.0.4" "@octokit/plugin-rest-endpoint-methods" "^5.12.0" -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": - version "6.34.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" - integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0": + version "6.41.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" + integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg== dependencies: - "@octokit/openapi-types" "^11.2.0" + "@octokit/openapi-types" "^12.11.0" "@peculiar/asn1-schema@^2.1.6": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.1.8.tgz#552300a1ed7991b22c9abf789a3920a3cb94c26b" - integrity sha512-u34H/bpqCdDuqrCVZvH0vpwFBT/dNEdNY+eE8u4IuC26yYnhDkXF4+Hliqca88Avbb7hyN2EF/eokyDdyS7G/A== + version "2.2.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.2.0.tgz#d8a54527685c8dee518e6448137349444310ad64" + integrity sha512-1ENEJNY7Lwlua/1wvzpYP194WtjQBfFxvde2FlzfBFh/ln6wvChrtxlORhbKEnYswzn6fOC4c7HdC5izLPMTJg== dependencies: - asn1js "^3.0.4" + asn1js "^3.0.5" pvtsutils "^1.3.2" tslib "^2.4.0" @@ -2271,24 +2303,24 @@ integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== "@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== "@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.1.19" @@ -2359,9 +2391,9 @@ "@types/json-schema" "*" "@types/estree@*": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== "@types/events@^3.0.0": version "3.0.0" @@ -2369,9 +2401,9 @@ integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== "@types/express-serve-static-core@^4.17.18": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== + version "4.17.30" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz#0f2f99617fa8f9696170c46152ccf7500b34ac04" + integrity sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ== dependencies: "@types/node" "*" "@types/qs" "*" @@ -2465,10 +2497,10 @@ resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-1.27.1.tgz#aceeb2d5be8fccf541237e184e37ecff5faa9096" integrity sha512-cPiXpOvPFDr2edMnOXlz3UBDApwUfR+cpizvxCy0n3vp9bz/qe8BWzHPIEFcy+ogUOyjKuCISgyq77ELZPmkkg== -"@types/mime@^1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" - integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/mime@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.0.tgz#e9a9903894405c6a6551f1774df4e64d9804d69c" + integrity sha512-fccbsHKqFDXClBZTDLA43zl0+TbxyIwyzIzwwhvoJvhNjOErCdeX2xJbURimv2EbSVUGav001PaCJg4mZxMl4w== "@types/minimatch@^3.0.3": version "3.0.5" @@ -2481,9 +2513,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node-fetch@^2.5.10": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" - integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== + version "2.6.2" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== dependencies: "@types/node" "*" form-data "^3.0.0" @@ -2509,9 +2541,9 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prettier@^2.1.5": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.1.tgz#76e72d8a775eef7ce649c63c8acae1a0824bbaed" - integrity sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw== + version "2.6.4" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.4.tgz#ad899dad022bab6b5a9f0a0fe67c2f7a4a8950ed" + integrity sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw== "@types/prop-types@*": version "15.7.5" @@ -2529,16 +2561,16 @@ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== "@types/react-native@^0.64.10": - version "0.64.24" - resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.64.24.tgz#54d8aaadc12d429004b0a573dc3a65ad27430cc6" - integrity sha512-qgqOJub7BYsAkcg3VSL3w63cgJdLoMmAX6TSTAPL53heCzUkIdtpWqjyNRH0n7jPjxPGG1Qmsv6GSUh7IfyqRg== + version "0.64.26" + resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.64.26.tgz#f19fdfe7f0d8a36f6864409b28e69c5f7d602cf3" + integrity sha512-L1U0+wM7GSq1uGu6d/Z9wKB705xyr7Pg47JiXjp9P8DZAFpqP4xsEM/PQ8hcCopEupo6ltQ8ipqoDJ4Nb9Lw5Q== dependencies: - "@types/react" "*" + "@types/react" "^17" -"@types/react@*": - version "18.0.9" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.9.tgz#d6712a38bd6cd83469603e7359511126f122e878" - integrity sha512-9bjbg1hJHUm4De19L1cHiW0Jvx3geel6Qczhjd0qY5VKVE2X5+x77YxAepuCwVh4vrgZJdgEJw48zrhRIeF4Nw== +"@types/react@^17": + version "17.0.48" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.48.tgz#a4532a8b91d7b27b8768b6fc0c3bccb760d15a6c" + integrity sha512-zJ6IYlJ8cYYxiJfUaZOQee4lh99mFihBoqkOSEGV+dFi9leROW6+PgstzQ+w3gWTnUfskALtQPGHK6dYmPj+2A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2564,11 +2596,11 @@ integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== "@types/serve-static@*": - version "1.13.10" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" - integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + version "1.15.0" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" + integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== dependencies: - "@types/mime" "^1" + "@types/mime" "*" "@types/node" "*" "@types/stack-utils@^2.0.0": @@ -2589,9 +2621,9 @@ integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@types/validator@^13.1.3": - version "13.7.2" - resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.2.tgz#a2114225d9be743fb154b06c29b8257aaca42922" - integrity sha512-KFcchQ3h0OPQgFirBRPZr5F/sVjxZsOrQHedj3zi8AH3Zv/hOLx2OLR4hxR5HcfoU+33n69ZuOfzthKVdMoTiw== + version "13.7.4" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.4.tgz#33cc949ee87dd47c63e35ba4ad94f6888852be04" + integrity sha512-uAaSWegu2lymY18l+s5nmcXu3sFeeTOl1zhSGoYzcr6T3wz1M+3OcW4UjfPhIhHGd13tIMRDsEpR+d8w/MexwQ== "@types/varint@^6.0.0": version "6.0.0" @@ -2778,9 +2810,9 @@ acorn@^7.1.1, acorn@^7.4.0: integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== acorn@^8.2.4, acorn@^8.4.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" - integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== add-stream@^1.0.0: version "1.0.0" @@ -2908,9 +2940,9 @@ anymatch@^3.0.3: picomatch "^2.0.4" appdirsjs@^1.2.4: - version "1.2.6" - resolved "https://registry.yarnpkg.com/appdirsjs/-/appdirsjs-1.2.6.tgz#fccf9ee543315492867cacfcfd4a2b32257d30ac" - integrity sha512-D8wJNkqMCeQs3kLasatELsddox/Xqkhp+J07iXGyL54fVN7oc+nmNfYzGuCs1IEP6uBw+TfpuO3JKwc+lECy4w== + version "1.2.7" + resolved "https://registry.yarnpkg.com/appdirsjs/-/appdirsjs-1.2.7.tgz#50b4b7948a26ba6090d4aede2ae2dc2b051be3b3" + integrity sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw== aproba@^1.0.3: version "1.2.0" @@ -2922,10 +2954,18 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + are-we-there-yet@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz#ba20bd6b553e31d62fc8c31bd23d22b95734390d" - integrity sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw== + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== dependencies: delegates "^1.0.0" readable-stream "^3.6.0" @@ -3036,6 +3076,17 @@ array.prototype.flat@^1.2.5: es-abstract "^1.19.2" es-shim-unscopables "^1.0.0" +array.prototype.reduce@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz#8167e80089f78bff70a99e20bd4201d4663b0a6f" + integrity sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.2" + es-array-method-boxes-properly "^1.0.0" + is-string "^1.0.7" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -3063,10 +3114,10 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" -asn1js@^3.0.1, asn1js@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.4.tgz#65fece61bd30d0ef1e31b39fcd383810f44c9fb5" - integrity sha512-ZibuNYyfODvHiVyRFs80xLAUjCwBSkLbE+r1TasjlRKwdodENGT4AlLdaN12Pl/EcK3lFMDYXU6lE2g7Sq9VVQ== +asn1js@^3.0.1, asn1js@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" + integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== dependencies: pvtsutils "^1.3.2" pvutils "^1.1.3" @@ -3204,24 +3255,24 @@ babel-plugin-jest-hoist@^27.5.1: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-polyfill-corejs2@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" - integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== +babel-plugin-polyfill-corejs2@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d" + integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q== dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.1" + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.2" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" - integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== +babel-plugin-polyfill-corejs3@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7" + integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" + "@babel/helper-define-polyfill-provider" "^0.3.2" core-js-compat "^3.21.0" -babel-plugin-polyfill-regenerator@^0.3.0: +babel-plugin-polyfill-regenerator@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== @@ -3357,9 +3408,9 @@ bindings@^1.3.1: file-uri-to-path "1.0.0" bn.js@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== body-parser@1.20.0: version "1.20.0" @@ -3442,16 +3493,15 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserslist@^4.20.2, browserslist@^4.20.3: - version "4.20.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" - integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== +browserslist@^4.20.2, browserslist@^4.21.3: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== dependencies: - caniuse-lite "^1.0.30001332" - electron-to-chromium "^1.4.118" - escalade "^3.1.1" - node-releases "^2.0.3" - picocolors "^1.0.0" + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" bs-logger@0.x: version "0.2.6" @@ -3602,10 +3652,10 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001332: - version "1.0.30001341" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz#59590c8ffa8b5939cf4161f00827b8873ad72498" - integrity sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA== +caniuse-lite@^1.0.30001370: + version "1.0.30001373" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz#2dc3bc3bfcb5d5a929bec11300883040d7b4b4be" + integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ== canonicalize@^1.0.1: version "1.0.8" @@ -3675,9 +3725,9 @@ ci-info@^2.0.0: integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== ci-info@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32" - integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg== + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== cjs-module-lexer@^1.0.0: version "1.2.2" @@ -3733,9 +3783,9 @@ cli-cursor@^3.1.0: restore-cursor "^3.1.0" cli-spinners@^2.0.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + version "2.7.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" + integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== cli-width@^3.0.0: version "3.0.0" @@ -3772,7 +3822,7 @@ clone-deep@^4.0.1: clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== cmd-shim@^4.1.0: version "4.1.0" @@ -3784,12 +3834,12 @@ cmd-shim@^4.1.0: co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== collect-v8-coverage@^1.0.0: version "1.0.1" @@ -3799,7 +3849,7 @@ collect-v8-coverage@^1.0.0: collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -3821,14 +3871,14 @@ color-convert@^2.0.1: color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.3: +color-support@^1.1.2, color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== @@ -3913,7 +3963,7 @@ commander@~2.13.0: commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== compare-func@^2.0.0: version "2.0.0" @@ -3956,7 +4006,7 @@ compression@^1.7.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^2.0.0: version "2.0.0" @@ -3989,7 +4039,7 @@ connect@^3.6.5: console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== content-disposition@0.5.4: version "0.5.4" @@ -4104,7 +4154,7 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.5.0: version "0.5.0" @@ -4114,20 +4164,20 @@ cookie@0.5.0: copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== core-js-compat@^3.21.0: - version "3.22.5" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.5.tgz#7fffa1d20cb18405bd22756ca1353c6f1a0e8614" - integrity sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg== + version "3.24.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.24.1.tgz#d1af84a17e18dfdd401ee39da9996f9a7ba887de" + integrity sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw== dependencies: - browserslist "^4.20.3" + browserslist "^4.21.3" semver "7.0.0" core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== core-util-is@~1.0.0: version "1.0.3" @@ -4173,7 +4223,7 @@ credentials-context@^2.0.0: resolved "https://registry.yarnpkg.com/credentials-context/-/credentials-context-2.0.0.tgz#68a9a1a88850c398d3bba4976c8490530af093e8" integrity sha512-/mFKax6FK26KjgV2KW2D4YqKgoJ5DVJpNt87X2Jc9IxT2HBMy7nEIlc+n7pEi+YFFe721XqrvZPd+jbyyBjsvQ== -cross-fetch@^3.1.2: +cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -4230,7 +4280,7 @@ dargs@^7.0.0: dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== dependencies: assert-plus "^1.0.0" @@ -4254,9 +4304,9 @@ dateformat@^3.0.0: integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== dayjs@^1.8.15: - version "1.11.2" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5" - integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw== + version "1.11.4" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e" + integrity sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g== debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" @@ -4282,12 +4332,12 @@ debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= + integrity sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw== decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== dependencies: decamelize "^1.1.0" map-obj "^1.0.0" @@ -4295,7 +4345,7 @@ decamelize-keys@^1.1.0: decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decimal.js@^10.2.1: version "10.3.1" @@ -4305,12 +4355,12 @@ decimal.js@^10.2.1: decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== deep-extend@^0.6.0, deep-extend@~0.6.0: version "0.6.0" @@ -4335,7 +4385,7 @@ deepmerge@^4.2.2: defaults@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + integrity sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA== dependencies: clone "^1.0.2" @@ -4350,14 +4400,14 @@ define-properties@^1.1.3, define-properties@^1.1.4: define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== dependencies: is-descriptor "^1.0.0" @@ -4372,17 +4422,17 @@ define-property@^2.0.2: delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== denodeify@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" - integrity sha1-OjYof1A05pnnV3kBBSwubJQlFjE= + integrity sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg== depd@2.0.0: version "2.0.0" @@ -4392,7 +4442,7 @@ depd@2.0.0: depd@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" @@ -4407,7 +4457,7 @@ destroy@1.2.0: detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= + integrity sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g== detect-indent@^6.0.0: version "6.1.0" @@ -4417,7 +4467,12 @@ detect-indent@^6.0.0: detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +detect-libc@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" + integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== detect-newline@^3.0.0: version "3.1.0" @@ -4432,10 +4487,10 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -did-resolver@^3.1.3, did-resolver@^3.1.5: - version "3.2.0" - resolved "https://registry.yarnpkg.com/did-resolver/-/did-resolver-3.2.0.tgz#b89edd0dd70ad6f1c65ca1285472e021c2239707" - integrity sha512-8YiTRitfGt9hJYDIzjc254gXgJptO4zq6Q2BMZMNqkbCf9EFkV6BD4QIh5BUF4YjBglBgJY+duQRzO3UZAlZsw== +did-resolver@^3.1.3, did-resolver@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/did-resolver/-/did-resolver-3.2.2.tgz#6f4e252a810f785d1b28a10265fad6dffee25158" + integrity sha512-Eeo2F524VM5N3W4GwglZrnul2y6TLTwMQP3In62JdG34NZoqihYyOZLk+5wUW8sSgvIYIcJM8Dlt3xsdKZZ3tg== diff-sequences@^26.6.2: version "26.6.2" @@ -4507,7 +4562,7 @@ duplexer@^0.1.1: ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -4515,12 +4570,12 @@ ecc-jsbn@~0.1.1: ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.118: - version "1.4.137" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz#186180a45617283f1c012284458510cd99d6787f" - integrity sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA== +electron-to-chromium@^1.4.202: + version "1.4.206" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz#580ff85b54d7ec0c05f20b1e37ea0becdd7b0ee4" + integrity sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA== emittery@^0.8.1: version "0.8.1" @@ -4535,7 +4590,7 @@ emoji-regex@^8.0.0: encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== encoding@^0.1.12: version "0.1.13" @@ -4581,11 +4636,11 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" error-stack-parser@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.7.tgz#b0c6e2ce27d0495cf78ad98715e0cad1219abb57" - integrity sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA== + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== dependencies: - stackframe "^1.1.1" + stackframe "^1.3.4" errorhandler@^1.5.0: version "1.5.1" @@ -4595,7 +4650,7 @@ errorhandler@^1.5.0: accepts "~1.3.7" escape-html "~1.0.3" -es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== @@ -4624,6 +4679,11 @@ es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19 string.prototype.trimstart "^1.0.5" unbox-primitive "^1.0.2" +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + es-shim-unscopables@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" @@ -4648,12 +4708,12 @@ escalade@^3.1.1: escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" @@ -4859,7 +4919,7 @@ esutils@^2.0.2: etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== event-target-shim@^5.0.0, event-target-shim@^5.0.1: version "5.0.1" @@ -4912,12 +4972,12 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -4995,14 +5055,14 @@ express@^4.17.1: extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -5038,7 +5098,7 @@ extglob@^2.0.4: extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== extsprintf@^1.2.0: version "1.4.1" @@ -5079,12 +5139,12 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-text-encoding@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53" - integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig== + version "1.0.4" + resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz#bf1898ad800282a4e53c0ea9690704dd26e4298e" + integrity sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ== fastq@^1.6.0: version "1.13.0" @@ -5144,7 +5204,7 @@ file-uri-to-path@1.0.0: fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -5161,7 +5221,7 @@ fill-range@^7.0.1: filter-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" - integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== finalhandler@1.1.2: version "1.1.2" @@ -5208,7 +5268,7 @@ find-replace@^3.0.0: find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== dependencies: locate-path "^2.0.0" @@ -5244,14 +5304,14 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + version "3.2.6" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" + integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== flow-parser@0.*: - version "0.178.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.178.0.tgz#85d300e29b146b54cb79e277e092ffd401b05f0c" - integrity sha512-OviMR2Y/sMSyUzR1xLLAmQvmHXTsD1Sq69OTmP5AckVulld7sVNsCfwsw7t3uK00dO9A7k4fD+wodbzzaaEn5g== + version "0.183.1" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.183.1.tgz#633387855028cbeb38d65ed0a0d64729e1599a3b" + integrity sha512-xBnvBk8D7aBY7gAilyjjGaNJe+9PGU6I/D2g6lGkkKyl4dW8nzn2eAc7Sc7RNRRr2NNYwpgHOOxBTjJKdKOXcA== flow-parser@^0.121.0: version "0.121.0" @@ -5261,12 +5321,12 @@ flow-parser@^0.121.0: for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== form-data@^3.0.0: version "3.0.1" @@ -5294,19 +5354,19 @@ forwarded@0.2.0: fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" - integrity sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA= + integrity sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ== dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -5348,7 +5408,7 @@ fs-minipass@^2.0.0, fs-minipass@^2.1.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.1.2, fsevents@^2.3.2: version "2.3.2" @@ -5373,13 +5433,28 @@ function.prototype.name@^1.1.5: functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== functions-have-names@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gauge@^4.0.3: version "4.0.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" @@ -5397,7 +5472,7 @@ gauge@^4.0.3: gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -5419,13 +5494,13 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== dependencies: function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.1" + has-symbols "^1.0.3" get-package-type@^0.1.0: version "0.1.0" @@ -5482,19 +5557,19 @@ get-uv-event-loop-napi-h@^1.0.5: get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== dependencies: assert-plus "^1.0.0" git-config@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/git-config/-/git-config-0.0.7.tgz#a9c8a3ef07a776c3d72261356d8b727b62202b28" - integrity sha1-qcij7wendsPXImE1bYtye2IgKyg= + integrity sha512-LidZlYZXWzVjS+M3TEwhtYBaYwLeOZrXci1tBgqp/vDdZTBMl02atvwb6G35L64ibscYoPnxfbwwUS+VZAISLA== dependencies: iniparser "~1.0.5" @@ -5512,7 +5587,7 @@ git-raw-commits@^2.0.8: git-remote-origin-url@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= + integrity sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw== dependencies: gitconfiglocal "^1.0.0" pify "^2.3.0" @@ -5543,7 +5618,7 @@ git-url-parse@^11.4.4: gitconfiglocal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= + integrity sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ== dependencies: ini "^1.3.2" @@ -5572,9 +5647,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.15.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" - integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== + version "13.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" + integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== dependencies: type-fest "^0.20.2" @@ -5610,7 +5685,7 @@ handlebars@^4.7.6, handlebars@^4.7.7: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== har-validator@~5.1.3: version "5.1.5" @@ -5633,7 +5708,7 @@ has-bigints@^1.0.1, has-bigints@^1.0.2: has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" @@ -5662,12 +5737,12 @@ has-tostringtag@^1.0.0: has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -5676,7 +5751,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -5685,12 +5760,12 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -5766,7 +5841,7 @@ http-proxy-agent@^4.0.1: http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" @@ -5788,7 +5863,7 @@ human-signals@^2.1.0: humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== dependencies: ms "^2.0.0" @@ -5841,7 +5916,7 @@ image-size@^0.6.0: import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== dependencies: caller-path "^2.0.0" resolve-from "^3.0.0" @@ -5865,7 +5940,7 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" @@ -5896,7 +5971,7 @@ infer-owner@^1.0.4: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -5914,7 +5989,7 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: iniparser@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/iniparser/-/iniparser-1.0.5.tgz#836d6befe6dfbfcee0bccf1cf9f2acc7027f783d" - integrity sha1-g21r7+bfv87gvM8c+fKsxwJ/eD0= + integrity sha512-i40MWqgTU6h/70NtMsDVVDLjDYWwcIR1yIEVDPfxZIJno9z9L4s83p/V7vAu2i48Vj0gpByrkGFub7ko9XvPrw== init-package-json@^2.0.2: version "2.0.5" @@ -5974,6 +6049,11 @@ ip@^1.1.5: resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -5982,7 +6062,7 @@ ipaddr.js@1.9.1: is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== dependencies: kind-of "^3.0.2" @@ -5996,7 +6076,7 @@ is-accessor-descriptor@^1.0.0: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-bigint@^1.0.1: version "1.0.4" @@ -6030,7 +6110,7 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.5.0, is-core-module@^2.8.1: +is-core-module@^2.5.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== @@ -6040,7 +6120,7 @@ is-core-module@^2.5.0, is-core-module@^2.8.1: is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== dependencies: kind-of "^3.0.2" @@ -6079,12 +6159,12 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== is-extendable@^1.0.1: version "1.0.1" @@ -6096,19 +6176,19 @@ is-extendable@^1.0.1: is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== is-fullwidth-code-point@^3.0.0: version "3.0.0" @@ -6130,7 +6210,7 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== is-negative-zero@^2.0.2: version "2.0.2" @@ -6147,7 +6227,7 @@ is-number-object@^1.0.4: is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== dependencies: kind-of "^3.0.2" @@ -6164,7 +6244,7 @@ is-obj@^2.0.0: is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== is-plain-obj@^2.0.0: version "2.1.0" @@ -6204,16 +6284,16 @@ is-shared-array-buffer@^1.0.2: call-bind "^1.0.2" is-ssh@^1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" - integrity sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ== + version "1.4.0" + resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" + integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== dependencies: - protocols "^1.1.0" + protocols "^2.0.1" is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== is-stream@^2.0.0: version "2.0.1" @@ -6237,14 +6317,14 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: is-text-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= + integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== dependencies: text-extensions "^1.0.0" is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== is-weakref@^1.0.2: version "1.0.2" @@ -6261,17 +6341,17 @@ is-windows@^1.0.2: is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== iso-url@^1.1.5: version "1.2.1" @@ -6281,14 +6361,14 @@ iso-url@^1.1.5: isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== isomorphic-webcrypto@^2.3.8: version "2.3.8" @@ -6311,7 +6391,7 @@ isomorphic-webcrypto@^2.3.8: isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" @@ -6348,9 +6428,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -6874,7 +6954,7 @@ js-yaml@^3.13.1: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== jsc-android@^245459.0.0: version "245459.0.0" @@ -6947,7 +7027,7 @@ jsesc@^2.5.1: jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== json-parse-better-errors@^1.0.1: version "1.0.2" @@ -6977,12 +7057,12 @@ json-schema@0.4.0: json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== json-text-sequence@~0.3.0: version "0.3.0" @@ -7006,14 +7086,14 @@ json5@^1.0.1: jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= + integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== optionalDependencies: graceful-fs "^4.1.6" @@ -7029,12 +7109,12 @@ jsonfile@^6.0.1: jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + integrity sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA== jsonparse@^1.2.0, jsonparse@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== jsprim@^1.2.2: version "1.4.2" @@ -7049,14 +7129,14 @@ jsprim@^1.2.2: kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== dependencies: is-buffer "^1.1.5" @@ -7073,7 +7153,7 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= + integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== optionalDependencies: graceful-fs "^4.1.9" @@ -7135,7 +7215,7 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" @@ -7162,9 +7242,9 @@ libnpmpublish@^4.0.0: ssri "^8.0.1" libphonenumber-js@^1.9.7: - version "1.10.4" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.4.tgz#90397f0ed620262570a32244c9fbc389cc417ce4" - integrity sha512-9QWxEk4GW5RDnFzt8UtyRENfFpAN8u7Sbf9wf32tcXY9tdtnz1dKHIBwW2Wnfx8ypXJb9zUnTpK9aQJ/B8AlnA== + version "1.10.11" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.11.tgz#0078756857bcc5c9dfe097123c6e04ea930e309b" + integrity sha512-ehoihx4HpRXO6FH/uJ0EnaEV4dVU+FDny+jv0S6k9JPyPsAIr0eXDAFvGRMBKE1daCtyHAaFSKCiuCxrOjVAzQ== lines-and-columns@^1.1.6: version "1.2.4" @@ -7174,7 +7254,7 @@ lines-and-columns@^1.1.6: load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== dependencies: graceful-fs "^4.1.2" parse-json "^4.0.0" @@ -7194,7 +7274,7 @@ load-json-file@^6.2.0: locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -7224,27 +7304,27 @@ locate-path@^6.0.0: lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" - integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= + integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== lodash.merge@^4.6.2: version "4.6.2" @@ -7269,12 +7349,12 @@ lodash.templatesettings@^4.0.0: lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.7.0: version "4.17.21" @@ -7329,7 +7409,7 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0: +make-dir@^3.0.0, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -7399,12 +7479,12 @@ makeerror@1.0.12: map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-obj@^4.0.0: version "4.3.0" @@ -7414,14 +7494,14 @@ map-obj@^4.0.0: map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== dependencies: object-visit "^1.0.0" media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== meow@^8.0.0: version "8.1.2" @@ -7443,7 +7523,7 @@ meow@^8.0.0: merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== merge-stream@^2.0.0: version "2.0.0" @@ -7458,7 +7538,7 @@ merge2@^1.3.0, merge2@^1.4.1: methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== metro-babel-register@0.64.0: version "0.64.0" @@ -7863,9 +7943,9 @@ minipass@^2.6.0, minipass@^2.9.0: yallist "^3.0.0" minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" - integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== + version "3.3.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.4.tgz#ca99f95dd77c43c7a76bf51e6d200025eee0ffae" + integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== dependencies: yallist "^4.0.0" @@ -7921,7 +8001,7 @@ modify-values@^1.0.0: ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== ms@2.1.2: version "2.1.2" @@ -7955,9 +8035,9 @@ mute-stream@0.0.8, mute-stream@~0.0.4: integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== nan@^2.11.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + version "2.16.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" + integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== nanomatch@^1.2.9: version "1.2.13" @@ -7979,7 +8059,7 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== needle@^2.5.2: version "2.9.1" @@ -8000,6 +8080,26 @@ neo-async@^2.5.0, neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +neon-cli@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/neon-cli/-/neon-cli-0.10.1.tgz#9705b7b860550faffe6344fc9ab6f6e389c95ed6" + integrity sha512-kOd9ELaYETe1J1nBEOYD7koAZVj6xR9TGwOPccAsWmwL5amkaXXXwXHCUHkBAWujlgSZY5f2pT+pFGkzoHExYQ== + dependencies: + chalk "^4.1.0" + command-line-args "^5.1.1" + command-line-commands "^3.0.1" + command-line-usage "^6.1.0" + git-config "0.0.7" + handlebars "^4.7.6" + inquirer "^7.3.3" + make-promises-safe "^5.1.0" + rimraf "^3.0.2" + semver "^7.3.2" + toml "^3.0.0" + ts-typed-json "^0.3.2" + validate-npm-package-license "^3.0.4" + validate-npm-package-name "^3.0.0" + neon-cli@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/neon-cli/-/neon-cli-0.8.2.tgz#5111b0e9d5d90273bdf85a9aa40a1a47a32df2ef" @@ -8038,7 +8138,7 @@ node-addon-api@^3.0.0: node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= + integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== dependencies: minimatch "^3.0.2" @@ -8058,9 +8158,9 @@ node-fetch@3.0.0-beta.9: fetch-blob "^2.1.1" node-gyp-build@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4" - integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== node-gyp@^5.0.2: version "5.1.1" @@ -8114,7 +8214,7 @@ node-gyp@^8.0.0: node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== node-pre-gyp@0.17.0: version "0.17.0" @@ -8132,10 +8232,10 @@ node-pre-gyp@0.17.0: semver "^5.7.1" tar "^4.4.13" -node-releases@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.4.tgz#f38252370c43854dc48aa431c766c6c398f40476" - integrity sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ== +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== node-stream-zip@^1.9.1: version "1.15.0" @@ -8180,7 +8280,7 @@ normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== dependencies: remove-trailing-separator "^1.0.1" @@ -8294,7 +8394,7 @@ npm-registry-fetch@^9.0.0: npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== dependencies: path-key "^2.0.0" @@ -8315,6 +8415,16 @@ npmlog@^4.1.2: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + npmlog@^6.0.0: version "6.0.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" @@ -8333,12 +8443,12 @@ nullthrows@^1.1.1: number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + version "2.2.1" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.1.tgz#10a9f268fbf4c461249ebcfe38e359aa36e2577c" + integrity sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg== oauth-sign@~0.9.0: version "0.9.0" @@ -8353,21 +8463,21 @@ ob1@0.64.0: object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" object-inspect@^1.10.3, object-inspect@^1.12.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== object-keys@^1.1.1: version "1.1.1" @@ -8377,7 +8487,7 @@ object-keys@^1.1.1: object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== dependencies: isobject "^3.0.0" @@ -8392,18 +8502,19 @@ object.assign@^4.1.0, object.assign@^4.1.2: object-keys "^1.1.1" object.getownpropertydescriptors@^2.0.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" - integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== + version "2.1.4" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz#7965e6437a57278b587383831a9b829455a4bc37" + integrity sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ== dependencies: + array.prototype.reduce "^1.0.4" call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.20.1" object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== dependencies: isobject "^3.0.1" @@ -8426,7 +8537,7 @@ on-finished@2.4.1: on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== dependencies: ee-first "1.1.1" @@ -8438,14 +8549,14 @@ on-headers@~1.0.2: once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== dependencies: mimic-fn "^1.0.0" @@ -8490,7 +8601,7 @@ optionator@^0.9.1: options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= + integrity sha512-bOj3L1ypm++N+n7CEbbe473A414AB7z+amKYshRb//iuL3MpdDCLhPnw6aVTdKB9g5ZRVHIEp8eUln6L2NUStg== ora@^3.4.0: version "3.4.0" @@ -8507,12 +8618,12 @@ ora@^3.4.0: os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== osenv@^0.1.4: version "0.1.5" @@ -8525,7 +8636,7 @@ osenv@^0.1.4: p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== p-limit@^1.1.0: version "1.3.0" @@ -8551,7 +8662,7 @@ p-limit@^3.0.2: p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== dependencies: p-limit "^1.1.0" @@ -8616,7 +8727,7 @@ p-timeout@^3.2.0: p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== p-try@^2.0.0: version "2.2.0" @@ -8665,7 +8776,7 @@ parent-module@^1.0.0: parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== dependencies: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" @@ -8681,9 +8792,9 @@ parse-json@^5.0.0, parse-json@^5.2.0: lines-and-columns "^1.1.6" parse-path@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" - integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== + version "4.0.4" + resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.4.tgz#4bf424e6b743fb080831f03b536af9fc43f0ffea" + integrity sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw== dependencies: is-ssh "^1.3.0" protocols "^1.4.0" @@ -8691,9 +8802,9 @@ parse-path@^4.0.0: query-string "^6.13.8" parse-url@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d" - integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw== + version "6.0.5" + resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.5.tgz#4acab8982cef1846a0f8675fa686cef24b2f6f9b" + integrity sha512-e35AeLTSIlkw/5GFq70IN7po8fmDUjpDPY1rIK+VubRfsUvBonjQ+PBZG+vWMACnQSmNlvl524IucoDmcioMxA== dependencies: is-ssh "^1.3.0" normalize-url "^6.1.0" @@ -8713,12 +8824,12 @@ parseurl@~1.3.3: pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== path-exists@^4.0.0: version "4.0.0" @@ -8728,12 +8839,12 @@ path-exists@^4.0.0: path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" @@ -8748,7 +8859,7 @@ path-parse@^1.0.7: path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== path-type@^3.0.0: version "3.0.0" @@ -8765,7 +8876,7 @@ path-type@^4.0.0: performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== picocolors@^1.0.0: version "1.0.0" @@ -8780,12 +8891,12 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pify@^4.0.1: version "4.0.1" @@ -8817,17 +8928,17 @@ pkg-dir@^4.2.0: find-up "^4.0.0" plist@^3.0.1, plist@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.5.tgz#2cbeb52d10e3cdccccf0c11a63a85d830970a987" - integrity sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3" + integrity sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA== dependencies: base64-js "^1.5.1" - xmlbuilder "^9.0.7" + xmlbuilder "^15.1.1" posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== prelude-ls@^1.2.1: version "1.2.1" @@ -8837,7 +8948,7 @@ prelude-ls@^1.2.1: prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== prettier-linter-helpers@^1.0.0: version "1.0.0" @@ -8847,9 +8958,9 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier@^2.3.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" - integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== pretty-format@^26.0.0, pretty-format@^26.5.2, pretty-format@^26.6.2: version "26.6.2" @@ -8883,7 +8994,7 @@ progress@^2.0.0: promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== promise-retry@^2.0.1: version "2.0.1" @@ -8911,7 +9022,7 @@ prompts@^2.0.1, prompts@^2.4.0: promzard@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= + integrity sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw== dependencies: read "1" @@ -8927,13 +9038,18 @@ prop-types@^15.7.2: proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -protocols@^1.1.0, protocols@^1.4.0: +protocols@^1.4.0: version "1.4.8" resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== +protocols@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" + integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -8943,9 +9059,9 @@ proxy-addr@~2.0.7: ipaddr.js "1.9.1" psl@^1.1.28, psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: version "3.0.0" @@ -8975,15 +9091,22 @@ pvutils@^1.1.3: q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@6.10.3, qs@^6.9.4: +qs@6.10.3: version "6.10.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== dependencies: side-channel "^1.0.4" +qs@^6.9.4: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" @@ -9045,9 +9168,9 @@ rc@^1.2.8: strip-json-comments "~2.0.1" react-devtools-core@^4.6.0: - version "4.24.6" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.24.6.tgz#3262114f483465179c97a49b7ada845048f4f97e" - integrity sha512-+6y6JAtAo1NUUxaCwCYTb13ViBpc7RjNTlj1HZRlDJmi7UYToj5+BNn8Duzz2YizzAzmRUWZkRM7OtqxnN6TnA== + version "4.25.0" + resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.25.0.tgz#78b11a2c9f81dd9ebff3745ab4ee2147cc96c12a" + integrity sha512-iewRrnu0ZnmfL+jJayKphXj04CFh6i3ezVnpCtcnZbTPSQgN09XqHAzXbKbqNDl7aTg9QLNkQRP6M3DvdrinWA== dependencies: shell-quote "^1.6.1" ws "^7" @@ -9089,7 +9212,7 @@ react-native-get-random-values@^1.7.0: react-native-securerandom@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/react-native-securerandom/-/react-native-securerandom-0.1.1.tgz#f130623a412c338b0afadedbc204c5cbb8bf2070" - integrity sha1-8TBiOkEsM4sK+t7bwgTFy7i/IHA= + integrity sha512-CozcCx0lpBLevxiXEb86kwLRalBCHNjiGPlw3P7Fi27U6ZLdfjOCNRHD1LtBKcvPvI3TvkBXB3GOtLvqaYJLGw== dependencies: base64-js "*" @@ -9199,7 +9322,7 @@ read-package-tree@^5.3.1: read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= + integrity sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw== dependencies: find-up "^2.0.0" read-pkg "^3.0.0" @@ -9216,7 +9339,7 @@ read-pkg-up@^7.0.1: read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== dependencies: load-json-file "^4.0.0" normalize-package-data "^2.3.2" @@ -9235,7 +9358,7 @@ read-pkg@^5.2.0: read@1, read@~1.0.1: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= + integrity sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ== dependencies: mute-stream "~0.0.4" @@ -9284,7 +9407,7 @@ recast@^0.20.3: rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== dependencies: resolve "^1.1.6" @@ -9369,10 +9492,10 @@ regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -regexpu-core@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" - integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== +regexpu-core@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d" + integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== dependencies: regenerate "^1.4.2" regenerate-unicode-properties "^10.0.1" @@ -9396,7 +9519,7 @@ regjsparser@^0.8.2: remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== repeat-element@^1.1.2: version "1.1.4" @@ -9406,7 +9529,7 @@ repeat-element@^1.1.2: repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== request@^2.88.0, request@^2.88.2: version "2.88.2" @@ -9437,7 +9560,7 @@ request@^2.88.0, request@^2.88.2: require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" @@ -9459,7 +9582,7 @@ resolve-cwd@^3.0.0: resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= + integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== resolve-from@^4.0.0: version "4.0.0" @@ -9474,7 +9597,7 @@ resolve-from@^5.0.0: resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== resolve.exports@^1.1.0: version "1.1.0" @@ -9482,18 +9605,18 @@ resolve.exports@^1.1.0: integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== dependencies: - is-core-module "^2.8.1" + is-core-module "^2.9.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -9514,7 +9637,7 @@ ret@~0.1.10: retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== reusify@^1.0.4: version "1.0.4" @@ -9543,7 +9666,7 @@ rimraf@^3.0.0, rimraf@^3.0.2, rimraf@~3.0.2: rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= + integrity sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg== rimraf@~2.6.2: version "2.6.3" @@ -9577,9 +9700,9 @@ rxjs@^6.6.0: tslib "^1.9.0" rxjs@^7.2.0: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== dependencies: tslib "^2.1.0" @@ -9596,7 +9719,7 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, s safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== dependencies: ret "~0.1.10" @@ -9620,7 +9743,7 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sax@^1.2.1, sax@^1.2.4: +sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -9684,7 +9807,7 @@ send@0.18.0: serialize-error@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" - integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go= + integrity sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw== serialize-error@^8.0.1: version "8.1.0" @@ -9706,7 +9829,7 @@ serve-static@1.15.0, serve-static@^1.13.1: set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" @@ -9733,7 +9856,7 @@ shallow-clone@^3.0.0: shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== dependencies: shebang-regex "^1.0.0" @@ -9747,7 +9870,7 @@ shebang-command@^2.0.0: shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== shebang-regex@^3.0.0: version "3.0.0" @@ -9757,7 +9880,7 @@ shebang-regex@^3.0.0: shell-quote@1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" - integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c= + integrity sha512-V0iQEZ/uoem3NmD91rD8XiuozJnq9/ZJnbHVXHnWqP1ucAhS3yJ7sLIIzEi57wFFcK3oi3kFUC46uSyWr35mxg== dependencies: array-filter "~0.0.0" array-map "~0.0.0" @@ -9832,7 +9955,7 @@ slice-ansi@^4.0.0: slide@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= + integrity sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw== smart-buffer@^4.2.0: version "4.2.0" @@ -9879,26 +10002,26 @@ socks-proxy-agent@^5.0.0: socks "^2.3.3" socks-proxy-agent@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz#f6b5229cc0cbd6f2f202d9695f09d871e951c85e" - integrity sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" + integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== dependencies: agent-base "^6.0.2" debug "^4.3.3" socks "^2.6.2" socks@^2.3.3, socks@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" - integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + version "2.7.0" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.0.tgz#f9225acdb841e874dca25f870e9130990f3913d0" + integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA== dependencies: - ip "^1.1.5" + ip "^2.0.0" smart-buffer "^4.2.0" sort-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + integrity sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg== dependencies: is-plain-obj "^1.0.0" @@ -9936,7 +10059,7 @@ source-map-url@^0.4.0: source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" @@ -9944,9 +10067,9 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== spdx-correct@^3.0.0: version "3.1.1" @@ -10003,7 +10126,7 @@ split@^1.0.0: sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sshpk@^1.7.0: version "1.17.0" @@ -10034,10 +10157,10 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -stackframe@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1" - integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg== +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== stacktrace-parser@^0.1.3: version "0.1.10" @@ -10049,7 +10172,7 @@ stacktrace-parser@^0.1.3: static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -10062,7 +10185,7 @@ statuses@2.0.1: statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== str2buf@^1.3.0: version "1.3.0" @@ -10072,12 +10195,12 @@ str2buf@^1.3.0: stream-buffers@2.2.x: version "2.2.0" resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4" - integrity sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ= + integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg== strict-uri-encode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== string-length@^4.0.1: version "4.0.2" @@ -10090,7 +10213,7 @@ string-length@^4.0.1: string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -10140,7 +10263,7 @@ string_decoder@~1.1.1: strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: ansi-regex "^2.0.0" @@ -10161,7 +10284,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" @@ -10171,7 +10294,7 @@ strip-bom@^4.0.0: strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== strip-final-newline@^2.0.0: version "2.0.0" @@ -10193,7 +10316,7 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== strong-log-transformer@^2.1.0: version "2.1.0" @@ -10282,7 +10405,7 @@ tar@^4.4.12, tar@^4.4.13: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.0.2, tar@^6.1.0, tar@^6.1.2: +tar@^6.0.2, tar@^6.1.0, tar@^6.1.11, tar@^6.1.2: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== @@ -10297,7 +10420,7 @@ tar@^6.0.2, tar@^6.1.0, tar@^6.1.2: temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= + integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== temp-write@^4.0.0: version "4.0.0" @@ -10313,7 +10436,7 @@ temp-write@^4.0.0: temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= + integrity sha512-jtnWJs6B1cZlHs9wPG7BrowKxZw/rf6+UpGAkr8AaYmiTyTO7zQlLoST8zx/8TcUPnZmeBoB+H8ARuHZaSijVw== dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" @@ -10350,7 +10473,7 @@ text-extensions@^1.0.0: text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== throat@^5.0.0: version "5.0.0" @@ -10380,7 +10503,7 @@ through2@^4.0.0: through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== tmp@^0.0.33: version "0.0.33" @@ -10397,19 +10520,19 @@ tmpl@1.0.5: to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -10468,7 +10591,7 @@ tr46@^2.1.0: tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== trim-newlines@^3.0.0: version "3.0.1" @@ -10490,11 +10613,11 @@ ts-jest@^27.0.3: yargs-parser "20.x" ts-node@^10.0.0, ts-node@^10.4.0: - version "10.7.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" - integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== dependencies: - "@cspotcode/source-map-support" "0.7.0" + "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" "@tsconfig/node12" "^1.0.7" "@tsconfig/node14" "^1.0.0" @@ -10505,7 +10628,7 @@ ts-node@^10.0.0, ts-node@^10.4.0: create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - v8-compile-cache-lib "^3.0.0" + v8-compile-cache-lib "^3.0.1" yn "3.1.1" ts-typed-json@^0.3.2: @@ -10557,14 +10680,14 @@ tsyringe@^4.7.0: tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -10576,7 +10699,7 @@ type-check@^0.4.0, type-check@~0.4.0: type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== dependencies: prelude-ls "~1.1.2" @@ -10638,7 +10761,7 @@ typedarray-to-buffer@^3.1.5: typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typescript@~4.3.0: version "4.3.5" @@ -10664,24 +10787,24 @@ uglify-es@^3.1.9: source-map "~0.6.1" uglify-js@^3.1.4: - version "3.15.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.5.tgz#2b10f9e0bfb3f5c15a8e8404393b6361eaeb33b3" - integrity sha512-hNM5q5GbBRB5xB+PMqVRcgYe4c8jbyZ1pzZhS6jbq54/4F2gFK869ZheiE5A8/t+W5jtTNpWef/5Q9zk639FNQ== + version "3.16.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.16.3.tgz#94c7a63337ee31227a18d03b8a3041c210fd1f1d" + integrity sha512-uVbFqx9vvLhQg0iBaau9Z75AxWJ8tqM9AV890dIZCLApF4rTcyHwmAvLeEdYRs+BzYWu8Iw81F79ah0EfTXbaw== uid-number@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= + integrity sha512-c461FXIljswCuscZn67xq9PpszkPT6RjheWFQTgCyabJrTUozElanb0YEqv2UGgk247YpcJkFBuSGNvBlpXM9w== ultron@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= + integrity sha512-QMpnpVtYaWEeY+MwKDN/UdKlE/LsFZXM5lO1u7GaZzNgmIbGixHEmVMIKT+vqYOALu3m5GYQy9kz4Xu4IVn7Ow== umask@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= + integrity sha512-lE/rxOhmiScJu9L6RTNVgB/zZbF+vGC0/p6D3xnkAePI2o0sMyFG966iR5Ki50OI/0mNi2yaRnxfLsPmEZF/JA== unbox-primitive@^1.0.2: version "1.0.2" @@ -10758,12 +10881,12 @@ universalify@^2.0.0: unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== dependencies: has-value "^0.3.1" isobject "^3.0.0" @@ -10773,6 +10896,14 @@ upath@^2.0.1: resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -10783,19 +10914,19 @@ uri-js@^4.2.2: urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== use-subscription@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.7.0.tgz#c7505263315deac9fd2581cdf4ab1e3ff2585d0f" - integrity sha512-87x6MjiIVE/BWqtxfiRvM6jfvGudN+UeVOnWi7qKYp2c0YJn5+Z5Jt0kZw6Tt+8hs7kw/BWo2WBhizJSAZsQJA== + version "1.8.0" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.8.0.tgz#f118938c29d263c2bce12fc5585d3fe694d4dbce" + integrity sha512-LISuG0/TmmoDoCRmV5XAqYkd3UCBNM0ML3gGBndze65WITcsExCD3DTvXXTLyNcOC0heFQZzluW88bN/oC1DQQ== dependencies: - use-sync-external-store "^1.1.0" + use-sync-external-store "^1.2.0" -use-sync-external-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82" - integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ== +use-sync-external-store@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== use@^3.1.0: version "3.1.1" @@ -10810,19 +10941,19 @@ utf8@^3.0.0: util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== util-promisify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" - integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= + integrity sha512-K+5eQPYs14b3+E+hmE2J6gCZ4JmMl9DbYS6BeP2CHq6WMuNxErxf5B/n0fz85L8zUuoO6rIzNNmIQDu/j+1OcA== dependencies: object.getownpropertydescriptors "^2.0.3" utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^3.3.2: version "3.4.0" @@ -10834,7 +10965,7 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-compile-cache-lib@^3.0.0: +v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== @@ -10864,7 +10995,7 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + integrity sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw== dependencies: builtins "^1.0.3" @@ -10881,12 +11012,12 @@ varint@^6.0.0: vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -10921,17 +11052,17 @@ walker@^1.0.7, walker@~1.0.5: wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== dependencies: defaults "^1.0.3" web-did-resolver@^2.0.8: - version "2.0.16" - resolved "https://registry.yarnpkg.com/web-did-resolver/-/web-did-resolver-2.0.16.tgz#23e6607a6a068218ff8403d967b8a70af2e0cc25" - integrity sha512-PNGO9nP8H1mTxBRzg/AdzB40HXHhQ99BMCMEQYLK1fatohdmEDetJglgTFwavKQEbBexDG3xknCIzryWD7iS0A== + version "2.0.19" + resolved "https://registry.yarnpkg.com/web-did-resolver/-/web-did-resolver-2.0.19.tgz#25f11fd89f510b2650ce77f50baae496ae20d104" + integrity sha512-KRnLWTOApVAVvx20k5Fn2e4Fwhbo7cZbALruOv/lcW3Fr/1UTfGXFg0hnFYcscxk/hBrT+wBORoJf/VeQIOMSQ== dependencies: - cross-fetch "^3.1.2" - did-resolver "^3.1.5" + cross-fetch "^3.1.5" + did-resolver "^3.2.2" webcrypto-core@^1.7.4: version "1.7.5" @@ -10952,7 +11083,7 @@ webcrypto-shim@^0.1.4: webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== webidl-conversions@^5.0.0: version "5.0.0" @@ -10984,7 +11115,7 @@ whatwg-mimetype@^2.3.0: whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -11012,7 +11143,7 @@ which-boxed-primitive@^1.0.2: which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== which@^1.2.9, which@^1.3.1: version "1.3.1" @@ -11028,7 +11159,7 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.0, wide-align@^1.1.5: +wide-align@^1.1.0, wide-align@^1.1.2, wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== @@ -11043,7 +11174,7 @@ word-wrap@^1.2.3, word-wrap@~1.2.3: wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== wordwrapjs@^4.0.0: version "4.0.1" @@ -11074,7 +11205,7 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: version "2.4.3" @@ -11144,9 +11275,9 @@ ws@^6.1.4: async-limiter "~1.0.0" ws@^7, ws@^7.4.6, ws@^7.5.3: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== xcode@^2.0.0: version "2.1.0" @@ -11161,10 +11292,10 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xmlbuilder@^9.0.7: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= +xmlbuilder@^15.1.1: + version "15.1.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== xmlchars@^2.2.0: version "2.2.0" @@ -11172,11 +11303,11 @@ xmlchars@^2.2.0: integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xmldoc@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/xmldoc/-/xmldoc-1.1.2.tgz#6666e029fe25470d599cd30e23ff0d1ed50466d7" - integrity sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ== + version "1.2.0" + resolved "https://registry.yarnpkg.com/xmldoc/-/xmldoc-1.2.0.tgz#7554371bfd8c138287cff01841ae4566d26e5541" + integrity sha512-2eN8QhjBsMW2uVj7JHLHkMytpvGHLHxKXBy4J3fAT/HujsEtM6yU84iGjpESYGHg6XwK0Vu4l+KgqQ2dv2cCqg== dependencies: - sax "^1.2.1" + sax "^1.2.4" xtend@~4.0.1: version "4.0.2"