{"version":3,"file":"v2-jwt-utils.mjs","names":[],"sources":["../../../src/modules/vc/v2-jwt-utils.ts"],"sourcesContent":["import { AgentContext } from '../../agent'\nimport { CredoError } from '../../error'\nimport { asArray, isDid } from '../../utils'\nimport {\n  type DidPurpose,\n  DidResolverService,\n  DidsApi,\n  getPublicJwkFromVerificationMethod,\n  parseDid,\n  VerificationMethod,\n} from '../dids'\nimport { getSupportedVerificationMethodTypesForPublicJwk } from '../dids/domain/key-type/keyDidMapping'\nimport { type KnownJwaSignatureAlgorithm, PublicJwk } from '../kms'\nimport { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from '../sd-jwt-vc/utils'\nimport { W3cV2JwtVerifiableCredential } from './jwt-vc/W3cV2JwtVerifiableCredential'\nimport { W3cV2JwtVerifiablePresentation } from './jwt-vc/W3cV2JwtVerifiablePresentation'\nimport { W3cV2EnvelopedVerifiableCredential } from './models/credential/W3cV2EnvelopedVerifiableCredential'\nimport type { W3cV2Presentation } from './models/presentation/W3cV2Presentation'\nimport { W3cV2SdJwtVerifiableCredential } from './sd-jwt-vc/W3cV2SdJwtVerifiableCredential'\nimport { W3cV2SdJwtVerifiablePresentation } from './sd-jwt-vc/W3cV2SdJwtVerifiablePresentation'\n\nexport async function validateAndResolveVerificationMethod(\n  agentContext: AgentContext,\n  verificationMethod: string,\n  allowsPurposes?: DidPurpose[]\n) {\n  if (!isDid(verificationMethod)) {\n    throw new CredoError('Only did identifiers are supported as verification method')\n  }\n\n  const parsedDid = parseDid(verificationMethod)\n  if (!parsedDid.fragment) {\n    throw new CredoError(`didUrl '${parsedDid.didUrl}' does not contain a '#'. Unable to derive key from did document`)\n  }\n\n  const dids = agentContext.resolve(DidsApi)\n  const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(parsedDid.did)\n  const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes)\n  const publicJwk = getPublicJwkFromVerificationMethod(verificationMethodObject)\n\n  publicJwk.keyId =\n    keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))\n      ?.kmsKeyId ?? publicJwk.legacyKeyId\n\n  return publicJwk\n}\n\nexport async function extractHolderFromPresentationCredentials(\n  agentContext: AgentContext,\n  presentation: W3cV2Presentation\n) {\n  const credentials = asArray(presentation.verifiableCredential)\n\n  const holderDid = presentation.holderId\n  if (holderDid) {\n    if (!isDid(holderDid)) {\n      throw new CredoError(`Presentation holder '${holderDid}' is not a valid did`)\n    }\n\n    const dids = agentContext.resolve(DidsApi)\n    const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(holderDid)\n\n    const authenticationMethods = didDocument.findVerificationMethodsByPurpose(['authentication'])\n\n    const candidateMethods = authenticationMethods.filter((method) =>\n      keys?.some(({ didDocumentRelativeKeyId }) => method.id.endsWith(didDocumentRelativeKeyId))\n    )\n\n    if (candidateMethods.length === 0) {\n      throw new CredoError(\n        `Unable to determine signer key for presentation holder '${holderDid}'. No locally controlled authentication verification method found.`\n      )\n    }\n\n    if (candidateMethods.length > 1) {\n      throw new CredoError(\n        `Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found.`\n      )\n    }\n\n    const selectedMethod = candidateMethods[0]\n    const publicJwk = getPublicJwkFromVerificationMethod(selectedMethod)\n    publicJwk.keyId =\n      keys?.find(({ didDocumentRelativeKeyId }) => selectedMethod.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ??\n      publicJwk.legacyKeyId\n\n    const [alg] = publicJwk.supportedSignatureAlgorithms\n    if (!alg) {\n      throw new CredoError(\n        `No supported JWA signature algorithms found for holder verification method '${selectedMethod.id}'`\n      )\n    }\n\n    return {\n      alg,\n      publicJwk,\n      cnf: {\n        kid: selectedMethod.id,\n      },\n    }\n  }\n\n  const fallbackHolders: Array<Awaited<ReturnType<typeof extractKeyFromHolderBinding>>> = []\n\n  for (const credential of credentials) {\n    if (!(credential instanceof W3cV2EnvelopedVerifiableCredential)) continue\n\n    let claims: Record<string, unknown>\n    if (credential.envelopedCredential instanceof W3cV2SdJwtVerifiableCredential) {\n      claims = credential.envelopedCredential.sdJwt.prettyClaims\n    } else if (credential.envelopedCredential instanceof W3cV2JwtVerifiableCredential) {\n      claims = credential.envelopedCredential.jwt.payload.toJson()\n    } else {\n      continue\n    }\n\n    const holderBinding = parseHolderBindingFromCredential(claims)\n    if (!holderBinding) continue\n\n    fallbackHolders.push(await extractKeyFromHolderBinding(agentContext, holderBinding, { forSigning: true }))\n  }\n\n  if (fallbackHolders.length === 0) {\n    throw new CredoError('Unable to determine signer from presentation credentials, and presentation.holder is missing')\n  }\n\n  const uniqueFallbackHolders = new Map(fallbackHolders.map((holder) => [holder.publicJwk.fingerprint, holder]))\n  if (uniqueFallbackHolders.size > 1) {\n    throw new CredoError(\n      'Unable to determine signer from presentation credentials. Multiple distinct holder bindings found and presentation.holder is missing.'\n    )\n  }\n\n  return uniqueFallbackHolders.values().next().value as Awaited<ReturnType<typeof extractKeyFromHolderBinding>>\n}\n\n/**\n * This method tries to find the verification method associated with the JWT credential or presentation.\n * This verification method can then be used to verify the credential or presentation signature.\n */\nexport async function getVerificationMethodForJwt(\n  agentContext: AgentContext,\n  credential:\n    | W3cV2JwtVerifiableCredential\n    | W3cV2JwtVerifiablePresentation\n    | W3cV2SdJwtVerifiableCredential\n    | W3cV2SdJwtVerifiablePresentation,\n  purpose?: DidPurpose[]\n) {\n  let alg: KnownJwaSignatureAlgorithm\n  let kid: string | undefined\n  let iss: string | undefined\n\n  // Determine the algorithm, kid and iss based on the type of credential / presentation\n  if (credential instanceof W3cV2JwtVerifiableCredential) {\n    alg = credential.jwt.header.alg as KnownJwaSignatureAlgorithm\n    kid = credential.jwt.header.kid\n    iss = credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId\n  } else if (credential instanceof W3cV2JwtVerifiablePresentation) {\n    alg = credential.jwt.header.alg as KnownJwaSignatureAlgorithm\n    kid = credential.jwt.header.kid\n    iss = credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId\n  } else if (credential instanceof W3cV2SdJwtVerifiableCredential) {\n    alg = credential.sdJwt.header.alg as KnownJwaSignatureAlgorithm\n    kid = credential.sdJwt.header.kid\n    iss = credential.sdJwt.payload.iss ?? credential.resolvedCredential.issuerId\n  } else {\n    alg = credential.sdJwt.header.alg as KnownJwaSignatureAlgorithm\n    kid = credential.sdJwt.header.kid\n    iss = credential.sdJwt.payload.iss ?? credential.resolvedPresentation.holderId\n  }\n\n  const didResolver = agentContext.dependencyManager.resolve(DidResolverService)\n  let verificationMethod: VerificationMethod\n\n  // If the kid starts with # we assume it is a relative did url, and we resolve\n  //it based on the `iss` and the `kid`\n  if (kid?.startsWith('#')) {\n    if (!iss || !isDid(iss)) {\n      throw new CredoError(`JWT 'iss' MUST be a did when 'kid' is a relative did url`)\n    }\n\n    const didDocument = await didResolver.resolveDidDocument(agentContext, iss)\n    verificationMethod = didDocument.dereferenceKey(`${iss}${kid}`, purpose)\n  } else if (kid && isDid(kid)) {\n    const didDocument = await didResolver.resolveDidDocument(agentContext, kid)\n    verificationMethod = didDocument.dereferenceKey(kid, purpose)\n\n    if (iss && didDocument.id !== iss) {\n      throw new CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${iss}'`)\n    }\n  } else {\n    if (!iss) {\n      throw new CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`)\n    }\n\n    // Find the verificationMethod in the did document based on the alg and proofPurpose\n    const jwkClass = PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(alg)\n    const supportedVerificationMethodTypes = getSupportedVerificationMethodTypesForPublicJwk(jwkClass)\n\n    const didDocument = await didResolver.resolveDidDocument(agentContext, iss)\n    const verificationMethods = didDocument.findVerificationMethodsByTypeAndPurpose(supportedVerificationMethodTypes, [\n      'assertionMethod',\n    ])\n\n    if (verificationMethods.length === 0) {\n      throw new CredoError(\n        `No verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`\n      )\n    }\n    if (verificationMethods.length > 1) {\n      throw new CredoError(\n        `Multiple verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`\n      )\n    }\n\n    verificationMethod = verificationMethods[0]\n  }\n\n  // Verify the controller of the verificationMethod matches the signer of the credential\n  if (iss && verificationMethod.controller !== iss) {\n    throw new CredoError(\n      `Verification method controller '${verificationMethod.controller}' does not match the signer '${iss}'`\n    )\n  }\n\n  return verificationMethod\n}\n"],"mappings":"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"}