{"version":3,"file":"credentialTransformer.mjs","names":[],"sources":["../../../../src/modules/vc/jwt-vc/credentialTransformer.ts"],"sourcesContent":["import { isObject } from 'class-validator'\nimport type { JwtPayloadOptions } from '../../../crypto/jose/jwt'\n\nimport { JwtPayload } from '../../../crypto/jose/jwt'\nimport { CredoError } from '../../../error'\nimport { isJsonObject } from '../../../types'\nimport { JsonTransformer } from '../../../utils'\nimport { W3cCredential } from '../models/credential/W3cCredential'\nimport { w3cDate } from '../util'\n\nexport function getJwtPayloadFromCredential(credential: W3cCredential) {\n  const vc = JsonTransformer.toJSON(credential)\n\n  const payloadOptions: JwtPayloadOptions = {\n    additionalClaims: {\n      vc,\n    },\n  }\n\n  // Extract `nbf` and remove issuance date from vc\n  const issuanceDate = Date.parse(credential.issuanceDate)\n  if (Number.isNaN(issuanceDate)) {\n    throw new CredoError('JWT VCs must have a valid issuance date')\n  }\n  payloadOptions.nbf = Math.floor(issuanceDate / 1000)\n  // biome-ignore lint/performance/noDelete: no explanation\n  delete vc.issuanceDate\n\n  // Extract `exp` and remove expiration date from vc\n  if (credential.expirationDate) {\n    const expirationDate = Date.parse(credential.expirationDate)\n    if (!Number.isNaN(expirationDate)) {\n      payloadOptions.exp = Math.floor(expirationDate / 1000)\n      // biome-ignore lint/performance/noDelete: no explanation\n      delete vc.expirationDate\n    }\n  }\n\n  // Extract `iss` and remove issuer id from vc\n  payloadOptions.iss = credential.issuerId\n  if (typeof vc.issuer === 'string') {\n    // biome-ignore lint/performance/noDelete: no explanation\n    delete vc.issuer\n  } else if (typeof vc.issuer === 'object') {\n    // biome-ignore lint/performance/noDelete: no explanation\n    delete vc.issuer.id\n    if (Object.keys(vc.issuer).length === 0) {\n      // biome-ignore lint/performance/noDelete: no explanation\n      delete vc.issuer\n    }\n  }\n\n  // Extract `jti` and remove id from vc\n  if (credential.id) {\n    payloadOptions.jti = credential.id\n    // biome-ignore lint/performance/noDelete: no explanation\n    delete vc.id\n  }\n\n  if (Array.isArray(credential.credentialSubject) && credential.credentialSubject.length !== 1) {\n    throw new CredoError('JWT VCs must have exactly one credential subject')\n  }\n\n  // Extract `sub` and remove credential subject id from vc\n  const [credentialSubjectId] = credential.credentialSubjectIds\n  if (credentialSubjectId) {\n    payloadOptions.sub = credentialSubjectId\n\n    if (Array.isArray(vc.credentialSubject)) {\n      // biome-ignore lint/performance/noDelete: no explanation\n      delete vc.credentialSubject[0].id\n    } else {\n      // biome-ignore lint/performance/noDelete: no explanation\n      delete vc.credentialSubject?.id\n    }\n  }\n\n  return new JwtPayload(payloadOptions)\n}\n\nexport function getCredentialFromJwtPayload(jwtPayload: JwtPayload) {\n  if (!('vc' in jwtPayload.additionalClaims) || !isJsonObject(jwtPayload.additionalClaims.vc)) {\n    throw new CredoError(\"JWT does not contain a valid 'vc' claim\")\n  }\n\n  const jwtVc = jwtPayload.additionalClaims.vc\n\n  if (!jwtPayload.nbf || !jwtPayload.iss) {\n    throw new CredoError(\"JWT does not contain valid 'nbf' and 'iss' claims\")\n  }\n\n  if (Array.isArray(jwtVc.credentialSubject) && jwtVc.credentialSubject.length !== 1) {\n    throw new CredoError('JWT VCs must have exactly one credential subject')\n  }\n\n  if (Array.isArray(jwtVc.credentialSubject) && !isObject(jwtVc.credentialSubject[0])) {\n    throw new CredoError('JWT VCs must have a credential subject of type object')\n  }\n\n  const credentialSubject = Array.isArray(jwtVc.credentialSubject)\n    ? jwtVc.credentialSubject[0]\n    : jwtVc.credentialSubject\n  if (!isJsonObject(credentialSubject)) {\n    throw new CredoError('JWT VC does not have a valid credential subject')\n  }\n  const subjectWithId = jwtPayload.sub ? { ...credentialSubject, id: jwtPayload.sub } : credentialSubject\n\n  // Validate vc.id and jti\n  if (jwtVc.id && jwtPayload.jti !== jwtVc.id) {\n    throw new CredoError('JWT jti and vc.id do not match')\n  }\n\n  // Validate vc.issuer and iss\n  if (\n    (typeof jwtVc.issuer === 'string' && jwtPayload.iss !== jwtVc.issuer) ||\n    (isJsonObject(jwtVc.issuer) && jwtVc.issuer.id && jwtPayload.iss !== jwtVc.issuer.id)\n  ) {\n    throw new CredoError('JWT iss and vc.issuer(.id) do not match')\n  }\n\n  // Validate vc.issuanceDate and nbf\n  if (jwtVc.issuanceDate) {\n    if (typeof jwtVc.issuanceDate !== 'string') {\n      throw new CredoError('JWT vc.issuanceDate must be a string')\n    }\n\n    const issuanceDate = Date.parse(jwtVc.issuanceDate) / 1000\n    if (jwtPayload.nbf !== issuanceDate) {\n      throw new CredoError('JWT nbf and vc.issuanceDate do not match')\n    }\n  }\n\n  // Validate vc.expirationDate and exp\n  if (jwtVc.expirationDate) {\n    if (typeof jwtVc.expirationDate !== 'string') {\n      throw new CredoError('JWT vc.expirationDate must be a string')\n    }\n\n    const expirationDate = Date.parse(jwtVc.expirationDate) / 1000\n    if (expirationDate !== jwtPayload.exp) {\n      throw new CredoError('JWT exp and vc.expirationDate do not match')\n    }\n  }\n\n  // Validate vc.credentialSubject.id and sub\n  if (\n    (isJsonObject(jwtVc.credentialSubject) &&\n      jwtVc.credentialSubject.id &&\n      jwtPayload.sub !== jwtVc.credentialSubject.id) ||\n    (Array.isArray(jwtVc.credentialSubject) &&\n      isJsonObject(jwtVc.credentialSubject[0]) &&\n      jwtVc.credentialSubject[0].id &&\n      jwtPayload.sub !== jwtVc.credentialSubject[0].id)\n  ) {\n    throw new CredoError('JWT sub and vc.credentialSubject.id do not match')\n  }\n\n  // Create a verifiable credential structure that is compatible with the VC data model\n  const dataModelVc = {\n    ...jwtVc,\n    issuanceDate: w3cDate(jwtPayload.nbf * 1000),\n    expirationDate: jwtPayload.exp ? w3cDate(jwtPayload.exp * 1000) : undefined,\n    issuer: typeof jwtVc.issuer === 'object' ? { ...jwtVc.issuer, id: jwtPayload.iss } : jwtPayload.iss,\n    id: jwtPayload.jti,\n    credentialSubject: Array.isArray(jwtVc.credentialSubject) ? [subjectWithId] : subjectWithId,\n  }\n\n  const vcInstance = JsonTransformer.fromJSON(dataModelVc, W3cCredential)\n\n  return vcInstance\n}\n"],"mappings":"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"}