// From https://github.com/capriza/syswide-cas/tree/e0a214f23a072866abf6af540a5b4b88b892a109 // With a patch to make it work within Jest environment const fs = require("fs"); const path = require("path"); const tls = require("tls"); const rootCAs = []; // for node 7.2 and up, trapping method must be used. var useTrap = false; const parts = process.versions.node.split("."); const major = parseInt(parts[0]); const minor = parseInt(parts[1]); if (major > 7 || (major == 7 && minor >= 2) || (major === 6 && minor >= 10)) { useTrap = true; } // create an empty secure context loaded with the root CAs const rootSecureContext = tls.createSecureContext ? tls.createSecureContext() : require("crypto").createCredentials(); function addDefaultCA(file) { try { var cert, match; 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); // this will add the cert to the root certificate authorities list // which will be used by all subsequent secure contexts with root CAs. // this only works up to node 6. node 7 and up it has no affect. if (!useTrap) { rootSecureContext.context.addCACert(cert); } }); } catch (e) { if (e.code !== "ENOENT") { console.log("failed reading file " + file + ": " + e.message); } } } exports.addCAs = function(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()) { addDefaultCA(file); } } catch (e) { if (e.code !== "ENOENT") { console.log("failed reading " + file + ": " + e.message); } } } } else { addDefaultCA(dirs[i]); } } catch (e) { if (e.code !== "ENOENT") { console.log("failed reading " + dirs[i] + ": " + e.message); } } } }; if (useTrap) { // trap the createSecureContext method and inject custom root CAs whenever invoked const origCreateSecureContext = tls.createSecureContext; tls.createSecureContext = function(options) { options = options || {}; // PATCH - in Jest, this is null var c = origCreateSecureContext.apply(null, arguments); if (!options.ca && rootCAs.length > 0) { rootCAs.forEach(function(ca) { // add to the created context our own root CAs c.context.addCACert(ca); }); } return c; }; } const defaultCALocations = ["/etc/ssl/ca-node.pem"]; exports.addCAs(defaultCALocations);