UNPKG

@small-tech/syswide-cas

Version:

Fork of syswide-cas by a now-defunct company called Capriza. Enable node to use system wide certificate authorities in conjunction with the bundled root CAs.

101 lines (89 loc) 2.79 kB
import fs from 'node:fs' import path from 'node:path' import tls from 'node:tls' /** @type {string[]} */ const rootCAs = [] // Monkeypatch tls.createSecureContext method to inject custom root CAs when invoked. const originalCreateSecureContext = tls.createSecureContext tls.createSecureContext = function (options) { var secureContext = originalCreateSecureContext.apply(null, arguments) if (!options?.ca && rootCAs.length > 0) { rootCAs.forEach(function (ca) { // Add our own root CAs to created context. secureContext.context.addCACert(ca) }) } return secureContext } export default class SyswideCas { /** Adds custom Certificate Authorities from the specified directories or files. @param {string|string[]} dirs - A single directory/file path or an array of paths, or a comma-separated string of paths. */ static addCAs (dirs) { if (!dirs) { return } if (typeof dirs === 'string') { dirs = dirs.split(',').map(function (dir) { return dir.trim() }) } var files, stat, file, i, j for (i = 0; i < dirs.length; ++i) { try { stat = fs.statSync(dirs[i]) if (stat.isDirectory()) { files = fs.readdirSync(dirs[i]) for (j = 0; j < files.length; ++j) { file = path.resolve(dirs[i], files[j]) try { stat = fs.statSync(file) if (stat.isFile()) { this.addDefaultCA(file) } } catch (e) { if (e.code !== 'ENOENT') { console.error(`Error reading ${file}: ${e.message}`) } } } } else { this.addDefaultCA(dirs[i]) } } catch (e) { if (e.code !== 'ENOENT') { console.log(`Error reading ${dirs[i]}: ${e.message}`) } } } } /** Adds certificate authority to list of root certificate authorities. @param {string} file */ static addDefaultCA (file) { try { var content = fs.readFileSync(file, {encoding: "ascii"}).trim() content = content.replace(/\r\n/g, "\n") // Handles certificates that have been created in Windows var regex = /-----BEGIN CERTIFICATE-----\n[\s\S]+?\n-----END CERTIFICATE-----/g var results = content.match(regex) if (!results) { throw new Error('Could not parse certificate.') } results.forEach(function (match) { var cert = match.trim() rootCAs.push(cert) }) } catch (e) { if (e.code !== 'ENOENT') { console.log(`Error reading file ${file}: ${e.message}`) } } } } // // Module load-time side-effects. // const defaultCALocations = ['/etc/ssl/ca-node.pem'] SyswideCas.addCAs(defaultCALocations)