@thangnm.nip/arouter 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +5 -5
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(dashboard)/mitm/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +2 -2
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/alias/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/alias/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/console-logs/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/claude-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/claude-settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/codex-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/codex-settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/copilot-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/copilot-settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/droid-settings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/droid-settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/openclaw-settings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/openclaw-settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/opencode-settings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/opencode-settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/keys/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/keys/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/locale/route.js +2 -2
- package/.next/standalone/.next/server/app/api/locale/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/models/alias/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/!KGRhc2hib2FyZCk/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/mitm.html +1 -1
- package/.next/standalone/.next/server/app/mitm.rsc +5 -5
- package/.next/standalone/.next/server/app/mitm.segments/!KGRhc2hib2FyZCk/mitm/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/mitm.segments/!KGRhc2hib2FyZCk/mitm.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/mitm.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/mitm.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/mitm.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/mitm.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +5 -5
- package/.next/standalone/.next/server/chunks/411.js +1 -1
- package/.next/standalone/.next/server/middleware.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +2 -2
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/{702-90a93bbee38dba8f.js → 702-0864796c00fc702e.js} +1 -1
- package/.next/standalone/node_modules/node-forge/LICENSE +331 -0
- package/.next/standalone/node_modules/node-forge/README.md +2071 -0
- package/.next/standalone/node_modules/node-forge/dist/forge.all.min.js +2 -0
- package/.next/standalone/node_modules/node-forge/dist/forge.all.min.js.map +1 -0
- package/.next/standalone/node_modules/node-forge/dist/forge.min.js +2 -0
- package/.next/standalone/node_modules/node-forge/dist/forge.min.js.map +1 -0
- package/.next/standalone/node_modules/node-forge/dist/prime.worker.min.js +2 -0
- package/.next/standalone/node_modules/node-forge/dist/prime.worker.min.js.map +1 -0
- package/.next/standalone/node_modules/node-forge/flash/swf/SocketPool.swf +0 -0
- package/.next/standalone/node_modules/node-forge/lib/aes.js +1091 -0
- package/.next/standalone/node_modules/node-forge/lib/aesCipherSuites.js +282 -0
- package/.next/standalone/node_modules/node-forge/lib/asn1-validator.js +91 -0
- package/.next/standalone/node_modules/node-forge/lib/asn1.js +1503 -0
- package/.next/standalone/node_modules/node-forge/lib/baseN.js +186 -0
- package/.next/standalone/node_modules/node-forge/lib/cipher.js +230 -0
- package/.next/standalone/node_modules/node-forge/lib/cipherModes.js +999 -0
- package/.next/standalone/node_modules/node-forge/lib/des.js +496 -0
- package/.next/standalone/node_modules/node-forge/lib/ed25519.js +1072 -0
- package/.next/standalone/node_modules/node-forge/lib/forge.js +13 -0
- package/.next/standalone/node_modules/node-forge/lib/form.js +149 -0
- package/.next/standalone/node_modules/node-forge/lib/hmac.js +146 -0
- package/.next/standalone/node_modules/node-forge/lib/http.js +1346 -0
- package/.next/standalone/node_modules/node-forge/lib/index.all.js +16 -0
- package/.next/standalone/node_modules/node-forge/lib/index.js +33 -0
- package/.next/standalone/node_modules/node-forge/lib/jsbn.js +1264 -0
- package/.next/standalone/node_modules/node-forge/lib/kem.js +168 -0
- package/.next/standalone/node_modules/node-forge/lib/log.js +319 -0
- package/.next/standalone/node_modules/node-forge/lib/md.all.js +13 -0
- package/.next/standalone/node_modules/node-forge/lib/md.js +11 -0
- package/.next/standalone/node_modules/node-forge/lib/md5.js +289 -0
- package/.next/standalone/node_modules/node-forge/lib/mgf.js +12 -0
- package/.next/standalone/node_modules/node-forge/lib/mgf1.js +57 -0
- package/.next/standalone/node_modules/node-forge/lib/oids.js +179 -0
- package/.next/standalone/node_modules/node-forge/lib/pbe.js +1023 -0
- package/.next/standalone/node_modules/node-forge/lib/pbkdf2.js +211 -0
- package/.next/standalone/node_modules/node-forge/lib/pem.js +237 -0
- package/.next/standalone/node_modules/node-forge/lib/pkcs1.js +276 -0
- package/.next/standalone/node_modules/node-forge/lib/pkcs12.js +1078 -0
- package/.next/standalone/node_modules/node-forge/lib/pkcs7.js +1260 -0
- package/.next/standalone/node_modules/node-forge/lib/pkcs7asn1.js +410 -0
- package/.next/standalone/node_modules/node-forge/lib/pki.js +102 -0
- package/.next/standalone/node_modules/node-forge/lib/prime.js +297 -0
- package/.next/standalone/node_modules/node-forge/lib/prime.worker.js +168 -0
- package/.next/standalone/node_modules/node-forge/lib/prng.js +419 -0
- package/.next/standalone/node_modules/node-forge/lib/pss.js +241 -0
- package/.next/standalone/node_modules/node-forge/lib/random.js +191 -0
- package/.next/standalone/node_modules/node-forge/lib/rc2.js +410 -0
- package/.next/standalone/node_modules/node-forge/lib/rsa.js +1949 -0
- package/.next/standalone/node_modules/node-forge/lib/sha1.js +319 -0
- package/.next/standalone/node_modules/node-forge/lib/sha256.js +327 -0
- package/.next/standalone/node_modules/node-forge/lib/sha512.js +561 -0
- package/.next/standalone/node_modules/node-forge/lib/socket.js +287 -0
- package/.next/standalone/node_modules/node-forge/lib/ssh.js +236 -0
- package/.next/standalone/node_modules/node-forge/lib/tls.js +4282 -0
- package/.next/standalone/node_modules/node-forge/lib/tlssocket.js +249 -0
- package/.next/standalone/node_modules/node-forge/lib/util.js +2652 -0
- package/.next/standalone/node_modules/node-forge/lib/x509.js +3242 -0
- package/.next/standalone/node_modules/node-forge/lib/xhr.js +738 -0
- package/.next/standalone/node_modules/node-forge/package.json +123 -0
- package/.next/standalone/node_modules/node-machine-id/.babelrc +26 -0
- package/.next/standalone/node_modules/node-machine-id/.eslintignore +2 -0
- package/.next/standalone/node_modules/node-machine-id/.eslintrc +140 -0
- package/.next/standalone/node_modules/node-machine-id/.flowconfig +9 -0
- package/.next/standalone/node_modules/node-machine-id/LICENSE +21 -0
- package/.next/standalone/node_modules/node-machine-id/README.md +84 -0
- package/.next/standalone/node_modules/node-machine-id/dist/index.js +1 -0
- package/.next/standalone/node_modules/node-machine-id/index.js +80 -0
- package/.next/standalone/node_modules/node-machine-id/package.json +74 -0
- package/.next/standalone/node_modules/node-machine-id/tests/index.js +45 -0
- package/.next/standalone/node_modules/node-machine-id/types/index.d.ts +17 -0
- package/.next/standalone/node_modules/node-machine-id/webpack.config.babel.js +59 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/src/mitm/cert/generate.js +32 -0
- package/.next/standalone/src/mitm/cert/install.js +176 -0
- package/.next/standalone/src/mitm/cert/rootCA.js +173 -0
- package/.next/standalone/src/mitm/dns/dnsConfig.js +216 -0
- package/.next/standalone/src/mitm/logger.js +8 -0
- package/.next/standalone/src/mitm/manager.js +603 -0
- package/.next/standalone/src/mitm/paths.js +16 -0
- package/package.json +1 -1
- /package/.next/standalone/.next/static/{Ws7kclTEFgfHRwd7pk9Ly → DkVxg6bby4SUixuq1vdO8}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Ws7kclTEFgfHRwd7pk9Ly → DkVxg6bby4SUixuq1vdO8}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
const { exec, spawn, execSync } = require("child_process");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const net = require("net");
|
|
6
|
+
const https = require("https");
|
|
7
|
+
const crypto = require("crypto");
|
|
8
|
+
const { addDNSEntry, removeDNSEntry, removeAllDNSEntries, checkAllDNSStatus, TOOL_HOSTS } = require("./dns/dnsConfig");
|
|
9
|
+
|
|
10
|
+
const IS_WIN = process.platform === "win32";
|
|
11
|
+
const { generateCert } = require("./cert/generate");
|
|
12
|
+
const { installCert, uninstallCert } = require("./cert/install");
|
|
13
|
+
const { isCertExpired } = require("./cert/rootCA");
|
|
14
|
+
const { MITM_DIR } = require("./paths");
|
|
15
|
+
const { log, err } = require("./logger");
|
|
16
|
+
|
|
17
|
+
const MITM_PORT = 443;
|
|
18
|
+
const MITM_WIN_NODE_PORT = 8443;
|
|
19
|
+
const PID_FILE = path.join(MITM_DIR, ".mitm.pid");
|
|
20
|
+
|
|
21
|
+
const MITM_MAX_RESTARTS = 5;
|
|
22
|
+
const MITM_RESTART_DELAYS_MS = [5000, 10000, 20000, 30000, 60000];
|
|
23
|
+
const MITM_RESTART_RESET_MS = 60000;
|
|
24
|
+
|
|
25
|
+
let mitmRestartCount = 0;
|
|
26
|
+
let mitmLastStartTime = 0;
|
|
27
|
+
let mitmIsRestarting = false;
|
|
28
|
+
|
|
29
|
+
function resolveServerPath() {
|
|
30
|
+
if (process.env.MITM_SERVER_PATH) return process.env.MITM_SERVER_PATH;
|
|
31
|
+
const sibling = path.join(__dirname, "server.js");
|
|
32
|
+
if (fs.existsSync(sibling)) return sibling;
|
|
33
|
+
const fromCwd = path.join(process.cwd(), "src", "mitm", "server.js");
|
|
34
|
+
if (fs.existsSync(fromCwd)) return fromCwd;
|
|
35
|
+
const fromNext = path.join(process.cwd(), "..", "src", "mitm", "server.js");
|
|
36
|
+
if (fs.existsSync(fromNext)) return fromNext;
|
|
37
|
+
return fromCwd;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const SERVER_PATH = resolveServerPath();
|
|
41
|
+
const ENCRYPT_ALGO = "aes-256-gcm";
|
|
42
|
+
const ENCRYPT_SALT = "9router-mitm-pwd";
|
|
43
|
+
|
|
44
|
+
function getProcessUsingPort443() {
|
|
45
|
+
try {
|
|
46
|
+
if (IS_WIN) {
|
|
47
|
+
const psCmd = `powershell -NonInteractive -WindowStyle Hidden -Command ` +
|
|
48
|
+
`"$c = Get-NetTCPConnection -LocalPort 443 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1; if ($c) { $c.OwningProcess } else { 0 }"`;
|
|
49
|
+
const pidStr = execSync(psCmd, { encoding: "utf8", windowsHide: true }).trim();
|
|
50
|
+
const pid = parseInt(pidStr, 10);
|
|
51
|
+
if (pid && pid > 4) {
|
|
52
|
+
const tasklistResult = execSync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: "utf8", windowsHide: true });
|
|
53
|
+
const processMatch = tasklistResult.match(/"([^"]+)"/);
|
|
54
|
+
if (processMatch) return processMatch[1].replace(".exe", "");
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
const result = execSync("lsof -i :443", { encoding: "utf8" });
|
|
58
|
+
const lines = result.trim().split("\n");
|
|
59
|
+
if (lines.length > 1) return lines[1].split(/\s+/)[0];
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let serverProcess = null;
|
|
68
|
+
let serverPid = null;
|
|
69
|
+
|
|
70
|
+
function getCachedPassword() { return globalThis.__mitmSudoPassword || null; }
|
|
71
|
+
function setCachedPassword(pwd) { globalThis.__mitmSudoPassword = pwd; }
|
|
72
|
+
|
|
73
|
+
function isProcessAlive(pid) {
|
|
74
|
+
try {
|
|
75
|
+
process.kill(pid, 0);
|
|
76
|
+
return true;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
return err.code === "EACCES";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function killProcess(pid, force = false, sudoPassword = null) {
|
|
83
|
+
if (IS_WIN) {
|
|
84
|
+
const flag = force ? "/F " : "";
|
|
85
|
+
exec(`taskkill ${flag}/PID ${pid}`, { windowsHide: true }, () => { });
|
|
86
|
+
} else {
|
|
87
|
+
const sig = force ? "SIGKILL" : "SIGTERM";
|
|
88
|
+
const cmd = `pkill -${sig} -P ${pid} 2>/dev/null; kill -${sig} ${pid} 2>/dev/null`;
|
|
89
|
+
if (sudoPassword) {
|
|
90
|
+
const { execWithPassword } = require("./dns/dnsConfig");
|
|
91
|
+
execWithPassword(cmd, sudoPassword).catch(() => exec(cmd, () => { }));
|
|
92
|
+
} else {
|
|
93
|
+
exec(cmd, () => { });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function deriveKey() {
|
|
99
|
+
try {
|
|
100
|
+
const { machineIdSync } = require("node-machine-id");
|
|
101
|
+
const raw = machineIdSync();
|
|
102
|
+
return crypto.createHash("sha256").update(raw + ENCRYPT_SALT).digest();
|
|
103
|
+
} catch {
|
|
104
|
+
return crypto.createHash("sha256").update(ENCRYPT_SALT).digest();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function encryptPassword(plaintext) {
|
|
109
|
+
const key = deriveKey();
|
|
110
|
+
const iv = crypto.randomBytes(12);
|
|
111
|
+
const cipher = crypto.createCipheriv(ENCRYPT_ALGO, key, iv);
|
|
112
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
113
|
+
const tag = cipher.getAuthTag();
|
|
114
|
+
return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted.toString("hex")}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function decryptPassword(stored) {
|
|
118
|
+
try {
|
|
119
|
+
const [ivHex, tagHex, dataHex] = stored.split(":");
|
|
120
|
+
if (!ivHex || !tagHex || !dataHex) return null;
|
|
121
|
+
const key = deriveKey();
|
|
122
|
+
const decipher = crypto.createDecipheriv(ENCRYPT_ALGO, key, Buffer.from(ivHex, "hex"));
|
|
123
|
+
decipher.setAuthTag(Buffer.from(tagHex, "hex"));
|
|
124
|
+
return decipher.update(Buffer.from(dataHex, "hex")) + decipher.final("utf8");
|
|
125
|
+
} catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let _getSettings = null;
|
|
131
|
+
let _updateSettings = null;
|
|
132
|
+
|
|
133
|
+
function initDbHooks(getSettingsFn, updateSettingsFn) {
|
|
134
|
+
_getSettings = getSettingsFn;
|
|
135
|
+
_updateSettings = updateSettingsFn;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function saveMitmSettings(enabled, password) {
|
|
139
|
+
if (!_updateSettings) return;
|
|
140
|
+
try {
|
|
141
|
+
const updates = { mitmEnabled: enabled };
|
|
142
|
+
if (password) updates.mitmSudoEncrypted = encryptPassword(password);
|
|
143
|
+
await _updateSettings(updates);
|
|
144
|
+
} catch (e) {
|
|
145
|
+
err(`Failed to save settings: ${e.message}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function loadEncryptedPassword() {
|
|
150
|
+
if (!_getSettings) return null;
|
|
151
|
+
try {
|
|
152
|
+
const settings = await _getSettings();
|
|
153
|
+
if (!settings.mitmSudoEncrypted) return null;
|
|
154
|
+
return decryptPassword(settings.mitmSudoEncrypted);
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function checkPort443Free() {
|
|
161
|
+
return new Promise((resolve) => {
|
|
162
|
+
const tester = net.createServer();
|
|
163
|
+
tester.once("error", (err) => {
|
|
164
|
+
if (err.code === "EADDRINUSE") resolve("in-use");
|
|
165
|
+
else resolve("no-permission");
|
|
166
|
+
});
|
|
167
|
+
tester.once("listening", () => { tester.close(() => resolve("free")); });
|
|
168
|
+
tester.listen(MITM_PORT, "127.0.0.1");
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function getPort443Owner(sudoPassword) {
|
|
173
|
+
return new Promise((resolve) => {
|
|
174
|
+
if (IS_WIN) {
|
|
175
|
+
const psCmd = `powershell -NonInteractive -WindowStyle Hidden -Command "` +
|
|
176
|
+
`$c = Get-NetTCPConnection -LocalPort 443 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1; ` +
|
|
177
|
+
`if ($c) { $c.OwningProcess } else { 0 }"`;
|
|
178
|
+
exec(psCmd, { windowsHide: true }, (err, stdout) => {
|
|
179
|
+
if (err) return resolve(null);
|
|
180
|
+
const pid = parseInt(stdout.trim(), 10);
|
|
181
|
+
if (!pid || pid <= 4) return resolve(null);
|
|
182
|
+
exec(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { windowsHide: true }, (e2, out2) => {
|
|
183
|
+
const m = out2?.match(/"([^"]+)"/);
|
|
184
|
+
resolve({ pid, name: m ? m[1] : "unknown" });
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
} else {
|
|
188
|
+
exec(`ps aux | grep "[s]erver.js"`, (err, stdout) => {
|
|
189
|
+
if (!stdout?.trim()) return resolve(null);
|
|
190
|
+
for (const line of stdout.split("\n")) {
|
|
191
|
+
const parts = line.trim().split(/\s+/);
|
|
192
|
+
const pid = parseInt(parts[1], 10);
|
|
193
|
+
if (!isNaN(pid)) return resolve({ pid, name: "node" });
|
|
194
|
+
}
|
|
195
|
+
resolve(null);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function killLeftoverMitm(sudoPassword) {
|
|
202
|
+
if (serverProcess && !serverProcess.killed) {
|
|
203
|
+
try { serverProcess.kill("SIGKILL"); } catch { /* ignore */ }
|
|
204
|
+
serverProcess = null;
|
|
205
|
+
serverPid = null;
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
if (fs.existsSync(PID_FILE)) {
|
|
209
|
+
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
210
|
+
if (savedPid && isProcessAlive(savedPid)) {
|
|
211
|
+
killProcess(savedPid, true, sudoPassword);
|
|
212
|
+
await new Promise(r => setTimeout(r, 500));
|
|
213
|
+
}
|
|
214
|
+
fs.unlinkSync(PID_FILE);
|
|
215
|
+
}
|
|
216
|
+
} catch { /* ignore */ }
|
|
217
|
+
if (!IS_WIN && SERVER_PATH) {
|
|
218
|
+
try {
|
|
219
|
+
const escaped = SERVER_PATH.replace(/'/g, "'\\''");
|
|
220
|
+
if (sudoPassword) {
|
|
221
|
+
const { execWithPassword } = require("./dns/dnsConfig");
|
|
222
|
+
await execWithPassword(`pkill -SIGKILL -f "${escaped}" 2>/dev/null || true`, sudoPassword).catch(() => { });
|
|
223
|
+
} else {
|
|
224
|
+
exec(`pkill -SIGKILL -f "${escaped}" 2>/dev/null || true`, () => { });
|
|
225
|
+
}
|
|
226
|
+
await new Promise(r => setTimeout(r, 500));
|
|
227
|
+
} catch { /* ignore */ }
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function pollMitmHealth(timeoutMs, port = MITM_PORT) {
|
|
232
|
+
return new Promise((resolve) => {
|
|
233
|
+
const deadline = Date.now() + timeoutMs;
|
|
234
|
+
const check = () => {
|
|
235
|
+
const req = https.request(
|
|
236
|
+
{ hostname: "127.0.0.1", port, path: "/_mitm_health", method: "GET", rejectUnauthorized: false },
|
|
237
|
+
(res) => {
|
|
238
|
+
let body = "";
|
|
239
|
+
res.on("data", (d) => { body += d; });
|
|
240
|
+
res.on("end", () => {
|
|
241
|
+
try {
|
|
242
|
+
const json = JSON.parse(body);
|
|
243
|
+
resolve(json.ok === true ? { ok: true, pid: json.pid || null } : null);
|
|
244
|
+
} catch { resolve(null); }
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
req.on("error", () => {
|
|
249
|
+
if (Date.now() < deadline) setTimeout(check, 500);
|
|
250
|
+
else resolve(null);
|
|
251
|
+
});
|
|
252
|
+
req.end();
|
|
253
|
+
};
|
|
254
|
+
check();
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Get full MITM status including per-tool DNS status
|
|
260
|
+
*/
|
|
261
|
+
async function getMitmStatus() {
|
|
262
|
+
let running = serverProcess !== null && !serverProcess.killed;
|
|
263
|
+
let pid = serverPid;
|
|
264
|
+
|
|
265
|
+
if (!running) {
|
|
266
|
+
try {
|
|
267
|
+
if (fs.existsSync(PID_FILE)) {
|
|
268
|
+
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
269
|
+
if (savedPid && isProcessAlive(savedPid)) {
|
|
270
|
+
running = true;
|
|
271
|
+
pid = savedPid;
|
|
272
|
+
} else {
|
|
273
|
+
fs.unlinkSync(PID_FILE);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} catch { /* ignore */ }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const dnsStatus = checkAllDNSStatus();
|
|
280
|
+
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
|
281
|
+
const certExists = fs.existsSync(rootCACertPath);
|
|
282
|
+
const { checkCertInstalled } = require("./cert/install");
|
|
283
|
+
const certTrusted = certExists ? await checkCertInstalled(rootCACertPath) : false;
|
|
284
|
+
|
|
285
|
+
return { running, pid, certExists, certTrusted, dnsStatus };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async function scheduleMitmRestart(apiKey) {
|
|
289
|
+
if (mitmIsRestarting) return;
|
|
290
|
+
|
|
291
|
+
const aliveMs = Date.now() - mitmLastStartTime;
|
|
292
|
+
if (aliveMs >= MITM_RESTART_RESET_MS) mitmRestartCount = 0;
|
|
293
|
+
|
|
294
|
+
if (mitmRestartCount >= MITM_MAX_RESTARTS) {
|
|
295
|
+
err("Max restart attempts reached. Giving up.");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const attempt = mitmRestartCount;
|
|
300
|
+
const delay = MITM_RESTART_DELAYS_MS[Math.min(attempt, MITM_RESTART_DELAYS_MS.length - 1)];
|
|
301
|
+
mitmRestartCount++;
|
|
302
|
+
mitmIsRestarting = true;
|
|
303
|
+
|
|
304
|
+
log(`Restarting in ${delay / 1000}s... (${mitmRestartCount}/${MITM_MAX_RESTARTS})`);
|
|
305
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
const settings = _getSettings ? await _getSettings() : null;
|
|
309
|
+
if (settings && !settings.mitmEnabled) {
|
|
310
|
+
log("MITM disabled, skipping restart");
|
|
311
|
+
mitmIsRestarting = false;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const password = getCachedPassword() || await loadEncryptedPassword();
|
|
315
|
+
if (!password && !IS_WIN) {
|
|
316
|
+
err("No cached password, cannot auto-restart");
|
|
317
|
+
mitmIsRestarting = false;
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
await startServer(apiKey, password);
|
|
321
|
+
log("🔄 Restarted successfully");
|
|
322
|
+
mitmRestartCount = 0;
|
|
323
|
+
mitmIsRestarting = false;
|
|
324
|
+
} catch (e) {
|
|
325
|
+
err(`Restart attempt ${mitmRestartCount}/${MITM_MAX_RESTARTS} failed: ${e.message}`);
|
|
326
|
+
mitmIsRestarting = false;
|
|
327
|
+
// Schedule next retry
|
|
328
|
+
scheduleMitmRestart(apiKey);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Start MITM server only (cert + server, no DNS)
|
|
334
|
+
*/
|
|
335
|
+
async function startServer(apiKey, sudoPassword) {
|
|
336
|
+
if (!serverProcess || serverProcess.killed) {
|
|
337
|
+
try {
|
|
338
|
+
if (fs.existsSync(PID_FILE)) {
|
|
339
|
+
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
340
|
+
if (savedPid && isProcessAlive(savedPid)) {
|
|
341
|
+
serverPid = savedPid;
|
|
342
|
+
log(`♻️ Reusing existing process (PID: ${savedPid})`);
|
|
343
|
+
await saveMitmSettings(true, sudoPassword);
|
|
344
|
+
if (sudoPassword) setCachedPassword(sudoPassword);
|
|
345
|
+
return { running: true, pid: savedPid };
|
|
346
|
+
} else {
|
|
347
|
+
fs.unlinkSync(PID_FILE);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
} catch { /* ignore */ }
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (serverProcess && !serverProcess.killed) {
|
|
354
|
+
throw new Error("MITM server is already running");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
await killLeftoverMitm(sudoPassword);
|
|
358
|
+
|
|
359
|
+
if (!IS_WIN) {
|
|
360
|
+
const portStatus = await checkPort443Free();
|
|
361
|
+
if (portStatus === "in-use" || portStatus === "no-permission") {
|
|
362
|
+
const owner = await getPort443Owner(sudoPassword);
|
|
363
|
+
if (owner && owner.name === "node") {
|
|
364
|
+
log(`Killing orphan node process on port 443 (PID ${owner.pid})...`);
|
|
365
|
+
try {
|
|
366
|
+
const { execWithPassword } = require("./dns/dnsConfig");
|
|
367
|
+
await execWithPassword(`kill -9 ${owner.pid}`, sudoPassword);
|
|
368
|
+
await new Promise(r => setTimeout(r, 800));
|
|
369
|
+
} catch { /* best effort */ }
|
|
370
|
+
} else if (owner) {
|
|
371
|
+
const shortName = owner.name.includes("/")
|
|
372
|
+
? owner.name.split("/").filter(Boolean).pop()
|
|
373
|
+
: owner.name;
|
|
374
|
+
throw new Error(`Port 443 is already in use by "${shortName}" (PID ${owner.pid}). Stop that process first.`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Step 1: Generate Root CA if missing or expired
|
|
380
|
+
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
|
381
|
+
const rootCAKeyPath = path.join(MITM_DIR, "rootCA.key");
|
|
382
|
+
const certExists = fs.existsSync(rootCACertPath) && fs.existsSync(rootCAKeyPath);
|
|
383
|
+
|
|
384
|
+
if (!certExists || isCertExpired(rootCACertPath)) {
|
|
385
|
+
if (certExists) {
|
|
386
|
+
// Uninstall expired cert from system store before regenerating
|
|
387
|
+
log("🔐 Cert expired — uninstalling old cert...");
|
|
388
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
389
|
+
try { await uninstallCert(password, rootCACertPath); } catch { /* best effort */ }
|
|
390
|
+
}
|
|
391
|
+
log("🔐 Generating Root CA...");
|
|
392
|
+
await generateCert();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Step 1.5: Auto-install Root CA if not trusted yet
|
|
396
|
+
const { checkCertInstalled } = require("./cert/install");
|
|
397
|
+
const rootCATrusted = await checkCertInstalled(rootCACertPath);
|
|
398
|
+
if (!rootCATrusted) {
|
|
399
|
+
log("🔐 Cert: not trusted → installing...");
|
|
400
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
401
|
+
if (!password && !IS_WIN) {
|
|
402
|
+
throw new Error("Sudo password required to install Root CA certificate");
|
|
403
|
+
}
|
|
404
|
+
try {
|
|
405
|
+
await installCert(password, rootCACertPath);
|
|
406
|
+
log("🔐 Cert: ✅ trusted");
|
|
407
|
+
} catch (e) {
|
|
408
|
+
throw new Error(`Failed to trust certificate: ${e.message}`);
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
log("🔐 Cert: already trusted ✅");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Step 2: Spawn server (Root CA already installed in Step 1.5)
|
|
415
|
+
log("🚀 Starting server...");
|
|
416
|
+
if (IS_WIN) {
|
|
417
|
+
// Kill any process using port 443 before spawning
|
|
418
|
+
try {
|
|
419
|
+
const psKill = `$c = Get-NetTCPConnection -LocalPort 443 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1; if ($c -and $c.OwningProcess -gt 4) { Stop-Process -Id $c.OwningProcess -Force -ErrorAction SilentlyContinue }`;
|
|
420
|
+
execSync(`powershell -NonInteractive -WindowStyle Hidden -Command "${psKill}"`, { windowsHide: true });
|
|
421
|
+
await new Promise(r => setTimeout(r, 500));
|
|
422
|
+
} catch { /* best effort */ }
|
|
423
|
+
|
|
424
|
+
// Spawn directly — process already has admin rights
|
|
425
|
+
serverProcess = spawn(
|
|
426
|
+
process.execPath,
|
|
427
|
+
[SERVER_PATH],
|
|
428
|
+
{
|
|
429
|
+
detached: false,
|
|
430
|
+
windowsHide: true,
|
|
431
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
432
|
+
env: { ...process.env, ROUTER_API_KEY: apiKey, NODE_ENV: "production" },
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
|
|
437
|
+
} else {
|
|
438
|
+
// Non-Windows: Root CA already installed in Step 1.5, just spawn server
|
|
439
|
+
const inlineCmd = `ROUTER_API_KEY='${apiKey}' NODE_ENV='production' '${process.execPath}' '${SERVER_PATH}'`;
|
|
440
|
+
serverProcess = spawn(
|
|
441
|
+
"sudo", ["-S", "-E", "sh", "-c", inlineCmd],
|
|
442
|
+
{ detached: false, stdio: ["pipe", "pipe", "pipe"] }
|
|
443
|
+
);
|
|
444
|
+
serverProcess.stdin.write(`${sudoPassword}\n`);
|
|
445
|
+
serverProcess.stdin.end();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (serverProcess) {
|
|
449
|
+
serverPid = serverProcess.pid;
|
|
450
|
+
fs.writeFileSync(PID_FILE, String(serverPid));
|
|
451
|
+
mitmLastStartTime = Date.now();
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
let startError = null;
|
|
455
|
+
if (serverProcess) {
|
|
456
|
+
serverProcess.stdout.on("data", (data) => {
|
|
457
|
+
// Route through console.log so consoleLogBuffer captures it for UI streaming
|
|
458
|
+
const lines = data.toString().trimEnd();
|
|
459
|
+
if (lines) console.log(lines);
|
|
460
|
+
});
|
|
461
|
+
serverProcess.stderr.on("data", (data) => {
|
|
462
|
+
const msg = data.toString().trim();
|
|
463
|
+
// Mac/Linux: filter sudo password prompt noise
|
|
464
|
+
if (msg && (IS_WIN || (!msg.includes("Password:") && !msg.includes("password for")))) {
|
|
465
|
+
err(msg);
|
|
466
|
+
startError = msg;
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
serverProcess.on("exit", (code) => {
|
|
470
|
+
log(`Server exited (code: ${code})`);
|
|
471
|
+
serverProcess = null;
|
|
472
|
+
serverPid = null;
|
|
473
|
+
try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
|
|
474
|
+
// Auto-restart on unexpected exit
|
|
475
|
+
if (code !== 0 && !mitmIsRestarting) scheduleMitmRestart(apiKey);
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const health = await pollMitmHealth(8000, MITM_PORT);
|
|
480
|
+
if (!health) {
|
|
481
|
+
if (serverProcess && !serverProcess.killed) { try { serverProcess.kill(); } catch { /* ignore */ } serverProcess = null; }
|
|
482
|
+
const processUsing443 = getProcessUsingPort443();
|
|
483
|
+
const portInfo = processUsing443 ? ` Port 443 already in use by ${processUsing443}.` : "";
|
|
484
|
+
const reason = startError || `Check sudo password or port 443 access.${portInfo}`;
|
|
485
|
+
throw new Error(`MITM server failed to start. ${reason}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
|
|
489
|
+
|
|
490
|
+
log(`✅ Server healthy (PID: ${serverPid || health.pid})`);
|
|
491
|
+
|
|
492
|
+
// Log DNS status per tool
|
|
493
|
+
const dnsStatus = checkAllDNSStatus();
|
|
494
|
+
for (const [tool, active] of Object.entries(dnsStatus)) {
|
|
495
|
+
log(`🌐 DNS ${tool}: ${active ? "✅ active" : "❌ inactive"}`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
await saveMitmSettings(true, sudoPassword);
|
|
499
|
+
if (sudoPassword) setCachedPassword(sudoPassword);
|
|
500
|
+
|
|
501
|
+
return { running: true, pid: serverPid };
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Stop MITM server — removes ALL tool DNS entries first, then kills server
|
|
506
|
+
*/
|
|
507
|
+
async function stopServer(sudoPassword) {
|
|
508
|
+
// Prevent auto-restart from triggering on intentional stop
|
|
509
|
+
mitmIsRestarting = true;
|
|
510
|
+
mitmRestartCount = 0;
|
|
511
|
+
log("⏹ Stopping server...");
|
|
512
|
+
|
|
513
|
+
// Kill server process
|
|
514
|
+
const proc = serverProcess;
|
|
515
|
+
const pidToKill = proc && !proc.killed
|
|
516
|
+
? proc.pid
|
|
517
|
+
: (() => { try { return parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10); } catch { return null; } })();
|
|
518
|
+
|
|
519
|
+
if (pidToKill && isProcessAlive(pidToKill)) {
|
|
520
|
+
log(`Killing server (PID: ${pidToKill})...`);
|
|
521
|
+
killProcess(pidToKill, false, sudoPassword);
|
|
522
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
523
|
+
if (isProcessAlive(pidToKill)) killProcess(pidToKill, true, sudoPassword);
|
|
524
|
+
}
|
|
525
|
+
serverProcess = null;
|
|
526
|
+
serverPid = null;
|
|
527
|
+
|
|
528
|
+
if (IS_WIN) {
|
|
529
|
+
// Process already has admin rights — edit hosts file directly
|
|
530
|
+
const hostsFile = path.join(process.env.SystemRoot || "C:\\Windows", "System32", "drivers", "etc", "hosts");
|
|
531
|
+
const allHosts = Object.values(TOOL_HOSTS).flat();
|
|
532
|
+
try {
|
|
533
|
+
const hostsContent = fs.readFileSync(hostsFile, "utf8");
|
|
534
|
+
const filtered = hostsContent.split(/\r?\n/).filter(l => !allHosts.some(h => l.includes(h))).join("\r\n");
|
|
535
|
+
fs.writeFileSync(hostsFile, filtered, "utf8");
|
|
536
|
+
require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
|
|
537
|
+
} catch (e) { err(`Failed to clean hosts: ${e.message}`); }
|
|
538
|
+
} else {
|
|
539
|
+
await removeAllDNSEntries(sudoPassword);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
|
|
543
|
+
await saveMitmSettings(false, null);
|
|
544
|
+
mitmIsRestarting = false;
|
|
545
|
+
|
|
546
|
+
return { running: false, pid: null };
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Enable DNS for a specific tool (requires server running)
|
|
551
|
+
*/
|
|
552
|
+
async function enableToolDNS(tool, sudoPassword) {
|
|
553
|
+
const status = await getMitmStatus();
|
|
554
|
+
if (!status.running) throw new Error("MITM server is not running. Start the server first.");
|
|
555
|
+
|
|
556
|
+
// Use cached password if not provided
|
|
557
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
558
|
+
await addDNSEntry(tool, password);
|
|
559
|
+
return { success: true };
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Disable DNS for a specific tool
|
|
564
|
+
*/
|
|
565
|
+
async function disableToolDNS(tool, sudoPassword) {
|
|
566
|
+
// Use cached password if not provided
|
|
567
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
568
|
+
await removeDNSEntry(tool, password);
|
|
569
|
+
return { success: true };
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Install Root CA to system trust store (standalone, no server start)
|
|
574
|
+
*/
|
|
575
|
+
async function trustCert(sudoPassword) {
|
|
576
|
+
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
|
577
|
+
if (!fs.existsSync(rootCACertPath)) throw new Error("Root CA not found. Start server first to generate it.");
|
|
578
|
+
const { installCert } = require("./cert/install");
|
|
579
|
+
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
|
580
|
+
if (!password && !IS_WIN) throw new Error("Sudo password required to trust certificate");
|
|
581
|
+
await installCert(password, rootCACertPath);
|
|
582
|
+
if (password) setCachedPassword(password);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Legacy aliases for backward compatibility
|
|
586
|
+
const startMitm = startServer;
|
|
587
|
+
const stopMitm = stopServer;
|
|
588
|
+
|
|
589
|
+
module.exports = {
|
|
590
|
+
getMitmStatus,
|
|
591
|
+
startServer,
|
|
592
|
+
stopServer,
|
|
593
|
+
enableToolDNS,
|
|
594
|
+
disableToolDNS,
|
|
595
|
+
trustCert,
|
|
596
|
+
// Legacy
|
|
597
|
+
startMitm,
|
|
598
|
+
stopMitm,
|
|
599
|
+
getCachedPassword,
|
|
600
|
+
setCachedPassword,
|
|
601
|
+
loadEncryptedPassword,
|
|
602
|
+
initDbHooks,
|
|
603
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
|
|
4
|
+
// Single source of truth for data directory — matches localDb.js logic
|
|
5
|
+
function getDataDir() {
|
|
6
|
+
if (process.env.DATA_DIR) return process.env.DATA_DIR;
|
|
7
|
+
if (process.platform === "win32") {
|
|
8
|
+
return path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "arouter");
|
|
9
|
+
}
|
|
10
|
+
return path.join(os.homedir(), ".arouter");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DATA_DIR = getDataDir();
|
|
14
|
+
const MITM_DIR = path.join(DATA_DIR, "mitm");
|
|
15
|
+
|
|
16
|
+
module.exports = { DATA_DIR, MITM_DIR };
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|