From 103af2882bdc1d77f2b38c38155697078e5369ef Mon Sep 17 00:00:00 2001 From: Berend Sliedrecht Date: Wed, 13 Dec 2023 16:20:15 +0100 Subject: [PATCH 1/2] feat(proofs): added PresentationExchangeModule Signed-off-by: Berend Sliedrecht --- .../proofs/protocol/v2/V2ProofProtocol.ts | 2 +- .../core/src/modules/proofs/utils/index.ts | 1 + packages/core/src/modules/vc/index.ts | 2 +- packages/presentation-exchange/jest.config.ts | 15 + packages/presentation-exchange/package.json | 37 ++ .../src/PresentationExchangeError.ts | 3 + .../src/PresentationExchangeModule.ts | 25 + .../src/PresentationExchangeService.ts | 481 ++++++++++++++++++ packages/presentation-exchange/src/index.ts | 4 + .../src/models/PresentationSubmission.ts | 119 +++++ .../presentation-exchange/src/models/index.ts | 1 + .../src/utils/credentialSelection.ts | 300 +++++++++++ .../presentation-exchange/src/utils/index.ts | 2 + .../src/utils/transform.ts | 78 +++ .../presentation-exchange/tsconfig.build.json | 9 + packages/presentation-exchange/tsconfig.json | 8 + yarn.lock | 399 ++++++++++++++- 17 files changed, 1480 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/modules/proofs/utils/index.ts create mode 100644 packages/presentation-exchange/jest.config.ts create mode 100644 packages/presentation-exchange/package.json create mode 100644 packages/presentation-exchange/src/PresentationExchangeError.ts create mode 100644 packages/presentation-exchange/src/PresentationExchangeModule.ts create mode 100644 packages/presentation-exchange/src/PresentationExchangeService.ts create mode 100644 packages/presentation-exchange/src/index.ts create mode 100644 packages/presentation-exchange/src/models/PresentationSubmission.ts create mode 100644 packages/presentation-exchange/src/models/index.ts create mode 100644 packages/presentation-exchange/src/utils/credentialSelection.ts create mode 100644 packages/presentation-exchange/src/utils/index.ts create mode 100644 packages/presentation-exchange/src/utils/transform.ts create mode 100644 packages/presentation-exchange/tsconfig.build.json create mode 100644 packages/presentation-exchange/tsconfig.json diff --git a/packages/core/src/modules/proofs/protocol/v2/V2ProofProtocol.ts b/packages/core/src/modules/proofs/protocol/v2/V2ProofProtocol.ts index ffec69b8a3..3ce7e2c9d8 100644 --- a/packages/core/src/modules/proofs/protocol/v2/V2ProofProtocol.ts +++ b/packages/core/src/modules/proofs/protocol/v2/V2ProofProtocol.ts @@ -42,7 +42,7 @@ import { ProofsModuleConfig } from '../../ProofsModuleConfig' import { PresentationProblemReportReason } from '../../errors/PresentationProblemReportReason' import { AutoAcceptProof, ProofState } from '../../models' import { ProofExchangeRecord, ProofRepository } from '../../repository' -import { composeAutoAccept } from '../../utils/composeAutoAccept' +import { composeAutoAccept } from '../../utils' import { BaseProofProtocol } from '../BaseProofProtocol' import { ProofFormatCoordinator } from './ProofFormatCoordinator' diff --git a/packages/core/src/modules/proofs/utils/index.ts b/packages/core/src/modules/proofs/utils/index.ts new file mode 100644 index 0000000000..e9685c62fe --- /dev/null +++ b/packages/core/src/modules/proofs/utils/index.ts @@ -0,0 +1 @@ +export * from './composeAutoAccept' diff --git a/packages/core/src/modules/vc/index.ts b/packages/core/src/modules/vc/index.ts index 47571cdecb..84a0da17c7 100644 --- a/packages/core/src/modules/vc/index.ts +++ b/packages/core/src/modules/vc/index.ts @@ -1,6 +1,6 @@ export * from './W3cCredentialService' export * from './W3cCredentialServiceOptions' -export * from './repository/W3cCredentialRecord' +export * from './repository' export * from './W3cCredentialsModule' export * from './W3cCredentialsApi' export * from './models' diff --git a/packages/presentation-exchange/jest.config.ts b/packages/presentation-exchange/jest.config.ts new file mode 100644 index 0000000000..7b6ec7f1c5 --- /dev/null +++ b/packages/presentation-exchange/jest.config.ts @@ -0,0 +1,15 @@ +import type { Config } from '@jest/types' + +import base from '../../jest.config.base' + +import packageJson from './package.json' + +process.env.TZ = 'GMT' + +const config: Config.InitialOptions = { + ...base, + displayName: packageJson.name, + setupFilesAfterEnv: ['./tests/setup.ts'], +} + +export default config diff --git a/packages/presentation-exchange/package.json b/packages/presentation-exchange/package.json new file mode 100644 index 0000000000..f31f73b572 --- /dev/null +++ b/packages/presentation-exchange/package.json @@ -0,0 +1,37 @@ +{ + "name": "@aries-framework/presentation-exchange", + "main": "build/index", + "types": "build/index", + "version": "0.4.2", + "files": [ + "build" + ], + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "homepage": "https://github.com/openwallet-foundation/agent-framework-javascript/tree/main/packages/presentation-exchange", + "repository": { + "type": "git", + "url": "https://github.com/openwallet-foundation/agent-framework-javascript", + "directory": "packages/presentation-exchange" + }, + "scripts": { + "build": "yarn run clean && yarn run compile", + "clean": "rimraf ./build", + "compile": "tsc -p tsconfig.build.json", + "prepublishOnly": "yarn run build" + }, + "dependencies": { + "@aries-framework/core": "^0.4.2", + "@sphereon/pex": "^2.2.2", + "@sphereon/pex-models": "^2.1.2", + "@sphereon/ssi-types": "^0.17.5", + "jsonpath": "^1.1.1", + "tsyringe": "^4.8.0" + }, + "devDependencies": { + "@types/jsonpath": "^0.2.4", + "typescript": "~4.9.5" + } +} diff --git a/packages/presentation-exchange/src/PresentationExchangeError.ts b/packages/presentation-exchange/src/PresentationExchangeError.ts new file mode 100644 index 0000000000..5c52b67752 --- /dev/null +++ b/packages/presentation-exchange/src/PresentationExchangeError.ts @@ -0,0 +1,3 @@ +import { AriesFrameworkError } from '@aries-framework/core' + +export class PresentationExchangeError extends AriesFrameworkError {} diff --git a/packages/presentation-exchange/src/PresentationExchangeModule.ts b/packages/presentation-exchange/src/PresentationExchangeModule.ts new file mode 100644 index 0000000000..efeb199aaa --- /dev/null +++ b/packages/presentation-exchange/src/PresentationExchangeModule.ts @@ -0,0 +1,25 @@ +import type { DependencyManager, Module } from '@aries-framework/core' + +import { AgentConfig } from '@aries-framework/core' + +import { PresentationExchangeService } from './PresentationExchangeService' + +/** + * @public + */ +export class PresentationExchangeModule implements Module { + /** + * Registers the dependencies of the presentation-exchange module on the dependency manager. + */ + public register(dependencyManager: DependencyManager) { + // Warn about experimental module + dependencyManager + .resolve(AgentConfig) + .logger.warn( + "The '@aries-framework/presentation-exchange' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + ) + + // Services + dependencyManager.registerSingleton(PresentationExchangeService) + } +} diff --git a/packages/presentation-exchange/src/PresentationExchangeService.ts b/packages/presentation-exchange/src/PresentationExchangeService.ts new file mode 100644 index 0000000000..8b9ba5dbcd --- /dev/null +++ b/packages/presentation-exchange/src/PresentationExchangeService.ts @@ -0,0 +1,481 @@ +import type { InputDescriptorToCredentials, PresentationSubmission } from './models' +import type { + AgentContext, + Query, + VerificationMethod, + W3cCredentialRecord, + W3cVerifiableCredential, + W3cVerifiablePresentation, +} from '@aries-framework/core' +import type { + IPresentationDefinition, + PresentationSignCallBackParams, + VerifiablePresentationResult, +} from '@sphereon/pex' +import type { + InputDescriptorV2, + PresentationSubmission as PexPresentationSubmission, + PresentationDefinitionV1, +} from '@sphereon/pex-models' +import type { OriginalVerifiableCredential } from '@sphereon/ssi-types' + +import { + getJwkFromKey, + JsonTransformer, + SignatureSuiteRegistry, + W3cPresentation, + W3cCredentialService, + ClaimFormat, + getKeyFromVerificationMethod, + DidsApi, + W3cCredentialRepository, +} from '@aries-framework/core' +import { PEVersion, PEX, PresentationSubmissionLocation } from '@sphereon/pex' +import { injectable } from 'tsyringe' + +import { PresentationExchangeError } from './PresentationExchangeError' +import { + selectCredentialsForRequest, + getSphereonOriginalVerifiableCredential, + getSphereonW3cVerifiablePresentation, + getW3cVerifiablePresentationInstance, +} from './utils' + +export type ProofStructure = Record>> +export type PresentationDefinition = IPresentationDefinition + +@injectable() +export class PresentationExchangeService { + private pex = new PEX() + + public async selectCredentialsForRequest( + agentContext: AgentContext, + presentationDefinition: PresentationDefinition + ): Promise { + const credentialRecords = await this.queryCredentialForPresentationDefinition(agentContext, presentationDefinition) + + const didsApi = agentContext.dependencyManager.resolve(DidsApi) + const didRecords = await didsApi.getCreatedDids() + const holderDids = didRecords.map((didRecord) => didRecord.did) + + return selectCredentialsForRequest(presentationDefinition, credentialRecords, holderDids) + } + + /** + * Queries the wallet for credentials that match the given presentation definition. This only does an initial query based on the + * schema of the input descriptors. It does not do any further filtering based on the constraints in the input descriptors. + */ + private async queryCredentialForPresentationDefinition( + agentContext: AgentContext, + presentationDefinition: PresentationDefinition + ): Promise> { + const w3cCredentialRepository = agentContext.dependencyManager.resolve(W3cCredentialRepository) + const query: Array> = [] + const presentationDefinitionVersion = PEX.definitionVersionDiscovery(presentationDefinition) + + if (!presentationDefinitionVersion.version) { + throw new PresentationExchangeError( + `Unable to determine the Presentation Exchange version from the presentation definition. ${ + presentationDefinitionVersion.error ?? 'Unknown error' + }` + ) + } + + if (presentationDefinitionVersion.version === PEVersion.v1) { + const pd = presentationDefinition as PresentationDefinitionV1 + + // The schema.uri can contain either an expanded type, or a context uri + for (const inputDescriptor of pd.input_descriptors) { + for (const schema of inputDescriptor.schema) { + query.push({ + $or: [{ expandedType: [schema.uri] }, { contexts: [schema.uri] }, { type: [schema.uri] }], + }) + } + } + } else if (presentationDefinitionVersion.version === PEVersion.v2) { + // FIXME: As PE version 2 does not have the `schema` anymore, we can't query by schema anymore. + // For now we retrieve ALL credentials, as we did the same for V1 with JWT credentials. We probably need + // to find some way to do initial filtering, hopefully if there's a filter on the `type` field or something. + } else { + throw new PresentationExchangeError( + `Unsupported presentation definition version ${presentationDefinitionVersion.version as unknown as string}` + ) + } + + // query the wallet ourselves first to avoid the need to query the pex library for all + // credentials for every proof request + const credentialRecords = await w3cCredentialRepository.findByQuery(agentContext, { + $or: query, + }) + + return credentialRecords + } + + private addCredentialToSubjectInputDescriptor( + subjectsToInputDescriptors: ProofStructure, + subjectId: string, + inputDescriptorId: string, + credential: W3cVerifiableCredential + ) { + const inputDescriptorsToCredentials = subjectsToInputDescriptors[subjectId] ?? {} + const credentials = inputDescriptorsToCredentials[inputDescriptorId] ?? [] + + credentials.push(credential) + inputDescriptorsToCredentials[inputDescriptorId] = credentials + subjectsToInputDescriptors[subjectId] = inputDescriptorsToCredentials + } + + private getPresentationFormat( + presentationDefinition: PresentationDefinition, + credentials: Array + ): ClaimFormat.JwtVp | ClaimFormat.LdpVp { + const allCredentialsAreJwtVc = credentials?.every((c) => typeof c === 'string') + const allCredentialsAreLdpVc = credentials?.every((c) => typeof c !== 'string') + + const inputDescriptorsNotSupportingJwtVc = ( + presentationDefinition.input_descriptors as Array + ).filter((d) => d.format && d.format.jwt_vc === undefined) + + const inputDescriptorsNotSupportingLdpVc = ( + presentationDefinition.input_descriptors as Array + ).filter((d) => d.format && d.format.ldp_vc === undefined) + + if ( + allCredentialsAreJwtVc && + (presentationDefinition.format === undefined || presentationDefinition.format.jwt_vc) && + inputDescriptorsNotSupportingJwtVc.length === 0 + ) { + return ClaimFormat.JwtVp + } else if ( + allCredentialsAreLdpVc && + (presentationDefinition.format === undefined || presentationDefinition.format.ldp_vc) && + inputDescriptorsNotSupportingLdpVc.length === 0 + ) { + return ClaimFormat.LdpVp + } else { + throw new PresentationExchangeError( + 'No suitable presentation format found for the given presentation definition, and credentials' + ) + } + } + + public async createPresentation( + agentContext: AgentContext, + options: { + credentialsForInputDescriptor: InputDescriptorToCredentials + presentationDefinition: PresentationDefinition + challenge?: string + domain?: string + nonce?: string + } + ) { + const { presentationDefinition, challenge, nonce, domain } = options + + const proofStructure: ProofStructure = {} + + Object.entries(options.credentialsForInputDescriptor).forEach(([inputDescriptorId, credentials]) => { + credentials.forEach((credential) => { + const subjectId = credential.credentialSubjectIds[0] + if (!subjectId) { + throw new PresentationExchangeError('Missing required credential subject for creating the presentation.') + } + + this.addCredentialToSubjectInputDescriptor(proofStructure, subjectId, inputDescriptorId, credential) + }) + }) + + const verifiablePresentationResultsWithFormat: Array<{ + verifiablePresentationResult: VerifiablePresentationResult + format: ClaimFormat.LdpVp | ClaimFormat.JwtVp + }> = [] + + const subjectToInputDescriptors = Object.entries(proofStructure) + for (const [subjectId, subjectInputDescriptorsToCredentials] of subjectToInputDescriptors) { + // Determine a suitable verification method for the presentation + const verificationMethod = await this.getVerificationMethodForSubjectId(agentContext, subjectId) + + if (!verificationMethod) { + throw new PresentationExchangeError(`No verification method found for subject id '${subjectId}'.`) + } + + // We create a presentation for each subject + // Thus for each subject we need to filter all the related input descriptors and credentials + // FIXME: cast to V1, as tsc errors for strange reasons if not + const inputDescriptorsForSubject = (presentationDefinition as PresentationDefinitionV1).input_descriptors.filter( + (inputDescriptor) => inputDescriptor.id in subjectInputDescriptorsToCredentials + ) + + // Get all the credentials associated with the input descriptors + const credentialsForSubject = Object.values(subjectInputDescriptorsToCredentials) + .flatMap((credentials) => credentials) + .map(getSphereonOriginalVerifiableCredential) + + const presentationDefinitionForSubject: PresentationDefinition = { + ...presentationDefinition, + input_descriptors: inputDescriptorsForSubject, + + // We remove the submission requirements, as it will otherwise fail to create the VP + submission_requirements: undefined, + } + + const format = this.getPresentationFormat(presentationDefinitionForSubject, credentialsForSubject) + + // FIXME: Q1: is holder always subject id, what if there are multiple subjects??? + // FIXME: Q2: What about proofType, proofPurpose verification method for multiple subjects? + const verifiablePresentationResult = await this.pex.verifiablePresentationFrom( + presentationDefinitionForSubject, + credentialsForSubject, + this.getPresentationSignCallback(agentContext, verificationMethod, format), + { + holderDID: subjectId, + proofOptions: { challenge, domain, nonce }, + signatureOptions: { verificationMethod: verificationMethod?.id }, + presentationSubmissionLocation: PresentationSubmissionLocation.EXTERNAL, + } + ) + + verifiablePresentationResultsWithFormat.push({ verifiablePresentationResult, format }) + } + + if (!verifiablePresentationResultsWithFormat[0]) { + throw new PresentationExchangeError('No verifiable presentations created.') + } + + if (!verifiablePresentationResultsWithFormat[0]) { + throw new PresentationExchangeError('No verifiable presentations created.') + } + + if (subjectToInputDescriptors.length !== verifiablePresentationResultsWithFormat.length) { + throw new PresentationExchangeError('Invalid amount of verifiable presentations created.') + } + + verifiablePresentationResultsWithFormat[0].verifiablePresentationResult.presentationSubmission + const presentationSubmission: PexPresentationSubmission = { + id: verifiablePresentationResultsWithFormat[0].verifiablePresentationResult.presentationSubmission.id, + definition_id: + verifiablePresentationResultsWithFormat[0].verifiablePresentationResult.presentationSubmission.definition_id, + descriptor_map: [], + } + + for (const vpf of verifiablePresentationResultsWithFormat) { + const { verifiablePresentationResult } = vpf + presentationSubmission.descriptor_map.push(...verifiablePresentationResult.presentationSubmission.descriptor_map) + } + + return { + verifiablePresentations: verifiablePresentationResultsWithFormat.map((r) => + getW3cVerifiablePresentationInstance(r.verifiablePresentationResult.verifiablePresentation) + ), + presentationSubmission, + presentationSubmissionLocation: + verifiablePresentationResultsWithFormat[0].verifiablePresentationResult.presentationSubmissionLocation, + } + } + + private getSigningAlgorithmFromVerificationMethod( + verificationMethod: VerificationMethod, + suitableAlgorithms?: Array + ) { + const key = getKeyFromVerificationMethod(verificationMethod) + const jwk = getJwkFromKey(key) + + if (suitableAlgorithms) { + const possibleAlgorithms = jwk.supportedSignatureAlgorithms.filter((alg) => suitableAlgorithms?.includes(alg)) + if (!possibleAlgorithms || possibleAlgorithms.length === 0) { + throw new PresentationExchangeError( + [ + `Found no suitable signing algorithm.`, + `Algorithms supported by Verification method: ${jwk.supportedSignatureAlgorithms.join(', ')}`, + `Suitable algorithms: ${suitableAlgorithms.join(', ')}`, + ].join('\n') + ) + } + } + + const alg = jwk.supportedSignatureAlgorithms[0] + if (!alg) throw new PresentationExchangeError(`No supported algs for key type: ${key.keyType}`) + return alg + } + + private getSigningAlgorithmsForPresentationDefinitionAndInputDescriptors( + algorithmsSatisfyingDefinition: Array, + inputDescriptorAlgorithms: Array> + ) { + const allDescriptorAlgorithms = inputDescriptorAlgorithms.flat() + const algorithmsSatisfyingDescriptors = allDescriptorAlgorithms.filter((alg) => + inputDescriptorAlgorithms.every((descriptorAlgorithmSet) => descriptorAlgorithmSet.includes(alg)) + ) + + const algorithmsSatisfyingPdAndDescriptorRestrictions = algorithmsSatisfyingDefinition.filter((alg) => + algorithmsSatisfyingDescriptors.includes(alg) + ) + + if ( + algorithmsSatisfyingDefinition.length > 0 && + algorithmsSatisfyingDescriptors.length > 0 && + algorithmsSatisfyingPdAndDescriptorRestrictions.length === 0 + ) { + throw new PresentationExchangeError( + `No signature algorithm found for satisfying restrictions of the presentation definition and input descriptors.` + ) + } + + if (allDescriptorAlgorithms.length > 0 && algorithmsSatisfyingDescriptors.length === 0) { + throw new PresentationExchangeError( + `No signature algorithm found for satisfying restrictions of the input descriptors.` + ) + } + + let suitableAlgorithms: Array | undefined + if (algorithmsSatisfyingPdAndDescriptorRestrictions.length > 0) { + suitableAlgorithms = algorithmsSatisfyingPdAndDescriptorRestrictions + } else if (algorithmsSatisfyingDescriptors.length > 0) { + suitableAlgorithms = algorithmsSatisfyingDescriptors + } else if (algorithmsSatisfyingDefinition.length > 0) { + suitableAlgorithms = algorithmsSatisfyingDefinition + } + + return suitableAlgorithms + } + + private getSigningAlgorithmForJwtVc( + presentationDefinition: PresentationDefinition, + verificationMethod: VerificationMethod + ) { + const algorithmsSatisfyingDefinition = presentationDefinition.format?.jwt_vc?.alg ?? [] + + const inputDescriptorAlgorithms: Array> = presentationDefinition.input_descriptors + .map((descriptor) => (descriptor as InputDescriptorV2).format?.jwt_vc?.alg ?? []) + .filter((alg) => alg.length > 0) + + const suitableAlgorithms = this.getSigningAlgorithmsForPresentationDefinitionAndInputDescriptors( + algorithmsSatisfyingDefinition, + inputDescriptorAlgorithms + ) + + return this.getSigningAlgorithmFromVerificationMethod(verificationMethod, suitableAlgorithms) + } + + private getProofTypeForLdpVc( + agentContext: AgentContext, + presentationDefinition: PresentationDefinition, + verificationMethod: VerificationMethod + ) { + const algorithmsSatisfyingDefinition = presentationDefinition.format?.ldp_vc?.proof_type ?? [] + + const inputDescriptorAlgorithms: Array> = presentationDefinition.input_descriptors + .map((descriptor) => (descriptor as InputDescriptorV2).format?.ldp_vc?.proof_type ?? []) + .filter((alg) => alg.length > 0) + + const suitableSignatureSuites = this.getSigningAlgorithmsForPresentationDefinitionAndInputDescriptors( + algorithmsSatisfyingDefinition, + inputDescriptorAlgorithms + ) + + // For each of the supported algs, find the key types, then find the proof types + const signatureSuiteRegistry = agentContext.dependencyManager.resolve(SignatureSuiteRegistry) + + const supportedSignatureSuite = signatureSuiteRegistry.getByVerificationMethodType(verificationMethod.type) + if (!supportedSignatureSuite) { + throw new PresentationExchangeError( + `Couldn't find a supported signature suite for the given verification method type '${verificationMethod.type}'.` + ) + } + + if (suitableSignatureSuites) { + if (suitableSignatureSuites.includes(supportedSignatureSuite.proofType) === false) { + throw new PresentationExchangeError( + [ + 'No possible signature suite found for the given verification method.', + `Verification method type: ${verificationMethod.type}`, + `SupportedSignatureSuite '${supportedSignatureSuite.proofType}'`, + `SuitableSignatureSuites: ${suitableSignatureSuites.join(', ')}`, + ].join('\n') + ) + } + + return supportedSignatureSuite.proofType + } + + return supportedSignatureSuite.proofType + } + + public getPresentationSignCallback( + agentContext: AgentContext, + verificationMethod: VerificationMethod, + vpFormat: ClaimFormat.LdpVp | ClaimFormat.JwtVp + ) { + const w3cCredentialService = agentContext.dependencyManager.resolve(W3cCredentialService) + + return async (callBackParams: PresentationSignCallBackParams) => { + // The created partial proof and presentation, as well as original supplied options + const { presentation: presentationJson, options, presentationDefinition } = callBackParams + const { challenge, domain, nonce } = options.proofOptions ?? {} + const { verificationMethod: verificationMethodId } = options.signatureOptions ?? {} + + if (verificationMethodId && verificationMethodId !== verificationMethod.id) { + throw new PresentationExchangeError( + `Verification method from signing options ${verificationMethodId} does not match verification method ${verificationMethod.id}.` + ) + } + + // Clients MUST ignore any presentation_submission element included inside a Verifiable Presentation. + const presentationToSign = { ...presentationJson, presentation_submission: undefined } + + let signedPresentation: W3cVerifiablePresentation + if (vpFormat === 'jwt_vp') { + signedPresentation = await w3cCredentialService.signPresentation(agentContext, { + format: ClaimFormat.JwtVp, + alg: this.getSigningAlgorithmForJwtVc(presentationDefinition, verificationMethod), + verificationMethod: verificationMethod.id, + presentation: JsonTransformer.fromJSON(presentationToSign, W3cPresentation), + challenge: challenge ?? nonce ?? (await agentContext.wallet.generateNonce()), + domain, + }) + } else if (vpFormat === 'ldp_vp') { + signedPresentation = await w3cCredentialService.signPresentation(agentContext, { + format: ClaimFormat.LdpVp, + proofType: this.getProofTypeForLdpVc(agentContext, presentationDefinition, verificationMethod), + proofPurpose: 'authentication', + verificationMethod: verificationMethod.id, + presentation: JsonTransformer.fromJSON(presentationToSign, W3cPresentation), + challenge: challenge ?? nonce ?? (await agentContext.wallet.generateNonce()), + domain, + }) + } else { + throw new PresentationExchangeError( + `Only JWT credentials or JSONLD credentials are supported for a single presentation.` + ) + } + + return getSphereonW3cVerifiablePresentation(signedPresentation) + } + } + + private async getVerificationMethodForSubjectId(agentContext: AgentContext, subjectId: string) { + const didsApi = agentContext.dependencyManager.resolve(DidsApi) + + if (!subjectId.startsWith('did:')) { + throw new PresentationExchangeError( + `Only dids are supported as credentialSubject id. ${subjectId} is not a valid did` + ) + } + + const didDocument = await didsApi.resolveDidDocument(subjectId) + + if (!didDocument.authentication || didDocument.authentication.length === 0) { + throw new PresentationExchangeError( + `No authentication verificationMethods found for did ${subjectId} in did document` + ) + } + + // the signature suite to use for the presentation is dependant on the credentials we share. + // 1. Get the verification method for this given proof purpose in this DID document + let [verificationMethod] = didDocument.authentication + if (typeof verificationMethod === 'string') { + verificationMethod = didDocument.dereferenceKey(verificationMethod, ['authentication']) + } + + return verificationMethod + } +} diff --git a/packages/presentation-exchange/src/index.ts b/packages/presentation-exchange/src/index.ts new file mode 100644 index 0000000000..0bb3c76aae --- /dev/null +++ b/packages/presentation-exchange/src/index.ts @@ -0,0 +1,4 @@ +export * from './PresentationExchangeError' +export * from './PresentationExchangeModule' +export * from './PresentationExchangeService' +export * from './models' diff --git a/packages/presentation-exchange/src/models/PresentationSubmission.ts b/packages/presentation-exchange/src/models/PresentationSubmission.ts new file mode 100644 index 0000000000..28f9209e5a --- /dev/null +++ b/packages/presentation-exchange/src/models/PresentationSubmission.ts @@ -0,0 +1,119 @@ +import type { W3cCredentialRecord, W3cVerifiableCredential } from '@aries-framework/core' + +export interface PresentationSubmission { + /** + * Whether all requirements have been satisfied by the credentials in the wallet. + */ + areRequirementsSatisfied: boolean + + /** + * The requirements for the presentation definition. If the `areRequirementsSatisfied` value + * is `false`, this list will still be populated with requirements, but won't contain credentials + * for all requirements. This can be useful to display the missing credentials for a presentation + * definition to be satisfied. + * + * NOTE: Presentation definition requirements can be really complex as there's a lot of different + * combinations that are possible. The structure doesn't include all possible combinations yet that + * could satisfy a presentation definition. + */ + requirements: PresentationSubmissionRequirement[] + + /** + * Name of the presentation definition + */ + name?: string + + /** + * Purpose of the presentation definition. + */ + purpose?: string +} + +/** + * A requirement for the presentation submission. A requirement + * is a group of input descriptors that together fulfill a requirement + * from the presentation definition. + * + * Each submission represents a input descriptor. + */ +export interface PresentationSubmissionRequirement { + /** + * Whether the requirement is satisfied. + * + * If the requirement is not satisfied, the submission will still contain + * entries, but the `verifiableCredentials` list will be empty. + */ + isRequirementSatisfied: boolean + + /** + * Name of the requirement + */ + name?: string + + /** + * Purpose of the requirement + */ + purpose?: string + + /** + * Array of objects, where each entry contains a credential that will be part + * of the submission. + * + * NOTE: if the `isRequirementSatisfied` is `false` the submission list will + * contain entries where the verifiable credential list is empty. In this case it could also + * contain more entries than are actually needed (as you sometimes can choose from + * e.g. 4 types of credentials and need to submit at least two). If + * `isRequirementSatisfied` is `false`, make sure to check the `needsCount` value + * to see how many of those submissions needed. + */ + submissionEntry: SubmissionEntry[] + + /** + * The number of submission entries that are needed to fulfill the requirement. + * If `isRequirementSatisfied` is `true`, the submission list will always be equal + * to the number of `needsCount`. If `isRequirementSatisfied` is `false` the list of + * submissions could be longer. + */ + needsCount: number + + /** + * The rule that is used to select the credentials for the submission. + * If the rule is `pick`, the user can select which credentials to use for the submission. + * If the rule is `all`, all credentials that satisfy the input descriptor will be used. + */ + rule: 'pick' | 'all' +} + +/** + * A submission entry that satisfies a specific input descriptor from the + * presentation definition. + */ +export interface SubmissionEntry { + /** + * The id of the input descriptor + */ + inputDescriptorId: string + + /** + * Name of the input descriptor + */ + name?: string + + /** + * Purpose of the input descriptor + */ + purpose?: string + + /** + * The verifiable credentials that satisfy the input descriptor. + * + * If the value is an empty list, it means the input descriptor could + * not be satisfied. + */ + verifiableCredentials: W3cCredentialRecord[] +} + +/** + * Mapping of selected credentials for an input descriptor + */ +export type InputDescriptorToCredentials = Record> diff --git a/packages/presentation-exchange/src/models/index.ts b/packages/presentation-exchange/src/models/index.ts new file mode 100644 index 0000000000..47247cbbc9 --- /dev/null +++ b/packages/presentation-exchange/src/models/index.ts @@ -0,0 +1 @@ +export * from './PresentationSubmission' diff --git a/packages/presentation-exchange/src/utils/credentialSelection.ts b/packages/presentation-exchange/src/utils/credentialSelection.ts new file mode 100644 index 0000000000..966af823c3 --- /dev/null +++ b/packages/presentation-exchange/src/utils/credentialSelection.ts @@ -0,0 +1,300 @@ +import type { PresentationSubmission, PresentationSubmissionRequirement, SubmissionEntry } from '../models' +import type { W3cCredentialRecord } from '@aries-framework/core' +import type { IPresentationDefinition, SelectResults, SubmissionRequirementMatch } from '@sphereon/pex' +import type { InputDescriptorV1, InputDescriptorV2, SubmissionRequirement } from '@sphereon/pex-models' + +import { AriesFrameworkError } from '@aries-framework/core' +import { PEX } from '@sphereon/pex' +import { Rules } from '@sphereon/pex-models' +import { default as jp } from 'jsonpath' + +import { getSphereonOriginalVerifiableCredential } from './transform' + +export async function selectCredentialsForRequest( + presentationDefinition: IPresentationDefinition, + credentialRecords: Array, + holderDIDs: Array +): Promise { + const encodedCredentials = credentialRecords.map((c) => getSphereonOriginalVerifiableCredential(c.credential)) + + if (!presentationDefinition) { + throw new AriesFrameworkError('Presentation Definition is required to select credentials for submission.') + } + + const pex = new PEX() + + // FIXME: there is a function for this in the VP library, but it is not usable atm + const selectResultsRaw = pex.selectFrom(presentationDefinition, encodedCredentials, { + holderDIDs, + // limitDisclosureSignatureSuites: [], + // restrictToDIDMethods, + // restrictToFormats + }) + + const selectResults = { + ...selectResultsRaw, + // Map the encoded credential to their respective w3c credential record + verifiableCredential: selectResultsRaw.verifiableCredential?.map((encoded) => { + const credentialIndex = encodedCredentials.indexOf(encoded) + const credentialRecord = credentialRecords[credentialIndex] + if (!credentialRecord) throw new AriesFrameworkError('Unable to find credential in credential records.') + + return credentialRecord + }), + } + + const presentationSubmission: PresentationSubmission = { + requirements: [], + areRequirementsSatisfied: false, + name: presentationDefinition.name, + purpose: presentationDefinition.purpose, + } + + // If there's no submission requirements, ALL input descriptors MUST be satisfied + if (!presentationDefinition.submission_requirements || presentationDefinition.submission_requirements.length === 0) { + presentationSubmission.requirements = getSubmissionRequirementsForAllInputDescriptors( + presentationDefinition.input_descriptors, + selectResults + ) + } else { + presentationSubmission.requirements = getSubmissionRequirements(presentationDefinition, selectResults) + } + + // There may be no requirements if we filter out all optional ones. To not makes things too complicated, we see it as an error + // for now if a request is made that has no required requirements (but only e.g. min: 0, which means we don't need to disclose anything) + // I see this more as the fault of the presentation definition, as it should have at least some requirements. + if (presentationSubmission.requirements.length === 0) { + throw new AriesFrameworkError( + 'Presentation Definition does not require any credentials. Optional credentials are not included in the presentation submission.' + ) + } + if (selectResultsRaw.areRequiredCredentialsPresent === 'error') { + return presentationSubmission + } + + return { + ...presentationSubmission, + + // If all requirements are satisfied, the presentation submission is satisfied + areRequirementsSatisfied: presentationSubmission.requirements.every( + (requirement) => requirement.isRequirementSatisfied + ), + } +} + +function getSubmissionRequirements( + presentationDefinition: IPresentationDefinition, + selectResults: W3cCredentialRecordSelectResults +): Array { + const submissionRequirements: Array = [] + + // There are submission requirements, so we need to select the input_descriptors + // based on the submission requirements + for (const submissionRequirement of presentationDefinition.submission_requirements ?? []) { + // Check: if the submissionRequirement uses `from_nested`, as we don't support this yet + if (submissionRequirement.from_nested) { + throw new AriesFrameworkError( + "Presentation definition contains requirement using 'from_nested', which is not supported yet." + ) + } + + // Check if there's a 'from'. If not the structure is not as we expect it + if (!submissionRequirement.from) { + throw new AriesFrameworkError("Missing 'from' in submission requirement match") + } + + if (submissionRequirement.rule === Rules.All) { + const selectedSubmission = getSubmissionRequirementRuleAll( + submissionRequirement, + presentationDefinition, + selectResults + ) + submissionRequirements.push(selectedSubmission) + } else { + const selectedSubmission = getSubmissionRequirementRulePick( + submissionRequirement, + presentationDefinition, + selectResults + ) + + submissionRequirements.push(selectedSubmission) + } + } + + // Submission may have requirement that doesn't require a credential to be submitted (e.g. min: 0) + // We use minimization strategy, and thus only disclose the minimum amount of information + const requirementsWithCredentials = submissionRequirements.filter((requirement) => requirement.needsCount > 0) + + return requirementsWithCredentials +} + +function getSubmissionRequirementsForAllInputDescriptors( + inputDescriptors: Array | Array, + selectResults: W3cCredentialRecordSelectResults +): Array { + const submissionRequirements: Array = [] + + for (const inputDescriptor of inputDescriptors) { + const submission = getSubmissionForInputDescriptor(inputDescriptor, selectResults) + + submissionRequirements.push({ + rule: Rules.Pick, + needsCount: 1, // Every input descriptor is a distinct requirement, so the count is always 1, + submissionEntry: [submission], + isRequirementSatisfied: submission.verifiableCredentials.length >= 1, + }) + } + + return submissionRequirements +} + +function getSubmissionRequirementRuleAll( + submissionRequirement: SubmissionRequirement, + presentationDefinition: IPresentationDefinition, + selectResults: W3cCredentialRecordSelectResults +) { + // Check if there's a 'from'. If not the structure is not as we expect it + if (!submissionRequirement.from) throw new AriesFrameworkError("Missing 'from' in submission requirement match.") + + const selectedSubmission: PresentationSubmissionRequirement = { + rule: Rules.All, + needsCount: 0, + name: submissionRequirement.name, + purpose: submissionRequirement.purpose, + submissionEntry: [], + isRequirementSatisfied: false, + } + + for (const inputDescriptor of presentationDefinition.input_descriptors) { + // We only want to get the submission if the input descriptor belongs to the group + if (!inputDescriptor.group?.includes(submissionRequirement.from)) continue + + const submission = getSubmissionForInputDescriptor(inputDescriptor, selectResults) + + // Rule ALL, so for every input descriptor that matches in this group, we need to add it + selectedSubmission.needsCount += 1 + selectedSubmission.submissionEntry.push(submission) + } + + return { + ...selectedSubmission, + + // If all submissions have a credential, the requirement is satisfied + isRequirementSatisfied: selectedSubmission.submissionEntry.every( + (submission) => submission.verifiableCredentials.length >= 1 + ), + } +} + +function getSubmissionRequirementRulePick( + submissionRequirement: SubmissionRequirement, + presentationDefinition: IPresentationDefinition, + selectResults: W3cCredentialRecordSelectResults +) { + // Check if there's a 'from'. If not the structure is not as we expect it + if (!submissionRequirement.from) throw new AriesFrameworkError("Missing 'from' in submission requirement match.") + + const selectedSubmission: PresentationSubmissionRequirement = { + rule: 'pick', + needsCount: submissionRequirement.count ?? submissionRequirement.min ?? 1, + name: submissionRequirement.name, + purpose: submissionRequirement.purpose, + // If there's no count, min, or max we assume one credential is required for submission + // however, the exact behavior is not specified in the spec + submissionEntry: [], + isRequirementSatisfied: false, + } + + const satisfiedSubmissions: Array = [] + const unsatisfiedSubmissions: Array = [] + + for (const inputDescriptor of presentationDefinition.input_descriptors) { + // We only want to get the submission if the input descriptor belongs to the group + if (!inputDescriptor.group?.includes(submissionRequirement.from)) continue + + const submission = getSubmissionForInputDescriptor(inputDescriptor, selectResults) + + if (submission.verifiableCredentials.length >= 1) { + satisfiedSubmissions.push(submission) + } else { + unsatisfiedSubmissions.push(submission) + } + + // If we have found enough credentials to satisfy the requirement, we could stop + // but the user may not want the first x that match, so we continue and return all matches + // if (satisfiedSubmissions.length === selectedSubmission.needsCount) break + } + + return { + ...selectedSubmission, + + // If there are enough satisfied submissions, the requirement is satisfied + isRequirementSatisfied: satisfiedSubmissions.length >= selectedSubmission.needsCount, + + // if the requirement is satisfied, we only need to return the satisfied submissions + // however if the requirement is not satisfied, we include all entries so the wallet could + // render which credentials are missing. + submission: + satisfiedSubmissions.length >= selectedSubmission.needsCount + ? satisfiedSubmissions + : [...satisfiedSubmissions, ...unsatisfiedSubmissions], + } +} + +function getSubmissionForInputDescriptor( + inputDescriptor: InputDescriptorV1 | InputDescriptorV2, + selectResults: W3cCredentialRecordSelectResults +): SubmissionEntry { + // https://github.com/Sphereon-Opensource/PEX/issues/116 + // If the input descriptor doesn't contain a name, the name of the match will be the id of the input descriptor that satisfied it + const matchesForInputDescriptor = selectResults.matches?.filter( + (m) => + m.name === inputDescriptor.id || + // FIXME: this is not collision proof as the name doesn't have to be unique + m.name === inputDescriptor.name + ) + + const submissionEntry: SubmissionEntry = { + inputDescriptorId: inputDescriptor.id, + name: inputDescriptor.name, + purpose: inputDescriptor.purpose, + verifiableCredentials: [], + } + + // return early if no matches. + if (!matchesForInputDescriptor?.length) return submissionEntry + + // FIXME: This can return multiple credentials for multiple input_descriptors, + // which I think is a bug in the PEX library + // Extract all credentials from the match + const verifiableCredentials = matchesForInputDescriptor.flatMap((matchForInputDescriptor) => + extractCredentialsFromMatch(matchForInputDescriptor, selectResults.verifiableCredential) + ) + + submissionEntry.verifiableCredentials = verifiableCredentials + + return submissionEntry +} + +function extractCredentialsFromMatch( + match: SubmissionRequirementMatch, + availableCredentials?: Array +) { + const verifiableCredentials: Array = [] + + for (const vcPath of match.vc_path) { + const [verifiableCredential] = jp.query({ verifiableCredential: availableCredentials }, vcPath) as [ + W3cCredentialRecord + ] + verifiableCredentials.push(verifiableCredential) + } + + return verifiableCredentials +} + +/** + * Custom SelectResults that include the W3cCredentialRecord instead of the encoded verifiable credential + */ +export type W3cCredentialRecordSelectResults = Omit & { + verifiableCredential?: Array +} diff --git a/packages/presentation-exchange/src/utils/index.ts b/packages/presentation-exchange/src/utils/index.ts new file mode 100644 index 0000000000..aaf44fa1b6 --- /dev/null +++ b/packages/presentation-exchange/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './transform' +export * from './credentialSelection' diff --git a/packages/presentation-exchange/src/utils/transform.ts b/packages/presentation-exchange/src/utils/transform.ts new file mode 100644 index 0000000000..a97513b9be --- /dev/null +++ b/packages/presentation-exchange/src/utils/transform.ts @@ -0,0 +1,78 @@ +import type { W3cVerifiableCredential, W3cVerifiablePresentation } from '@aries-framework/core' +import type { + OriginalVerifiableCredential as SphereonOriginalVerifiableCredential, + W3CVerifiableCredential as SphereonW3cVerifiableCredential, + W3CVerifiablePresentation as SphereonW3cVerifiablePresentation, +} from '@sphereon/ssi-types' + +import { + AriesFrameworkError, + JsonTransformer, + W3cJsonLdVerifiableCredential, + W3cJsonLdVerifiablePresentation, + W3cJwtVerifiableCredential, + W3cJwtVerifiablePresentation, + ClaimFormat, +} from '@aries-framework/core' + +export function getSphereonOriginalVerifiableCredential( + w3cVerifiableCredential: W3cVerifiableCredential +): SphereonOriginalVerifiableCredential { + if (w3cVerifiableCredential.claimFormat === ClaimFormat.LdpVc) { + return JsonTransformer.toJSON(w3cVerifiableCredential) as SphereonOriginalVerifiableCredential + } else if (w3cVerifiableCredential.claimFormat === ClaimFormat.JwtVc) { + return w3cVerifiableCredential.serializedJwt + } else { + throw new AriesFrameworkError( + `Unsupported claim format. Only ${ClaimFormat.LdpVc} and ${ClaimFormat.JwtVc} are supported.` + ) + } +} + +export function getSphereonW3cVerifiableCredential( + w3cVerifiableCredential: W3cVerifiableCredential +): SphereonW3cVerifiableCredential { + if (w3cVerifiableCredential.claimFormat === ClaimFormat.LdpVc) { + return JsonTransformer.toJSON(w3cVerifiableCredential) as SphereonW3cVerifiableCredential + } else if (w3cVerifiableCredential.claimFormat === ClaimFormat.JwtVc) { + return w3cVerifiableCredential.serializedJwt + } else { + throw new AriesFrameworkError( + `Unsupported claim format. Only ${ClaimFormat.LdpVc} and ${ClaimFormat.JwtVc} are supported.` + ) + } +} + +export function getSphereonW3cVerifiablePresentation( + w3cVerifiablePresentation: W3cVerifiablePresentation +): SphereonW3cVerifiablePresentation { + if (w3cVerifiablePresentation instanceof W3cJsonLdVerifiablePresentation) { + return JsonTransformer.toJSON(w3cVerifiablePresentation) as SphereonW3cVerifiablePresentation + } else if (w3cVerifiablePresentation instanceof W3cJwtVerifiablePresentation) { + return w3cVerifiablePresentation.serializedJwt + } else { + throw new AriesFrameworkError( + `Unsupported claim format. Only ${ClaimFormat.LdpVc} and ${ClaimFormat.JwtVc} are supported.` + ) + } +} + +export function getW3cVerifiablePresentationInstance( + w3cVerifiablePresentation: SphereonW3cVerifiablePresentation +): W3cVerifiablePresentation { + if (typeof w3cVerifiablePresentation === 'string') { + return W3cJwtVerifiablePresentation.fromSerializedJwt(w3cVerifiablePresentation) + } else { + return JsonTransformer.fromJSON(w3cVerifiablePresentation, W3cJsonLdVerifiablePresentation) + } +} + +export function getW3cVerifiableCredentialInstance( + w3cVerifiableCredential: SphereonW3cVerifiableCredential +): W3cVerifiableCredential { + if (typeof w3cVerifiableCredential === 'string') { + return W3cJwtVerifiableCredential.fromSerializedJwt(w3cVerifiableCredential) + } else { + return JsonTransformer.fromJSON(w3cVerifiableCredential, W3cJsonLdVerifiableCredential) + } +} diff --git a/packages/presentation-exchange/tsconfig.build.json b/packages/presentation-exchange/tsconfig.build.json new file mode 100644 index 0000000000..0a015be666 --- /dev/null +++ b/packages/presentation-exchange/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.build.json", + + "compilerOptions": { + "outDir": "./build" + }, + + "include": ["src/**/*", "types"] +} diff --git a/packages/presentation-exchange/tsconfig.json b/packages/presentation-exchange/tsconfig.json new file mode 100644 index 0000000000..93d9dd32b5 --- /dev/null +++ b/packages/presentation-exchange/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "allowJs": false, + "typeRoots": ["../../node_modules/@types", "src/types"], + "types": ["jest"] + } +} diff --git a/yarn.lock b/yarn.lock index abae25902c..7f2ecb49e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,6 +32,13 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" +"@astronautlabs/jsonpath@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@astronautlabs/jsonpath/-/jsonpath-1.1.2.tgz#af19bb4a7d13dcfbc60c3c998ee1e73d7c2ddc38" + integrity sha512-FqL/muoreH7iltYC1EB5Tvox5E8NSOOPGkgns4G+qxRKl6k5dxEVljUjB5NcKESzkqwnUqWjSZkL61XGYOuV+A== + dependencies: + static-eval "2.0.2" + "@azure/core-asynciterator-polyfill@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.2.tgz#0dd3849fb8d97f062a39db0e5cadc9ffaf861fec" @@ -2572,6 +2579,32 @@ debug "^4.3.4" uint8arrays "^3.1.1" +"@sphereon/pex-models@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@sphereon/pex-models/-/pex-models-2.1.2.tgz#e1a0ce16ccc6b32128fc8c2da79d65fc35f6d10f" + integrity sha512-Ec1qZl8tuPd+s6E+ZM7v+HkGkSOjGDMLNN1kqaxAfWpITBYtTLb+d5YvwjvBZ1P2upZ7zwNER97FfW5n/30y2w== + +"@sphereon/pex@^2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@sphereon/pex/-/pex-2.2.2.tgz#3df9ed75281b46f0899256774060ed2ff982fade" + integrity sha512-NkR8iDTC2PSnYsOHlG2M2iOpFTTbzszs2/pL3iK3Dlv9QYLqX7NtPAlmeSwaoVP1NB1ewcs6U1DtemQAD+90yQ== + dependencies: + "@astronautlabs/jsonpath" "^1.1.2" + "@sphereon/pex-models" "^2.1.2" + "@sphereon/ssi-types" "^0.17.5" + ajv "^8.12.0" + ajv-formats "^2.1.1" + jwt-decode "^3.1.2" + nanoid "^3.3.6" + string.prototype.matchall "^4.0.8" + +"@sphereon/ssi-types@^0.17.5": + version "0.17.5" + resolved "https://registry.yarnpkg.com/@sphereon/ssi-types/-/ssi-types-0.17.5.tgz#7b4de0326e7c2993ab816caeef6deaea41a5f65f" + integrity sha512-hoQOkeOtshvIzNAG+HTqcKxeGssLVfwX7oILHJgs6VMb1GhR6QlqjMAxflDxZ/8Aq2R0I6fEPWmf73zAXY2X2Q== + dependencies: + jwt-decode "^3.1.2" + "@sphereon/ssi-types@^0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@sphereon/ssi-types/-/ssi-types-0.9.0.tgz#d140eb6abd77381926d0da7ac51b3c4b96a31b4b" @@ -2929,6 +2962,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/jsonpath@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@types/jsonpath/-/jsonpath-0.2.4.tgz#065be59981c1420832835af656377622271154be" + integrity sha512-K3hxB8Blw0qgW6ExKgMbXQv2UPZBoE2GqLpVY+yr7nMD2Pq86lsuIzyAaiQ7eMqFL5B6di6pxSkogLJEyEHoGA== + "@types/long@^4.0.1": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" @@ -3290,6 +3328,13 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -3300,6 +3345,16 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0, ajv@^8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + anser@^1.4.9: version "1.4.10" resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" @@ -3534,6 +3589,19 @@ array.prototype.flatmap@^1.3.1: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -4120,6 +4188,15 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + caller-callsite@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" @@ -4906,7 +4983,7 @@ deep-extend@^0.6.0, deep-extend@~0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@^0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== @@ -4928,6 +5005,15 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" @@ -5270,6 +5356,51 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: unbox-primitive "^1.0.2" which-typed-array "^1.1.9" +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -5346,6 +5477,18 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escodegen@^1.8.1: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-prettier@^8.3.0: version "8.8.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" @@ -5492,7 +5635,12 @@ espree@^9.5.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.0" -esprima@^4.0.0, esprima@~4.0.0: +esprima@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b" + integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== + +esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -5511,7 +5659,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -5771,7 +5919,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-sta resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@^2.0.6: +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 sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== @@ -6086,6 +6234,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.prototype.name@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" @@ -6096,6 +6249,16 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + functions-have-names@^1.2.2, functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -6177,6 +6340,16 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -6540,6 +6713,13 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hermes-estree@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.8.0.tgz#530be27243ca49f008381c1f3e8b18fb26bf9ec0" @@ -7183,6 +7363,13 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" +is-typed-array@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" @@ -7217,6 +7404,11 @@ isarray@1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -7908,6 +8100,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + 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" @@ -7968,6 +8165,15 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +jsonpath@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901" + integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w== + dependencies: + esprima "1.2.2" + static-eval "2.0.2" + underscore "1.12.1" + just-diff-apply@^5.2.0: version "5.5.0" resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.5.0.tgz#771c2ca9fa69f3d2b54e7c3f5c1dfcbcc47f9f0f" @@ -8127,6 +8333,14 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + libnpmaccess@6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-6.0.3.tgz#473cc3e4aadb2bc713419d92e45d23b070d8cded" @@ -9110,6 +9324,11 @@ nan@^2.11.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nanoid@^3.3.6: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -9724,6 +9943,11 @@ object-inspect@^1.10.3, object-inspect@^1.12.3, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -9811,6 +10035,18 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -10195,6 +10431,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -10801,6 +11042,15 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.2.0" functions-have-names "^1.2.3" +regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + regexpu-core@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" @@ -10835,6 +11085,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -10968,6 +11223,16 @@ rxjs@^7.2.0, rxjs@^7.5.5, rxjs@^7.8.0: dependencies: tslib "^2.1.0" +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -11088,6 +11353,25 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -11398,6 +11682,13 @@ stacktrace-parser@^0.1.3: dependencies: type-fest "^0.7.1" +static-eval@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" + integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg== + dependencies: + escodegen "^1.8.1" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -11457,6 +11748,21 @@ string-width@^1.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.matchall@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" + integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + regexp.prototype.flags "^1.5.0" + set-function-name "^2.0.0" + side-channel "^1.0.4" + string.prototype.trim@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" @@ -11466,6 +11772,15 @@ string.prototype.trim@^1.2.7: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -11475,6 +11790,15 @@ string.prototype.trimend@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string.prototype.trimstart@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" @@ -11484,6 +11808,15 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -11957,6 +12290,13 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -12025,6 +12365,36 @@ type@^2.7.2: resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -12084,6 +12454,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +underscore@1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" + integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== + undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -12404,6 +12779,17 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which-typed-array@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" @@ -12449,6 +12835,11 @@ word-wrap@^1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== +word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" From f4420c06aeb345046075fbf0078c4c310d391be8 Mon Sep 17 00:00:00 2001 From: Berend Sliedrecht Date: Wed, 13 Dec 2023 16:20:15 +0100 Subject: [PATCH 2/2] feat(pex): created core PEX module Signed-off-by: Berend Sliedrecht --- packages/core/package.json | 5 +++ .../PresentationExchangeError.ts | 2 +- .../PresentationExchangeModule.ts | 6 +-- .../PresentationExchangeService.ts | 32 +++++++--------- .../modules/presentation-exchange}/index.ts | 0 .../models/PresentationSubmission.ts | 2 +- .../presentation-exchange}/models/index.ts | 0 .../utils/credentialSelection.ts | 26 ++++++++----- .../presentation-exchange}/utils/index.ts | 0 .../presentation-exchange}/utils/transform.ts | 14 +++---- packages/presentation-exchange/jest.config.ts | 15 -------- packages/presentation-exchange/package.json | 37 ------------------- .../presentation-exchange/tsconfig.build.json | 9 ----- packages/presentation-exchange/tsconfig.json | 8 ---- 14 files changed, 47 insertions(+), 109 deletions(-) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/PresentationExchangeError.ts (54%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/PresentationExchangeModule.ts (61%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/PresentationExchangeService.ts (97%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/index.ts (100%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/models/PresentationSubmission.ts (99%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/models/index.ts (100%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/utils/credentialSelection.ts (93%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/utils/index.ts (100%) rename packages/{presentation-exchange/src => core/src/modules/presentation-exchange}/utils/transform.ts (91%) delete mode 100644 packages/presentation-exchange/jest.config.ts delete mode 100644 packages/presentation-exchange/package.json delete mode 100644 packages/presentation-exchange/tsconfig.build.json delete mode 100644 packages/presentation-exchange/tsconfig.json diff --git a/packages/core/package.json b/packages/core/package.json index 363143ddcd..4a0306f9b8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,6 +27,9 @@ "@digitalcredentials/jsonld-signatures": "^9.3.1", "@digitalcredentials/vc": "^1.1.2", "@multiformats/base-x": "^4.0.1", + "@sphereon/pex": "^2.2.2", + "@sphereon/pex-models": "^2.1.2", + "@sphereon/ssi-types": "^0.17.5", "@stablelib/ed25519": "^1.0.2", "@stablelib/random": "^1.0.1", "@stablelib/sha256": "^1.0.1", @@ -38,6 +41,7 @@ "class-transformer": "0.5.1", "class-validator": "0.14.0", "did-resolver": "^4.1.0", + "jsonpath": "^1.1.1", "lru_map": "^0.4.1", "luxon": "^3.3.0", "make-error": "^1.3.6", @@ -52,6 +56,7 @@ }, "devDependencies": { "@types/events": "^3.0.0", + "@types/jsonpath": "^0.2.4", "@types/luxon": "^3.2.0", "@types/object-inspect": "^1.8.0", "@types/uuid": "^9.0.1", diff --git a/packages/presentation-exchange/src/PresentationExchangeError.ts b/packages/core/src/modules/presentation-exchange/PresentationExchangeError.ts similarity index 54% rename from packages/presentation-exchange/src/PresentationExchangeError.ts rename to packages/core/src/modules/presentation-exchange/PresentationExchangeError.ts index 5c52b67752..e9be720603 100644 --- a/packages/presentation-exchange/src/PresentationExchangeError.ts +++ b/packages/core/src/modules/presentation-exchange/PresentationExchangeError.ts @@ -1,3 +1,3 @@ -import { AriesFrameworkError } from '@aries-framework/core' +import { AriesFrameworkError } from '../../error' export class PresentationExchangeError extends AriesFrameworkError {} diff --git a/packages/presentation-exchange/src/PresentationExchangeModule.ts b/packages/core/src/modules/presentation-exchange/PresentationExchangeModule.ts similarity index 61% rename from packages/presentation-exchange/src/PresentationExchangeModule.ts rename to packages/core/src/modules/presentation-exchange/PresentationExchangeModule.ts index efeb199aaa..dba83cd306 100644 --- a/packages/presentation-exchange/src/PresentationExchangeModule.ts +++ b/packages/core/src/modules/presentation-exchange/PresentationExchangeModule.ts @@ -1,6 +1,6 @@ -import type { DependencyManager, Module } from '@aries-framework/core' +import type { DependencyManager, Module } from '../../plugins' -import { AgentConfig } from '@aries-framework/core' +import { AgentConfig } from '../../agent/AgentConfig' import { PresentationExchangeService } from './PresentationExchangeService' @@ -16,7 +16,7 @@ export class PresentationExchangeModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@aries-framework/presentation-exchange' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The 'PresentationExchangeModule' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." ) // Services diff --git a/packages/presentation-exchange/src/PresentationExchangeService.ts b/packages/core/src/modules/presentation-exchange/PresentationExchangeService.ts similarity index 97% rename from packages/presentation-exchange/src/PresentationExchangeService.ts rename to packages/core/src/modules/presentation-exchange/PresentationExchangeService.ts index 8b9ba5dbcd..5b3f1d54f6 100644 --- a/packages/presentation-exchange/src/PresentationExchangeService.ts +++ b/packages/core/src/modules/presentation-exchange/PresentationExchangeService.ts @@ -1,12 +1,8 @@ import type { InputDescriptorToCredentials, PresentationSubmission } from './models' -import type { - AgentContext, - Query, - VerificationMethod, - W3cCredentialRecord, - W3cVerifiableCredential, - W3cVerifiablePresentation, -} from '@aries-framework/core' +import type { AgentContext } from '../../agent' +import type { Query } from '../../storage/StorageService' +import type { VerificationMethod } from '../dids' +import type { W3cCredentialRecord, W3cVerifiableCredential, W3cVerifiablePresentation } from '../vc' import type { IPresentationDefinition, PresentationSignCallBackParams, @@ -19,19 +15,19 @@ import type { } from '@sphereon/pex-models' import type { OriginalVerifiableCredential } from '@sphereon/ssi-types' +import { PEVersion, PEX, PresentationSubmissionLocation } from '@sphereon/pex' +import { injectable } from 'tsyringe' + +import { getJwkFromKey } from '../../crypto' +import { JsonTransformer } from '../../utils' +import { DidsApi, getKeyFromVerificationMethod } from '../dids' import { - getJwkFromKey, - JsonTransformer, - SignatureSuiteRegistry, - W3cPresentation, - W3cCredentialService, ClaimFormat, - getKeyFromVerificationMethod, - DidsApi, + SignatureSuiteRegistry, W3cCredentialRepository, -} from '@aries-framework/core' -import { PEVersion, PEX, PresentationSubmissionLocation } from '@sphereon/pex' -import { injectable } from 'tsyringe' + W3cCredentialService, + W3cPresentation, +} from '../vc' import { PresentationExchangeError } from './PresentationExchangeError' import { diff --git a/packages/presentation-exchange/src/index.ts b/packages/core/src/modules/presentation-exchange/index.ts similarity index 100% rename from packages/presentation-exchange/src/index.ts rename to packages/core/src/modules/presentation-exchange/index.ts diff --git a/packages/presentation-exchange/src/models/PresentationSubmission.ts b/packages/core/src/modules/presentation-exchange/models/PresentationSubmission.ts similarity index 99% rename from packages/presentation-exchange/src/models/PresentationSubmission.ts rename to packages/core/src/modules/presentation-exchange/models/PresentationSubmission.ts index 28f9209e5a..309cb93c62 100644 --- a/packages/presentation-exchange/src/models/PresentationSubmission.ts +++ b/packages/core/src/modules/presentation-exchange/models/PresentationSubmission.ts @@ -1,4 +1,4 @@ -import type { W3cCredentialRecord, W3cVerifiableCredential } from '@aries-framework/core' +import type { W3cCredentialRecord, W3cVerifiableCredential } from '../../vc' export interface PresentationSubmission { /** diff --git a/packages/presentation-exchange/src/models/index.ts b/packages/core/src/modules/presentation-exchange/models/index.ts similarity index 100% rename from packages/presentation-exchange/src/models/index.ts rename to packages/core/src/modules/presentation-exchange/models/index.ts diff --git a/packages/presentation-exchange/src/utils/credentialSelection.ts b/packages/core/src/modules/presentation-exchange/utils/credentialSelection.ts similarity index 93% rename from packages/presentation-exchange/src/utils/credentialSelection.ts rename to packages/core/src/modules/presentation-exchange/utils/credentialSelection.ts index 966af823c3..fdec050b9e 100644 --- a/packages/presentation-exchange/src/utils/credentialSelection.ts +++ b/packages/core/src/modules/presentation-exchange/utils/credentialSelection.ts @@ -1,13 +1,14 @@ +import type { W3cCredentialRecord } from '../../vc' import type { PresentationSubmission, PresentationSubmissionRequirement, SubmissionEntry } from '../models' -import type { W3cCredentialRecord } from '@aries-framework/core' import type { IPresentationDefinition, SelectResults, SubmissionRequirementMatch } from '@sphereon/pex' import type { InputDescriptorV1, InputDescriptorV2, SubmissionRequirement } from '@sphereon/pex-models' -import { AriesFrameworkError } from '@aries-framework/core' import { PEX } from '@sphereon/pex' import { Rules } from '@sphereon/pex-models' import { default as jp } from 'jsonpath' +import { PresentationExchangeError } from '../PresentationExchangeError' + import { getSphereonOriginalVerifiableCredential } from './transform' export async function selectCredentialsForRequest( @@ -18,7 +19,7 @@ export async function selectCredentialsForRequest( const encodedCredentials = credentialRecords.map((c) => getSphereonOriginalVerifiableCredential(c.credential)) if (!presentationDefinition) { - throw new AriesFrameworkError('Presentation Definition is required to select credentials for submission.') + throw new PresentationExchangeError('Presentation Definition is required to select credentials for submission.') } const pex = new PEX() @@ -37,7 +38,9 @@ export async function selectCredentialsForRequest( verifiableCredential: selectResultsRaw.verifiableCredential?.map((encoded) => { const credentialIndex = encodedCredentials.indexOf(encoded) const credentialRecord = credentialRecords[credentialIndex] - if (!credentialRecord) throw new AriesFrameworkError('Unable to find credential in credential records.') + if (!credentialRecord) { + throw new PresentationExchangeError('Unable to find credential in credential records.') + } return credentialRecord }), @@ -64,7 +67,7 @@ export async function selectCredentialsForRequest( // for now if a request is made that has no required requirements (but only e.g. min: 0, which means we don't need to disclose anything) // I see this more as the fault of the presentation definition, as it should have at least some requirements. if (presentationSubmission.requirements.length === 0) { - throw new AriesFrameworkError( + throw new PresentationExchangeError( 'Presentation Definition does not require any credentials. Optional credentials are not included in the presentation submission.' ) } @@ -93,14 +96,14 @@ function getSubmissionRequirements( for (const submissionRequirement of presentationDefinition.submission_requirements ?? []) { // Check: if the submissionRequirement uses `from_nested`, as we don't support this yet if (submissionRequirement.from_nested) { - throw new AriesFrameworkError( + throw new PresentationExchangeError( "Presentation definition contains requirement using 'from_nested', which is not supported yet." ) } // Check if there's a 'from'. If not the structure is not as we expect it if (!submissionRequirement.from) { - throw new AriesFrameworkError("Missing 'from' in submission requirement match") + throw new PresentationExchangeError("Missing 'from' in submission requirement match") } if (submissionRequirement.rule === Rules.All) { @@ -154,7 +157,8 @@ function getSubmissionRequirementRuleAll( selectResults: W3cCredentialRecordSelectResults ) { // Check if there's a 'from'. If not the structure is not as we expect it - if (!submissionRequirement.from) throw new AriesFrameworkError("Missing 'from' in submission requirement match.") + if (!submissionRequirement.from) + throw new PresentationExchangeError("Missing 'from' in submission requirement match.") const selectedSubmission: PresentationSubmissionRequirement = { rule: Rules.All, @@ -192,10 +196,12 @@ function getSubmissionRequirementRulePick( selectResults: W3cCredentialRecordSelectResults ) { // Check if there's a 'from'. If not the structure is not as we expect it - if (!submissionRequirement.from) throw new AriesFrameworkError("Missing 'from' in submission requirement match.") + if (!submissionRequirement.from) { + throw new PresentationExchangeError("Missing 'from' in submission requirement match.") + } const selectedSubmission: PresentationSubmissionRequirement = { - rule: 'pick', + rule: Rules.Pick, needsCount: submissionRequirement.count ?? submissionRequirement.min ?? 1, name: submissionRequirement.name, purpose: submissionRequirement.purpose, diff --git a/packages/presentation-exchange/src/utils/index.ts b/packages/core/src/modules/presentation-exchange/utils/index.ts similarity index 100% rename from packages/presentation-exchange/src/utils/index.ts rename to packages/core/src/modules/presentation-exchange/utils/index.ts diff --git a/packages/presentation-exchange/src/utils/transform.ts b/packages/core/src/modules/presentation-exchange/utils/transform.ts similarity index 91% rename from packages/presentation-exchange/src/utils/transform.ts rename to packages/core/src/modules/presentation-exchange/utils/transform.ts index a97513b9be..c857c362db 100644 --- a/packages/presentation-exchange/src/utils/transform.ts +++ b/packages/core/src/modules/presentation-exchange/utils/transform.ts @@ -1,19 +1,19 @@ -import type { W3cVerifiableCredential, W3cVerifiablePresentation } from '@aries-framework/core' +import type { W3cVerifiableCredential, W3cVerifiablePresentation } from '../../vc' import type { OriginalVerifiableCredential as SphereonOriginalVerifiableCredential, W3CVerifiableCredential as SphereonW3cVerifiableCredential, W3CVerifiablePresentation as SphereonW3cVerifiablePresentation, } from '@sphereon/ssi-types' +import { JsonTransformer } from '../../../utils' import { - AriesFrameworkError, - JsonTransformer, W3cJsonLdVerifiableCredential, W3cJsonLdVerifiablePresentation, W3cJwtVerifiableCredential, W3cJwtVerifiablePresentation, ClaimFormat, -} from '@aries-framework/core' +} from '../../vc' +import { PresentationExchangeError } from '../PresentationExchangeError' export function getSphereonOriginalVerifiableCredential( w3cVerifiableCredential: W3cVerifiableCredential @@ -23,7 +23,7 @@ export function getSphereonOriginalVerifiableCredential( } else if (w3cVerifiableCredential.claimFormat === ClaimFormat.JwtVc) { return w3cVerifiableCredential.serializedJwt } else { - throw new AriesFrameworkError( + throw new PresentationExchangeError( `Unsupported claim format. Only ${ClaimFormat.LdpVc} and ${ClaimFormat.JwtVc} are supported.` ) } @@ -37,7 +37,7 @@ export function getSphereonW3cVerifiableCredential( } else if (w3cVerifiableCredential.claimFormat === ClaimFormat.JwtVc) { return w3cVerifiableCredential.serializedJwt } else { - throw new AriesFrameworkError( + throw new PresentationExchangeError( `Unsupported claim format. Only ${ClaimFormat.LdpVc} and ${ClaimFormat.JwtVc} are supported.` ) } @@ -51,7 +51,7 @@ export function getSphereonW3cVerifiablePresentation( } else if (w3cVerifiablePresentation instanceof W3cJwtVerifiablePresentation) { return w3cVerifiablePresentation.serializedJwt } else { - throw new AriesFrameworkError( + throw new PresentationExchangeError( `Unsupported claim format. Only ${ClaimFormat.LdpVc} and ${ClaimFormat.JwtVc} are supported.` ) } diff --git a/packages/presentation-exchange/jest.config.ts b/packages/presentation-exchange/jest.config.ts deleted file mode 100644 index 7b6ec7f1c5..0000000000 --- a/packages/presentation-exchange/jest.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Config } from '@jest/types' - -import base from '../../jest.config.base' - -import packageJson from './package.json' - -process.env.TZ = 'GMT' - -const config: Config.InitialOptions = { - ...base, - displayName: packageJson.name, - setupFilesAfterEnv: ['./tests/setup.ts'], -} - -export default config diff --git a/packages/presentation-exchange/package.json b/packages/presentation-exchange/package.json deleted file mode 100644 index f31f73b572..0000000000 --- a/packages/presentation-exchange/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@aries-framework/presentation-exchange", - "main": "build/index", - "types": "build/index", - "version": "0.4.2", - "files": [ - "build" - ], - "license": "Apache-2.0", - "publishConfig": { - "access": "public" - }, - "homepage": "https://github.com/openwallet-foundation/agent-framework-javascript/tree/main/packages/presentation-exchange", - "repository": { - "type": "git", - "url": "https://github.com/openwallet-foundation/agent-framework-javascript", - "directory": "packages/presentation-exchange" - }, - "scripts": { - "build": "yarn run clean && yarn run compile", - "clean": "rimraf ./build", - "compile": "tsc -p tsconfig.build.json", - "prepublishOnly": "yarn run build" - }, - "dependencies": { - "@aries-framework/core": "^0.4.2", - "@sphereon/pex": "^2.2.2", - "@sphereon/pex-models": "^2.1.2", - "@sphereon/ssi-types": "^0.17.5", - "jsonpath": "^1.1.1", - "tsyringe": "^4.8.0" - }, - "devDependencies": { - "@types/jsonpath": "^0.2.4", - "typescript": "~4.9.5" - } -} diff --git a/packages/presentation-exchange/tsconfig.build.json b/packages/presentation-exchange/tsconfig.build.json deleted file mode 100644 index 0a015be666..0000000000 --- a/packages/presentation-exchange/tsconfig.build.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.build.json", - - "compilerOptions": { - "outDir": "./build" - }, - - "include": ["src/**/*", "types"] -} diff --git a/packages/presentation-exchange/tsconfig.json b/packages/presentation-exchange/tsconfig.json deleted file mode 100644 index 93d9dd32b5..0000000000 --- a/packages/presentation-exchange/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "allowJs": false, - "typeRoots": ["../../node_modules/@types", "src/types"], - "types": ["jest"] - } -}