fix(mitm): generate root ca on server startup (#2228)
Direct MITM server startup read rootCA.key/.crt immediately and exited when either was missing, bypassing the manager.js CA setup path. - generate Root CA from server.js when key/cert is missing - make generateRootCA()/generateCert() synchronous to avoid a startup race before readFileSync - add unit test covering synchronous Root CA creation Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0b3c794075
commit
182c849979
4 changed files with 44 additions and 4 deletions
|
|
@ -7,8 +7,8 @@ const { generateRootCA, loadRootCA, generateLeafCert } = require("./rootCA");
|
||||||
* Generate Root CA certificate (one-time setup)
|
* Generate Root CA certificate (one-time setup)
|
||||||
* This replaces the old static wildcard cert approach
|
* This replaces the old static wildcard cert approach
|
||||||
*/
|
*/
|
||||||
async function generateCert() {
|
function generateCert() {
|
||||||
return await generateRootCA();
|
return generateRootCA();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ function isCertExpired(certPath) {
|
||||||
* Generate Root CA certificate (only once, auto-regenerate if expired)
|
* Generate Root CA certificate (only once, auto-regenerate if expired)
|
||||||
* This Root CA will sign all dynamic leaf certificates
|
* This Root CA will sign all dynamic leaf certificates
|
||||||
*/
|
*/
|
||||||
async function generateRootCA() {
|
function generateRootCA() {
|
||||||
const exists = fs.existsSync(ROOT_CA_KEY_PATH) && fs.existsSync(ROOT_CA_CERT_PATH);
|
const exists = fs.existsSync(ROOT_CA_KEY_PATH) && fs.existsSync(ROOT_CA_CERT_PATH);
|
||||||
if (exists && !isCertExpired(ROOT_CA_CERT_PATH)) {
|
if (exists && !isCertExpired(ROOT_CA_CERT_PATH)) {
|
||||||
console.log("✅ Root CA already exists");
|
console.log("✅ Root CA already exists");
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ const { execSync } = require("child_process");
|
||||||
const { log, err, dumpRequest, createResponseDumper, clearDumpDir } = require("./logger");
|
const { log, err, dumpRequest, createResponseDumper, clearDumpDir } = require("./logger");
|
||||||
const { IS_DEV, LSOF_BIN, TARGET_HOSTS, URL_PATTERNS, MODEL_SYNONYMS, MODEL_PATTERNS, MODEL_NO_MAP, getToolForHost } = require("./config");
|
const { IS_DEV, LSOF_BIN, TARGET_HOSTS, URL_PATTERNS, MODEL_SYNONYMS, MODEL_PATTERNS, MODEL_NO_MAP, getToolForHost } = require("./config");
|
||||||
const { DATA_DIR, MITM_DIR } = require("./paths");
|
const { DATA_DIR, MITM_DIR } = require("./paths");
|
||||||
const { getCertForDomain } = require("./cert/generate");
|
const { generateCert, getCertForDomain } = require("./cert/generate");
|
||||||
const { getMitmAlias } = require("./dbReader");
|
const { getMitmAlias } = require("./dbReader");
|
||||||
const { applyAntigravityIdeVersionOverride } = require("./antigravityIdeVersion");
|
const { applyAntigravityIdeVersionOverride } = require("./antigravityIdeVersion");
|
||||||
const LOCAL_PORT = 443;
|
const LOCAL_PORT = 443;
|
||||||
|
|
@ -57,6 +57,11 @@ function sniCallback(servername, cb) {
|
||||||
|
|
||||||
let sslOptions;
|
let sslOptions;
|
||||||
try {
|
try {
|
||||||
|
if (!fs.existsSync(path.join(MITM_DIR, "rootCA.key")) || !fs.existsSync(path.join(MITM_DIR, "rootCA.crt"))) {
|
||||||
|
log("Root CA missing, generating...");
|
||||||
|
generateCert();
|
||||||
|
}
|
||||||
|
|
||||||
const rootKey = fs.readFileSync(path.join(MITM_DIR, "rootCA.key"));
|
const rootKey = fs.readFileSync(path.join(MITM_DIR, "rootCA.key"));
|
||||||
const rootCert = fs.readFileSync(path.join(MITM_DIR, "rootCA.crt"));
|
const rootCert = fs.readFileSync(path.join(MITM_DIR, "rootCA.crt"));
|
||||||
rootCAPem = rootCert.toString("utf8");
|
rootCAPem = rootCert.toString("utf8");
|
||||||
|
|
|
||||||
35
tests/unit/mitm-root-ca.test.js
Normal file
35
tests/unit/mitm-root-ca.test.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { createRequire } from "module";
|
||||||
|
import fs from "fs";
|
||||||
|
import os from "os";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
function loadRootCAWithDataDir(dataDir) {
|
||||||
|
const rootCAPath = require.resolve("../../src/mitm/cert/rootCA.js");
|
||||||
|
const pathsPath = require.resolve("../../src/mitm/paths.js");
|
||||||
|
delete require.cache[rootCAPath];
|
||||||
|
delete require.cache[pathsPath];
|
||||||
|
|
||||||
|
const oldDataDir = process.env.DATA_DIR;
|
||||||
|
process.env.DATA_DIR = dataDir;
|
||||||
|
try {
|
||||||
|
return require("../../src/mitm/cert/rootCA.js");
|
||||||
|
} finally {
|
||||||
|
if (oldDataDir === undefined) delete process.env.DATA_DIR;
|
||||||
|
else process.env.DATA_DIR = oldDataDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("MITM Root CA generation", () => {
|
||||||
|
it("creates Root CA files synchronously for direct server startup", () => {
|
||||||
|
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "9router-mitm-ca-"));
|
||||||
|
const { generateRootCA } = loadRootCAWithDataDir(dataDir);
|
||||||
|
|
||||||
|
generateRootCA();
|
||||||
|
|
||||||
|
expect(fs.existsSync(path.join(dataDir, "mitm", "rootCA.key"))).toBe(true);
|
||||||
|
expect(fs.existsSync(path.join(dataDir, "mitm", "rootCA.crt"))).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue