{"version":3,"file":"TrustedIssuerContext.mjs","names":[],"sources":["../../src/agent/TrustedIssuerContext.ts"],"sourcesContent":["import { CredoError } from '../error'\nimport { parseDid } from '../modules/dids'\nimport { X509Certificate } from '../modules/x509/X509Certificate'\nimport { X509Service } from '../modules/x509/X509Service'\nimport type { AgentContext } from './context'\nimport type {\n  TrustedIssuer,\n  TrustedIssuerDid,\n  TrustedIssuersForVerificationContext,\n  TrustedIssuersForVerificationResult,\n  VerificationSigner,\n} from './TrustedIssuersForVerification'\n\ntype TrustedIssuerForSigner<SignerMethod extends VerificationSigner['method']> = Extract<\n  TrustedIssuer,\n  { method: SignerMethod }\n>\n\n// biome-ignore lint/complexity/noStaticOnlyClass: no explanation\nexport class TrustedIssuerContext {\n  public static async getTrustedIssuersForVerification<\n    Signer extends VerificationSigner,\n    AdditionalVerificationTypes extends { type: string } = never,\n  >(\n    agentContext: AgentContext,\n    context: TrustedIssuersForVerificationContext<Signer, AdditionalVerificationTypes>\n  ): Promise<TrustedIssuersForVerificationResult<TrustedIssuerForSigner<Signer['method']>> | undefined> {\n    // Call the user-registered callback\n    const trustedIssuers = await agentContext.config.getTrustedIssuersForVerification?.(agentContext, context)\n\n    // If there's no result, we return undefined (generally means we allow anything, but in case of mdoc nothing)\n    if (!trustedIssuers) return undefined\n\n    for (const trustedIssuer of trustedIssuers.trustedIssuers) {\n      // In the future we could allow a signer method to map to multiple trusted issuer methods\n      // but for now we require a 1-to-1 mapping\n      if (context.signer.method !== trustedIssuer.method) {\n        throw new CredoError(\n          `All trusted issuer methods must match the signer method (${context.signer.method}). Found method ${trustedIssuer.method}`\n        )\n      }\n    }\n\n    return {\n      trustedIssuers: trustedIssuers.trustedIssuers as TrustedIssuerForSigner<Signer['method']>[],\n    }\n  }\n\n  public static async ensureTrustedSigner<\n    Signer extends VerificationSigner,\n    AdditionalVerificationTypes extends { type: string } = never,\n  >(\n    agentContext: AgentContext,\n    context: TrustedIssuersForVerificationContext<Signer, AdditionalVerificationTypes>,\n    // The trusted issuers to verify the signer against. If not provided they will be dynamically fetched.\n    _trustedIssuers?: TrustedIssuer[]\n  ): Promise<{ trustedIssuer: TrustedIssuerForSigner<Signer['method']> | undefined }> {\n    const signer = context.signer\n    const trustedIssuers =\n      _trustedIssuers ??\n      (await TrustedIssuerContext.getTrustedIssuersForVerification(agentContext, context))?.trustedIssuers\n\n    if (signer.method === 'x509') {\n      // For X509 we do not allow verification to continue if there's no trusted issuers returned.\n      if (!trustedIssuers) {\n        throw new CredoError(\n          'No trusted certificates configured for X509 certificate chain validation. Signer cannot be verified.'\n        )\n      }\n\n      const x509Issuers = trustedIssuers.filter((t) => t.method === 'x509')\n      const validatedChain = await X509Service.validateCertificateChain(agentContext, {\n        // TODO: we should allow x509 cert instance here\n        certificateChain: signer.certificateChain.map((certificate) => certificate.toString('base64')),\n        trustedCertificates: x509Issuers.flatMap((t) => t.issuance),\n      })\n\n      // validateCertificateChain returns the chain, where the first element is\n      // always the matched trusted certificate from the list we provided\n      const trustAnchor = validatedChain[0]\n      const trustedIssuer = x509Issuers.find((t) =>\n        t.issuance.some((certificate) => X509Certificate.fromEncodedCertificate(certificate).equal(trustAnchor))\n      )\n\n      return { trustedIssuer: trustedIssuer as TrustedIssuerForSigner<Signer['method']> }\n    }\n\n    if (signer.method === 'did') {\n      // For DIDs we do allow verification to continue if there's no trusted issuers returned. To mimic original behavior.\n      // This can easily be disabled by returning an empty array\n      if (!trustedIssuers) return { trustedIssuer: undefined }\n\n      const didIssuers = trustedIssuers?.filter((t) => t.method === 'did') as TrustedIssuerDid[]\n      const signerDid = parseDid(signer.didUrl)\n\n      const trustedIssuer = didIssuers.find((t) => {\n        const did = parseDid(t.issuance)\n        return signerDid.did === did.did\n      })\n\n      if (!trustedIssuer) {\n        throw new CredoError(`Signer did ${signerDid.did} is not trusted. Unable to verify signature.`)\n      }\n\n      return { trustedIssuer: trustedIssuer as TrustedIssuerForSigner<Signer['method']> }\n    }\n\n    throw new CredoError('Unknown trusted entity signer method')\n  }\n}\n"],"mappings":";;;;;;;AAmBA,IAAa,uBAAb,MAAa,qBAAqB;CAChC,aAAoB,iCAIlB,cACA,SACoG;EAEpG,MAAM,iBAAiB,MAAM,aAAa,OAAO,mCAAmC,cAAc,OAAO;EAGzG,IAAI,CAAC,gBAAgB,OAAO,KAAA;EAE5B,KAAK,MAAM,iBAAiB,eAAe,gBAGzC,IAAI,QAAQ,OAAO,WAAW,cAAc,QAC1C,MAAM,IAAI,WACR,4DAA4D,QAAQ,OAAO,OAAO,kBAAkB,cAAc,QACpH;EAIJ,OAAO,EACL,gBAAgB,eAAe,eACjC;CACF;CAEA,aAAoB,oBAIlB,cACA,SAEA,iBACkF;EAClF,MAAM,SAAS,QAAQ;EACvB,MAAM,iBACJ,oBACC,MAAM,qBAAqB,iCAAiC,cAAc,OAAO,EAAA,EAAI;EAExF,IAAI,OAAO,WAAW,QAAQ;GAE5B,IAAI,CAAC,gBACH,MAAM,IAAI,WACR,sGACF;GAGF,MAAM,cAAc,eAAe,QAAQ,MAAM,EAAE,WAAW,MAAM;GASpE,MAAM,eAAc,MARS,YAAY,yBAAyB,cAAc;IAE9E,kBAAkB,OAAO,iBAAiB,KAAK,gBAAgB,YAAY,SAAS,QAAQ,CAAC;IAC7F,qBAAqB,YAAY,SAAS,MAAM,EAAE,QAAQ;GAC5D,CAAC,EAAA,CAIkC;GAKnC,OAAO,EAAE,eAJa,YAAY,MAAM,MACtC,EAAE,SAAS,MAAM,gBAAgB,gBAAgB,uBAAuB,WAAW,CAAC,CAAC,MAAM,WAAW,CAAC,CAGrE,EAA8C;EACpF;EAEA,IAAI,OAAO,WAAW,OAAO;GAG3B,IAAI,CAAC,gBAAgB,OAAO,EAAE,eAAe,KAAA,EAAU;GAEvD,MAAM,aAAa,gBAAgB,QAAQ,MAAM,EAAE,WAAW,KAAK;GACnE,MAAM,YAAY,SAAS,OAAO,MAAM;GAExC,MAAM,gBAAgB,WAAW,MAAM,MAAM;IAC3C,MAAM,MAAM,SAAS,EAAE,QAAQ;IAC/B,OAAO,UAAU,QAAQ,IAAI;GAC/B,CAAC;GAED,IAAI,CAAC,eACH,MAAM,IAAI,WAAW,cAAc,UAAU,IAAI,6CAA6C;GAGhG,OAAO,EAAiB,cAA0D;EACpF;EAEA,MAAM,IAAI,WAAW,sCAAsC;CAC7D;AACF"}