{"version":3,"file":"W3cJsonLdCredentialService.mjs","names":["vc","jsonld"],"sources":["../../../../src/modules/vc/data-integrity/W3cJsonLdCredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../../agent/context'\nimport { createKmsKeyPairClass } from '../../../crypto/KmsKeyPair'\nimport { CredoError } from '../../../error'\nimport { injectable } from '../../../plugins'\nimport type { SingleOrArray } from '../../../types'\nimport { asArray, JsonTransformer } from '../../../utils'\nimport { DidsApi, parseDid, VerificationMethod } from '../../dids'\nimport { getPublicJwkFromVerificationMethod } from '../../dids/domain/key-type'\nimport { PublicJwk } from '../../kms'\nimport type { W3cVerifyCredentialResult, W3cVerifyPresentationResult } from '../models'\nimport type { W3cJsonCredential } from '../models/credential/W3cJsonCredential'\nimport { w3cDate } from '../util'\nimport type {\n  W3cJsonLdSignCredentialOptions,\n  W3cJsonLdSignPresentationOptions,\n  W3cJsonLdVerifyCredentialOptions,\n  W3cJsonLdVerifyPresentationOptions,\n} from '../W3cCredentialServiceOptions'\nimport { W3cCredentialsModuleConfig } from '../W3cCredentialsModuleConfig'\nimport { assertOnlyW3cJsonLdVerifiableCredentials } from './jsonldUtil'\nimport jsonld from './libraries/jsonld'\nimport vc from './libraries/vc'\nimport { W3cJsonLdVerifiableCredential } from './models'\nimport { W3cJsonLdVerifiablePresentation } from './models/W3cJsonLdVerifiablePresentation'\nimport { SignatureSuiteRegistry } from './SignatureSuiteRegistry'\n\n/**\n * Supports signing and verification of credentials according to the [Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model)\n * using [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs).\n */\n@injectable()\nexport class W3cJsonLdCredentialService {\n  private signatureSuiteRegistry: SignatureSuiteRegistry\n  private w3cCredentialsModuleConfig: W3cCredentialsModuleConfig\n\n  public constructor(\n    signatureSuiteRegistry: SignatureSuiteRegistry,\n    w3cCredentialsModuleConfig: W3cCredentialsModuleConfig\n  ) {\n    this.signatureSuiteRegistry = signatureSuiteRegistry\n    this.w3cCredentialsModuleConfig = w3cCredentialsModuleConfig\n  }\n\n  /**\n   * Signs a credential\n   */\n  public async signCredential(\n    agentContext: AgentContext,\n    options: W3cJsonLdSignCredentialOptions\n  ): Promise<W3cJsonLdVerifiableCredential> {\n    const WalletKeyPair = createKmsKeyPairClass(agentContext)\n\n    const signingKey = await this.getPublicJwkFromVerificationMethod(agentContext, options.verificationMethod)\n    const suiteInfo = this.signatureSuiteRegistry.getByProofType(options.proofType)\n\n    const suitesForKey = this.signatureSuiteRegistry.getAllByPublicJwkType(signingKey)\n\n    if (!suitesForKey.some(({ suiteClass }) => suiteClass === suiteInfo.suiteClass)) {\n      throw new CredoError('The key type of the verification method does not match the suite')\n    }\n\n    const keyPair = new WalletKeyPair({\n      controller: options.credential.issuerId, // should we check this against the verificationMethod.controller?\n      id: options.verificationMethod,\n      publicJwk: signingKey,\n    })\n\n    const SuiteClass = suiteInfo.suiteClass\n\n    const suite = new SuiteClass({\n      key: keyPair,\n      LDKeyClass: WalletKeyPair,\n      proof: {\n        verificationMethod: options.verificationMethod,\n      },\n      useNativeCanonize: false,\n      date: options.created ?? w3cDate(),\n    })\n\n    try {\n      const result = await vc.issue({\n        credential: JsonTransformer.toJSON(options.credential),\n        suite: suite,\n        purpose: options.proofPurpose,\n        documentLoader: this.w3cCredentialsModuleConfig.documentLoader(agentContext),\n      })\n\n      return JsonTransformer.fromJSON(result, W3cJsonLdVerifiableCredential)\n    } catch (error) {\n      throw new CredoError(`Error issuing W3C JSON-LD VC. ${error.message}`, {\n        cause: error,\n      })\n    }\n  }\n\n  /**\n   * Verifies the signature(s) of a credential\n   *\n   * @param credential the credential to be verified\n   * @returns the verification result\n   */\n  public async verifyCredential(\n    agentContext: AgentContext,\n    options: W3cJsonLdVerifyCredentialOptions\n  ): Promise<W3cVerifyCredentialResult> {\n    try {\n      const verifyCredentialStatus = options.verifyCredentialStatus ?? true\n\n      const suites = this.getSignatureSuitesForCredential(agentContext, options.credential)\n\n      const verifyOptions: Record<string, unknown> = {\n        credential: JsonTransformer.toJSON(options.credential),\n        suite: suites,\n        documentLoader: this.w3cCredentialsModuleConfig.documentLoader(agentContext),\n        checkStatus: ({ credential }: { credential: W3cJsonCredential }) => {\n          // Only throw error if credentialStatus is present\n          if (verifyCredentialStatus && 'credentialStatus' in credential) {\n            throw new CredoError('Verifying credential status for JSON-LD credentials is currently not supported')\n          }\n          return {\n            verified: true,\n          }\n        },\n      }\n\n      // this is a hack because vcjs throws if purpose is passed as undefined or null\n      if (options.proofPurpose) {\n        verifyOptions.purpose = options.proofPurpose\n      }\n\n      const result = await vc.verifyCredential(verifyOptions)\n\n      const { verified: isValid, ...remainingResult } = result\n\n      if (!isValid) {\n        agentContext.config.logger.debug(`Credential verification failed: ${result.error?.message}`, {\n          stack: result.error?.stack,\n        })\n      }\n\n      // We map the result to our own result type to make it easier to work with\n      // however, for now we just add a single vcJs validation result as we don't\n      // have access to the internal validation results of vc-js\n      return {\n        isValid,\n        validations: {\n          vcJs: {\n            isValid,\n            ...remainingResult,\n          },\n        },\n        error: result.error,\n      }\n    } catch (error) {\n      return {\n        isValid: false,\n        validations: {},\n        error,\n      }\n    }\n  }\n\n  /**\n   * Signs a presentation including the credentials it includes\n   *\n   * @param presentation the presentation to be signed\n   * @returns the signed presentation\n   */\n  public async signPresentation(\n    agentContext: AgentContext,\n    options: W3cJsonLdSignPresentationOptions\n  ): Promise<W3cJsonLdVerifiablePresentation> {\n    // create keyPair\n    const WalletKeyPair = createKmsKeyPairClass(agentContext)\n\n    const suiteInfo = this.signatureSuiteRegistry.getByProofType(options.proofType)\n\n    if (!suiteInfo) {\n      throw new CredoError(`The requested proofType ${options.proofType} is not supported`)\n    }\n\n    const signingKey = await this.getPublicJwkFromVerificationMethod(agentContext, options.verificationMethod)\n    const suitesForKey = this.signatureSuiteRegistry.getAllByPublicJwkType(signingKey)\n\n    if (!suitesForKey.some(({ suiteClass }) => suiteClass === suiteInfo.suiteClass)) {\n      throw new CredoError('The key type of the verification method does not match the suite')\n    }\n\n    const documentLoader = this.w3cCredentialsModuleConfig.documentLoader(agentContext)\n    const verificationMethodObject = (await documentLoader(options.verificationMethod)).document as Record<\n      string,\n      unknown\n    >\n\n    const keyPair = new WalletKeyPair({\n      controller: verificationMethodObject.controller as string,\n      id: options.verificationMethod,\n      publicJwk: signingKey,\n    })\n\n    const suite = new suiteInfo.suiteClass({\n      LDKeyClass: WalletKeyPair,\n      proof: {\n        verificationMethod: options.verificationMethod,\n      },\n      date: new Date().toISOString(),\n      key: keyPair,\n      useNativeCanonize: false,\n    })\n\n    const signOptions: Record<string, unknown> = {\n      presentation: JsonTransformer.toJSON(options.presentation),\n      suite: suite,\n      challenge: options.challenge,\n      domain: options.domain,\n      documentLoader: this.w3cCredentialsModuleConfig.documentLoader(agentContext),\n    }\n\n    // this is a hack because vcjs throws if purpose is passed as undefined or null\n    if (options.proofPurpose) {\n      signOptions.purpose = options.proofPurpose\n    }\n\n    const result = await vc.signPresentation(signOptions)\n\n    return JsonTransformer.fromJSON(result, W3cJsonLdVerifiablePresentation)\n  }\n\n  /**\n   * Verifies a presentation including the credentials it includes\n   *\n   * @param presentation the presentation to be verified\n   * @returns the verification result\n   */\n  public async verifyPresentation(\n    agentContext: AgentContext,\n    options: W3cJsonLdVerifyPresentationOptions\n  ): Promise<W3cVerifyPresentationResult> {\n    try {\n      // create keyPair\n      const WalletKeyPair = createKmsKeyPairClass(agentContext)\n\n      let proofs = options.presentation.proof\n\n      if (!Array.isArray(proofs)) {\n        proofs = [proofs]\n      }\n      if (options.purpose) {\n        proofs = proofs.filter((proof) => proof.proofPurpose === options.purpose.term)\n      }\n\n      const presentationSuites = proofs.map((proof) => {\n        const SuiteClass = this.signatureSuiteRegistry.getByProofType(proof.type).suiteClass\n        return new SuiteClass({\n          LDKeyClass: WalletKeyPair,\n          proof: {\n            verificationMethod: proof.verificationMethod,\n          },\n          date: proof.created,\n          useNativeCanonize: false,\n        })\n      })\n\n      const credentials = asArray(options.presentation.verifiableCredential)\n      assertOnlyW3cJsonLdVerifiableCredentials(credentials)\n\n      const credentialSuites = credentials.map((credential) =>\n        this.getSignatureSuitesForCredential(agentContext, credential)\n      )\n      const allSuites = presentationSuites.concat(...credentialSuites)\n\n      const verifyOptions: Record<string, unknown> = {\n        presentation: JsonTransformer.toJSON(options.presentation),\n        suite: allSuites,\n        challenge: options.challenge,\n        domain: options.domain,\n        documentLoader: this.w3cCredentialsModuleConfig.documentLoader(agentContext),\n      }\n\n      // this is a hack because vcjs throws if purpose is passed as undefined or null\n      if (options.purpose) {\n        verifyOptions.presentationPurpose = options.purpose\n      }\n\n      const result = await vc.verify(verifyOptions)\n\n      const { verified: isValid, ...remainingResult } = result\n\n      // We map the result to our own result type to make it easier to work with\n      // however, for now we just add a single vcJs validation result as we don't\n      // have access to the internal validation results of vc-js\n      return {\n        isValid,\n        validations: {\n          vcJs: {\n            isValid,\n            ...remainingResult,\n          },\n        },\n        error: result.error,\n      }\n    } catch (error) {\n      return {\n        isValid: false,\n        validations: {},\n        error,\n      }\n    }\n  }\n\n  public getVerificationMethodTypesByProofType(proofType: string): string[] {\n    return this.signatureSuiteRegistry.getByProofType(proofType).verificationMethodTypes\n  }\n\n  public async getExpandedTypesForCredential(agentContext: AgentContext, credential: W3cJsonLdVerifiableCredential) {\n    // Get the expanded types\n    const expandedTypes: SingleOrArray<string> = (\n      await jsonld.expand(JsonTransformer.toJSON(credential), {\n        documentLoader: this.w3cCredentialsModuleConfig.documentLoader(agentContext),\n      })\n    )[0]['@type']\n\n    return asArray(expandedTypes)\n  }\n\n  private async getPublicJwkFromVerificationMethod(\n    agentContext: AgentContext,\n    verificationMethod: string\n  ): Promise<PublicJwk> {\n    const dids = agentContext.resolve(DidsApi)\n\n    const documentLoader = this.w3cCredentialsModuleConfig.documentLoader(agentContext)\n    const verificationMethodObject = await documentLoader(verificationMethod)\n    const verificationMethodInstance = JsonTransformer.fromJSON(verificationMethodObject.document, VerificationMethod)\n    const did = parseDid(verificationMethod)\n    const publicJwk = getPublicJwkFromVerificationMethod(verificationMethodInstance)\n\n    const [didRecord] = await dids.getCreatedDids({ did: did.did })\n\n    // For all modern uses of did bound credentials there MUST be a did record\n    if (didRecord) {\n      publicJwk.keyId =\n        didRecord.keys?.find(({ didDocumentRelativeKeyId }) => didDocumentRelativeKeyId === `#${did.fragment}`)\n          ?.kmsKeyId ?? publicJwk.legacyKeyId\n    } else {\n      // If we don't have a did record we assume legacy key id should be used.\n      publicJwk.keyId = publicJwk.legacyKeyId\n    }\n\n    return publicJwk\n  }\n\n  private getSignatureSuitesForCredential(agentContext: AgentContext, credential: W3cJsonLdVerifiableCredential) {\n    const WalletKeyPair = createKmsKeyPairClass(agentContext)\n\n    let proofs = credential.proof\n\n    if (!Array.isArray(proofs)) {\n      proofs = [proofs]\n    }\n\n    return proofs.map((proof) => {\n      const SuiteClass = this.signatureSuiteRegistry.getByProofType(proof.type).suiteClass\n      return new SuiteClass({\n        LDKeyClass: WalletKeyPair,\n        proof: {\n          verificationMethod: proof.verificationMethod,\n        },\n        date: proof.created,\n        useNativeCanonize: false,\n      })\n    })\n  }\n}\n"],"mappings":"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"}