source dump of claude code
at main 115 lines 4.4 kB view raw
1import memoize from 'lodash-es/memoize.js' 2import { logForDebugging } from './debug.js' 3import { hasNodeOption } from './envUtils.js' 4import { getFsImplementation } from './fsOperations.js' 5 6/** 7 * Load CA certificates for TLS connections. 8 * 9 * Since setting `ca` on an HTTPS agent replaces the default certificate store, 10 * we must always include base CAs (either system or bundled Mozilla) when returning. 11 * 12 * Returns undefined when no custom CA configuration is needed, allowing the 13 * runtime's default certificate handling to apply. 14 * 15 * Behavior: 16 * - Neither NODE_EXTRA_CA_CERTS nor --use-system-ca/--use-openssl-ca set: undefined (runtime defaults) 17 * - NODE_EXTRA_CA_CERTS only: bundled Mozilla CAs + extra cert file contents 18 * - --use-system-ca or --use-openssl-ca only: system CAs 19 * - --use-system-ca + NODE_EXTRA_CA_CERTS: system CAs + extra cert file contents 20 * 21 * Memoized for performance. Call clearCACertsCache() to invalidate after 22 * environment variable changes (e.g., after trust dialog applies settings.json). 23 * 24 * Reads ONLY `process.env.NODE_EXTRA_CA_CERTS`. `caCertsConfig.ts` populates 25 * that env var from settings.json at CLI init; this module stays config-free 26 * so `proxy.ts`/`mtls.ts` don't transitively pull in the command registry. 27 */ 28export const getCACertificates = memoize((): string[] | undefined => { 29 const useSystemCA = 30 hasNodeOption('--use-system-ca') || hasNodeOption('--use-openssl-ca') 31 32 const extraCertsPath = process.env.NODE_EXTRA_CA_CERTS 33 34 logForDebugging( 35 `CA certs: useSystemCA=${useSystemCA}, extraCertsPath=${extraCertsPath}`, 36 ) 37 38 // If neither is set, return undefined (use runtime defaults, no override) 39 if (!useSystemCA && !extraCertsPath) { 40 return undefined 41 } 42 43 // Deferred load: Bun's node:tls module eagerly materializes ~150 Mozilla 44 // root certificates (~750KB heap) on import, even if tls.rootCertificates 45 // is never accessed. Most users hit the early return above, so we only 46 // pay this cost when custom CA handling is actually needed. 47 /* eslint-disable @typescript-eslint/no-require-imports */ 48 const tls = require('tls') as typeof import('tls') 49 /* eslint-enable @typescript-eslint/no-require-imports */ 50 51 const certs: string[] = [] 52 53 if (useSystemCA) { 54 // Load system CA store (Bun API) 55 const getCACerts = ( 56 tls as typeof tls & { getCACertificates?: (type: string) => string[] } 57 ).getCACertificates 58 const systemCAs = getCACerts?.('system') 59 if (systemCAs && systemCAs.length > 0) { 60 certs.push(...systemCAs) 61 logForDebugging( 62 `CA certs: Loaded ${certs.length} system CA certificates (--use-system-ca)`, 63 ) 64 } else if (!getCACerts && !extraCertsPath) { 65 // Under Node.js where getCACertificates doesn't exist and no extra certs, 66 // return undefined to let Node.js handle --use-system-ca natively. 67 logForDebugging( 68 'CA certs: --use-system-ca set but system CA API unavailable, deferring to runtime', 69 ) 70 return undefined 71 } else { 72 // System CA API returned empty or unavailable; fall back to bundled root certs 73 certs.push(...tls.rootCertificates) 74 logForDebugging( 75 `CA certs: Loaded ${certs.length} bundled root certificates as base (--use-system-ca fallback)`, 76 ) 77 } 78 } else { 79 // Must include bundled Mozilla CAs as base since ca replaces defaults 80 certs.push(...tls.rootCertificates) 81 logForDebugging( 82 `CA certs: Loaded ${certs.length} bundled root certificates as base`, 83 ) 84 } 85 86 // Append extra certs from file 87 if (extraCertsPath) { 88 try { 89 const extraCert = getFsImplementation().readFileSync(extraCertsPath, { 90 encoding: 'utf8', 91 }) 92 certs.push(extraCert) 93 logForDebugging( 94 `CA certs: Appended extra certificates from NODE_EXTRA_CA_CERTS (${extraCertsPath})`, 95 ) 96 } catch (error) { 97 logForDebugging( 98 `CA certs: Failed to read NODE_EXTRA_CA_CERTS file (${extraCertsPath}): ${error}`, 99 { level: 'error' }, 100 ) 101 } 102 } 103 104 return certs.length > 0 ? certs : undefined 105}) 106 107/** 108 * Clear the CA certificates cache. 109 * Call this when environment variables that affect CA certs may have changed 110 * (e.g., NODE_EXTRA_CA_CERTS, NODE_OPTIONS). 111 */ 112export function clearCACertsCache(): void { 113 getCACertificates.cache.clear?.() 114 logForDebugging('Cleared CA certificates cache') 115}