{"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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"}