diff --git a/src/lib/server/models.ts b/src/lib/server/models.ts index 5459f6202cc..8aa819c907e 100644 --- a/src/lib/server/models.ts +++ b/src/lib/server/models.ts @@ -6,6 +6,11 @@ import endpoints, { endpointSchema, type Endpoint } from "./endpoints/endpoints" import JSON5 from "json5"; import { logger } from "$lib/server/logger"; import { makeRouterEndpoint } from "$lib/server/router/endpoint"; +import { loadClientCertificates } from "$lib/utils/loadClientCerts"; + +if (config.USE_CLIENT_CERTIFICATE === "true" && config.CERT_PATH && config.KEY_PATH) { + loadClientCertificates(config.CERT_PATH, config.KEY_PATH); +} type Optional = Pick, K> & Omit; diff --git a/src/lib/utils/loadClientCerts.ts b/src/lib/utils/loadClientCerts.ts new file mode 100644 index 00000000000..20135b6686a --- /dev/null +++ b/src/lib/utils/loadClientCerts.ts @@ -0,0 +1,50 @@ +import * as fs from "fs"; +import { setGlobalDispatcher, Agent } from "undici"; + +/** + * Load client certificates for mutual TLS authentication. This function must be called before any HTTP requests are made. + * This is a global setting that affects all HTTP requests made by the application using the native fetch API. + * + * @param clientCertPath Path to client certificate + * @param clientKeyPath Path to client key + * @param caCertPath Path to CA certificate [optional] + * @param clientKeyPassword Password for client key [optional] + * @param rejectUnauthorized Reject unauthorized certificates. + * Only use for testing/development, not recommended in production environments [optional] + * + * @returns void + * + * @example + * ```typescript + * loadClientCertificates("cert.pem", "key.pem", "ca.pem", "password", false); + * ``` + * + * @see + * [Undici Agent](https://undici.nodejs.org/#/docs/api/Agent) + * @see + * [Undici Dispatcher](https://undici.nodejs.org/#/docs/api/Dispatcher) + * @see + * [NodeJS Native Fetch API](https://nodejs.org/docs/latest-v19.x/api/globals.html#fetch) + */ +export function loadClientCertificates( + clientCertPath: string, + clientKeyPath: string, + caCertPath?: string, + clientKeyPassword?: string, + rejectUnauthorized?: boolean +): void { + const clientCert = fs.readFileSync(clientCertPath); + const clientKey = fs.readFileSync(clientKeyPath); + const caCert = caCertPath ? fs.readFileSync(caCertPath) : undefined; + const agent = new Agent({ + connect: { + cert: clientCert, + key: clientKey, + ca: caCert, + passphrase: clientKeyPassword, + rejectUnauthorized, + }, + }); + + setGlobalDispatcher(agent); +}