UNPKG

@credo-ts/core

Version:

<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1

69 lines (68 loc) • 3.15 kB
import { X509Error } from "../X509Error.mjs"; import { fetchWithTimeout } from "../../../utils/fetch.mjs"; import { CacheModuleConfig } from "../../cache/CacheModuleConfig.mjs"; import "../../cache/index.mjs"; import { isX509CrlSummary } from "./crlSummary.mjs"; //#region src/modules/x509/utils/crlFetcher.ts /** * Default maximum CRL size in bytes (10 MB) * This is a reasonable limit as most CRLs are much smaller. * Very large CRLs (>10 MB) are uncommon and may indicate issues. */ const DEFAULT_MAX_CRL_SIZE_BYTES = 10485760; /** * Default CRL fetch timeout in milliseconds (5 seconds) */ const DEFAULT_TIMEOUT_MILLISECONDS = 5e3; function crlSummaryCacheKey(url) { return `x509:crl-summary:v1:${url}`; } /** * Fetches a CRL from a given URL with size limit and timeout enforcement. * * This does NOT cache: caching is the responsibility of the caller, which should only cache a CRL * after it has been verified (see {@link setCachedCrlSummary}), so unverified or expired CRLs are * never persisted. * * @throws {X509Error} If the fetch fails, returns a non-OK status, or exceeds the size limit */ async function fetchCrl(options) { const { url, timeoutMs = DEFAULT_TIMEOUT_MILLISECONDS, agentContext, maxSizeBytes = DEFAULT_MAX_CRL_SIZE_BYTES } = options; try { const response = await fetchWithTimeout(agentContext.config.agentDependencies.fetch, url, { timeoutMs, maxResponseBytes: maxSizeBytes }); if (!response.ok) throw new X509Error(`Failed to fetch CRL from ${url}: HTTP ${response.status} ${response.statusText}`); return new Uint8Array(await response.arrayBuffer()); } catch (error) { if (error instanceof X509Error) throw error; throw new X509Error(`Failed to fetch CRL from ${url}: ${error instanceof Error ? error.message : String(error)}`, { cause: error instanceof Error ? error : void 0 }); } } /** * Return the cached verified CRL summary for a URL, or `null` if not cached. Values that do not * match the expected summary shape are treated as a cache miss, never as an error. * * Summaries are cached in the global scope: CRLs are public data, shared across all agent contexts. */ async function getCachedCrlSummary(agentContext, url) { const cached = await agentContext.resolve(CacheModuleConfig).cache.get(agentContext, crlSummaryCacheKey(url), { scope: "global" }).catch(() => null); return isX509CrlSummary(cached) ? cached : null; } /** * Cache the summary of a verified CRL for a URL. * * Callers must only cache summaries derived from CRLs that have passed verification, and should * derive `expiresInSeconds` from the CRL's `nextUpdate` so an expired CRL is never served from the * cache. * * Summaries are cached in the global scope: CRLs are public data, shared across all agent contexts. */ async function setCachedCrlSummary(agentContext, url, summary, expiresInSeconds) { if (expiresInSeconds <= 0) return; await agentContext.resolve(CacheModuleConfig).cache.set(agentContext, crlSummaryCacheKey(url), summary, expiresInSeconds, { scope: "global" }).catch(() => null); } //#endregion export { fetchCrl, getCachedCrlSummary, setCachedCrlSummary }; //# sourceMappingURL=crlFetcher.mjs.map