@credo-ts/core
Version:
<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1
1 lines • 16.6 kB
Source Map (JSON)
{"version":3,"file":"W3cV2DataIntegrityCredentialService.mjs","names":["createDataIntegrityCredoError"],"sources":["../../../../src/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../../agent/context'\nimport { CredoError } from '../../../error'\nimport { injectable } from '../../../plugins'\nimport { JsonTransformer, MessageValidator } from '../../../utils'\nimport {\n createW3cDataIntegrityCredoError as createDataIntegrityCredoError,\n type W3cDataIntegrityIssueList as DataIntegrityIssueList,\n W3cDataIntegrityProofService as DataIntegrityProofService,\n} from '../../w3c-di/internal'\nimport { CREDENTIALS_CONTEXT_V2_URL } from '../constants'\nimport { ClaimFormat } from '../models/ClaimFormat'\nimport { W3cV2Credential } from '../models/credential/W3cV2Credential'\nimport type { W3cV2VerifiableCredential } from '../models/credential/W3cV2VerifiableCredential'\nimport { W3cV2Presentation } from '../models/presentation/W3cV2Presentation'\nimport type { W3cV2VerifiablePresentation } from '../models/presentation/W3cV2VerifiablePresentation'\nimport type { W3cV2VerifyCredentialResult, W3cV2VerifyPresentationResult } from '../models/W3cV2VerifyResult'\nimport type { SingleValidationResult } from '../models/W3cVerifyResult'\nimport { validateVc2ContextBaseline, validateVc2CredentialStatus } from '../validators'\nimport type {\n W3cV2DiSignCredentialOptions,\n W3cV2DiSignPresentationOptions,\n W3cV2DiVerifyCredentialOptions,\n W3cV2DiVerifyPresentationOptions,\n} from '../W3cV2CredentialServiceOptions'\nimport { getVerificationMethodForDataIntegrityProof } from './v2-di-utils'\nimport { W3cV2DataIntegrityContextValidator } from './W3cV2DataIntegrityContextValidator'\nimport { W3cV2DataIntegrityVerifiableCredential } from './W3cV2DataIntegrityVerifiableCredential'\nimport { W3cV2DataIntegrityVerifiablePresentation } from './W3cV2DataIntegrityVerifiablePresentation'\n\n@injectable()\nexport class W3cV2DataIntegrityCredentialService {\n private dataIntegrityProofService: DataIntegrityProofService\n private contextValidator: W3cV2DataIntegrityContextValidator\n\n public constructor(\n dataIntegrityProofService: DataIntegrityProofService,\n contextValidator: W3cV2DataIntegrityContextValidator\n ) {\n this.dataIntegrityProofService = dataIntegrityProofService\n this.contextValidator = contextValidator\n }\n\n public async signCredential(\n agentContext: AgentContext,\n options: W3cV2DiSignCredentialOptions\n ): Promise<W3cV2VerifiableCredential<ClaimFormat.DiVc>> {\n const unsecuredCredential = JsonTransformer.toJSON(options.credential)\n if (unsecuredCredential['@context'] === undefined || unsecuredCredential['@context'] === null) {\n unsecuredCredential['@context'] = [CREDENTIALS_CONTEXT_V2_URL]\n }\n\n MessageValidator.validateSync(JsonTransformer.fromJSON(unsecuredCredential, W3cV2Credential, { validate: false }))\n\n const contextValidation = validateVc2ContextBaseline(unsecuredCredential['@context'])\n if (!contextValidation.isValid) {\n throw contextValidation.error ?? new CredoError('VC2 credential @context validation failed')\n }\n\n const proofResult = await this.dataIntegrityProofService.createProof(agentContext, {\n unsecuredDocument: unsecuredCredential,\n verificationMethod: options.verificationMethod,\n proofPurpose: 'assertionMethod',\n cryptosuite: options.cryptosuite,\n })\n\n if (!proofResult.created) {\n throw createDataIntegrityCredoError(proofResult.errors)\n }\n\n return new W3cV2DataIntegrityVerifiableCredential({\n securedCredential: {\n ...unsecuredCredential,\n proof: proofResult.proof,\n },\n })\n }\n\n public async verifyCredential(\n agentContext: AgentContext,\n options: W3cV2DiVerifyCredentialOptions\n ): Promise<W3cV2VerifyCredentialResult> {\n const securedCredential = options.credential.securedCredential\n const verificationResult = Array.isArray(securedCredential.proof)\n ? await this.dataIntegrityProofService.verifyProofSetAndChain(agentContext, securedCredential as never, {\n expectedProofPurpose: 'assertionMethod',\n })\n : await this.dataIntegrityProofService.verifyProof(agentContext, securedCredential as never, {\n expectedProofPurpose: 'assertionMethod',\n })\n\n if (!verificationResult.verified) {\n return this.invalidResult(verificationResult.errors, 'credential')\n }\n\n const contextResult = await this.contextValidator.validate(agentContext, securedCredential)\n if (!contextResult.validated) {\n return this.invalidResult(contextResult.errors as DataIntegrityIssueList, 'credential')\n }\n\n const credentialStatus = validateVc2CredentialStatus({\n credentialStatus: securedCredential.credentialStatus,\n credentialFormat: 'DI',\n verifyCredentialStatus: options.verifyCredentialStatus,\n })\n\n const issuerIsSigner = await this.verifySignerIsExpectedParty(\n agentContext,\n securedCredential,\n 'assertionMethod',\n options.credential.resolvedCredential.issuerId,\n (verificationMethodId, issuerId) =>\n `Credential is signed using verification method ${verificationMethodId}, while the issuer of the credential is '${issuerId}'`\n )\n\n const isValid = credentialStatus.isValid && issuerIsSigner.isValid\n\n return {\n isValid,\n validations: {\n dataModel: { isValid: true },\n signature: { isValid: true },\n credentialStatus,\n issuerIsSigner,\n },\n }\n }\n\n public async signPresentation(\n agentContext: AgentContext,\n options: W3cV2DiSignPresentationOptions\n ): Promise<W3cV2VerifiablePresentation<ClaimFormat.DiVp>> {\n const unsecuredPresentation = JsonTransformer.toJSON(options.presentation)\n if (unsecuredPresentation['@context'] === undefined || unsecuredPresentation['@context'] === null) {\n unsecuredPresentation['@context'] = [CREDENTIALS_CONTEXT_V2_URL]\n }\n\n MessageValidator.validateSync(\n JsonTransformer.fromJSON(unsecuredPresentation, W3cV2Presentation, { validate: false })\n )\n\n const contextValidation = validateVc2ContextBaseline(unsecuredPresentation['@context'])\n if (!contextValidation.isValid) {\n throw contextValidation.error ?? new CredoError('VC2 presentation @context validation failed')\n }\n\n const proofResult = await this.dataIntegrityProofService.createProof(agentContext, {\n unsecuredDocument: unsecuredPresentation,\n verificationMethod: options.verificationMethod,\n proofPurpose: 'authentication',\n cryptosuite: options.cryptosuite,\n challenge: options.challenge,\n domain: options.domain,\n })\n\n if (!proofResult.created) {\n throw createDataIntegrityCredoError(proofResult.errors)\n }\n\n const securedPresentation = {\n ...unsecuredPresentation,\n proof: proofResult.proof,\n }\n\n return new W3cV2DataIntegrityVerifiablePresentation({\n securedPresentation,\n resolvedPresentation: JsonTransformer.fromJSON(securedPresentation, W3cV2Presentation, { validate: false }),\n })\n }\n\n public async verifyPresentation(\n agentContext: AgentContext,\n options: W3cV2DiVerifyPresentationOptions\n ): Promise<W3cV2VerifyPresentationResult> {\n const securedPresentation = options.presentation.securedPresentation\n\n const verificationResult = Array.isArray(securedPresentation.proof)\n ? await this.dataIntegrityProofService.verifyProofSetAndChain(agentContext, securedPresentation as never, {\n expectedProofPurpose: 'authentication',\n challenge: options.challenge,\n domain: options.domain,\n })\n : await this.dataIntegrityProofService.verifyProof(agentContext, securedPresentation as never, {\n expectedProofPurpose: 'authentication',\n challenge: options.challenge,\n domain: options.domain,\n })\n\n if (!verificationResult.verified) {\n return this.invalidResult(verificationResult.errors, 'presentation')\n }\n\n const presentationContextResult = await this.contextValidator.validate(agentContext, securedPresentation)\n if (!presentationContextResult.validated) {\n return this.invalidResult(presentationContextResult.errors as DataIntegrityIssueList, 'presentation')\n }\n\n const holderIsSigner = await this.verifySignerIsExpectedParty(\n agentContext,\n options.presentation.securedPresentation,\n 'authentication',\n options.presentation.resolvedPresentation.holderId,\n (verificationMethodId, holderId) =>\n `Presentation is signed using verification method ${verificationMethodId}, while the holder of the presentation is '${holderId}'`\n )\n\n return {\n isValid: holderIsSigner.isValid,\n presentation: {\n isValid: holderIsSigner.isValid,\n validations: {\n dataModel: { isValid: true },\n holderIsSigner,\n presentationSignature: { isValid: true },\n },\n },\n credentialEntries: [],\n }\n }\n\n /**\n * Checks that a secured document was signed by the identity it names as responsible for it —\n * the `issuer` of a credential, or the `holder` of a presentation.\n *\n * Mirrors the equivalent checks in the JWT and SD-JWT services — though those compare key\n * fingerprints for the issuer, whereas Data Integrity proofs name a verification method, so the\n * comparison here is by controller for both roles. It implements the association described in\n * VC-DATA-INTEGRITY §\"Relationship to Verifiable Credentials\": that the `controller` of the\n * proof's verification method matches the identifier used for the `issuer` or `holder`, and that\n * the verification method is expressed under a verification relationship acceptable for the\n * proof's purpose. The latter is enforced by dereferencing the key with `purpose`.\n *\n * Verifying the proof only establishes that *someone* signed; without this comparison a document\n * could name one party and be signed by an unrelated one.\n *\n * @param expectedSigner the `issuer` or `holder`. `Holder` is optional in\n * VCDM 2.0 so when undefined there is no claim to contradict, so the validation passes.\n */\n private async verifySignerIsExpectedParty(\n agentContext: AgentContext,\n securedDocument: { proof: unknown },\n purpose: 'assertionMethod' | 'authentication',\n expectedSigner: string | undefined,\n describeMismatch: (verificationMethodId: string, expectedSigner: string) => string\n ): Promise<SingleValidationResult> {\n if (!expectedSigner) {\n return { isValid: true }\n }\n\n try {\n const verificationMethod = await getVerificationMethodForDataIntegrityProof(\n agentContext,\n securedDocument,\n purpose,\n expectedSigner\n )\n\n // NOTE: as in the JWT service's holder check, this compares verificationMethod.controller\n // rather than verificationMethod.id, since issuer and holder identify an entity rather than\n // a specific key.\n if (verificationMethod.controller !== expectedSigner) {\n return {\n isValid: false,\n error: new CredoError(describeMismatch(verificationMethod.id, expectedSigner)),\n }\n }\n\n return { isValid: true }\n } catch (error) {\n return { isValid: false, error }\n }\n }\n\n private invalidResult(errors: DataIntegrityIssueList, target: 'credential'): W3cV2VerifyCredentialResult\n private invalidResult(errors: DataIntegrityIssueList, target: 'presentation'): W3cV2VerifyPresentationResult\n private invalidResult(\n errors: DataIntegrityIssueList,\n target: 'credential' | 'presentation'\n ): W3cV2VerifyCredentialResult | W3cV2VerifyPresentationResult {\n const invalidValidation = this.invalidValidation(errors)\n\n if (target === 'credential') {\n return {\n isValid: false,\n validations: {\n signature: invalidValidation,\n },\n }\n }\n\n return this.invalidPresentationResult('presentationSignature', invalidValidation.error)\n }\n\n private invalidValidation(errors: DataIntegrityIssueList) {\n return {\n isValid: false,\n error: createDataIntegrityCredoError(errors),\n } as const\n }\n\n private invalidPresentationResult(\n field: 'dataModel' | 'presentationSignature',\n error: Error\n ): W3cV2VerifyPresentationResult {\n return {\n isValid: false,\n presentation: {\n isValid: false,\n validations: {\n [field]: {\n isValid: false,\n error,\n },\n },\n },\n credentialEntries: [],\n }\n }\n}\n"],"mappings":"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"}