mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Combine NODE_EXTRA_CA_CERTS with Safe Chain's certificate bundle
This commit is contained in:
parent
15cc6ff7fe
commit
7086cfa277
2 changed files with 71 additions and 2 deletions
|
|
@ -6,6 +6,7 @@ import certifi from "certifi";
|
|||
import tls from "node:tls";
|
||||
import { X509Certificate } from "node:crypto";
|
||||
import { getCaCertPath } from "./certUtils.js";
|
||||
import { ui } from "../environment/userInteraction.js";
|
||||
|
||||
/**
|
||||
* Check if a PEM string contains only parsable cert blocks.
|
||||
|
|
@ -93,3 +94,68 @@ export function getCombinedCaBundlePath() {
|
|||
cachedPath = target;
|
||||
return cachedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read user certificate file.
|
||||
* @param {string} certPath - Path to certificate file
|
||||
* @returns {string | null} Certificate PEM content or null if invalid/unreadable
|
||||
*/
|
||||
function readUserCertificateFile(certPath) {
|
||||
try {
|
||||
// Validate path is a string and not attempting path traversal
|
||||
if (typeof certPath !== "string" || certPath.includes("..") || certPath.startsWith("/")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(certPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const certPathAbsolute = path.resolve(certPath);
|
||||
// Verify it's an absolute path (cross-platform)
|
||||
if (!path.isAbsolute(certPathAbsolute)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(certPathAbsolute, "utf8");
|
||||
return content && isParsable(content) ? content : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine user's existing NODE_EXTRA_CA_CERTS with Safe Chain's CA certificate.
|
||||
* If user has NODE_EXTRA_CA_CERTS set, it's merged with Safe Chain CA.
|
||||
*
|
||||
* @param {string | undefined} userCertPath - User's existing NODE_EXTRA_CA_CERTS path (if any)
|
||||
* @returns {string} Path to the final CA bundle
|
||||
*/
|
||||
export function getCombinedCaBundlePathWithUserCerts(userCertPath) {
|
||||
const parts = [];
|
||||
|
||||
// 1) Add Safe Chain CA (for MITM'd registries)
|
||||
const safeChainPath = getCaCertPath();
|
||||
try {
|
||||
const safeChainPem = fs.readFileSync(safeChainPath, "utf8");
|
||||
if (isParsable(safeChainPem)) parts.push(safeChainPem.trim());
|
||||
} catch {
|
||||
// Ignore if Safe Chain CA is not available
|
||||
}
|
||||
|
||||
// 2) Add user's certificates if provided
|
||||
if (userCertPath) {
|
||||
const userPem = readUserCertificateFile(userCertPath);
|
||||
if (userPem) {
|
||||
parts.push(userPem.trim());
|
||||
ui.writeWarning(`Safe-chain: Merging user's NODE_EXTRA_CA_CERTS from ${userCertPath}`);
|
||||
} else {
|
||||
ui.writeWarning(`Safe-chain: Could not read or parse user's NODE_EXTRA_CA_CERTS from ${userCertPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
const finalCombined = parts.filter(Boolean).join("\n");
|
||||
const target = path.join(os.tmpdir(), `safe-chain-ca-bundle-${Date.now()}.pem`);
|
||||
fs.writeFileSync(target, finalCombined, { encoding: "utf8" });
|
||||
return target;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as http from "http";
|
|||
import { tunnelRequest } from "./tunnelRequestHandler.js";
|
||||
import { mitmConnect } from "./mitmRequestHandler.js";
|
||||
import { handleHttpProxyRequest } from "./plainHttpProxy.js";
|
||||
import { getCaCertPath } from "./certUtils.js";
|
||||
import { getCombinedCaBundlePathWithUserCerts } from "./certBundle.js";
|
||||
import { ui } from "../environment/userInteraction.js";
|
||||
import chalk from "chalk";
|
||||
import { createInterceptorForUrl } from "./interceptors/createInterceptorForEcoSystem.js";
|
||||
|
|
@ -37,10 +37,13 @@ function getSafeChainProxyEnvironmentVariables() {
|
|||
}
|
||||
|
||||
const proxyUrl = `http://localhost:${state.port}`;
|
||||
const userNodeExtraCaCerts = process.env.NODE_EXTRA_CA_CERTS;
|
||||
const caCertPath = getCombinedCaBundlePathWithUserCerts(userNodeExtraCaCerts);
|
||||
|
||||
return {
|
||||
HTTPS_PROXY: proxyUrl,
|
||||
GLOBAL_AGENT_HTTP_PROXY: proxyUrl,
|
||||
NODE_EXTRA_CA_CERTS: getCaCertPath(),
|
||||
NODE_EXTRA_CA_CERTS: caCertPath,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue