mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Isolate cloudflared runtime environment
This commit is contained in:
@@ -24,6 +24,18 @@ type AssetSpec = {
|
||||
downloadUrl: string;
|
||||
};
|
||||
|
||||
type CloudflaredRuntimeDirs = {
|
||||
runtimeRoot: string;
|
||||
homeDir: string;
|
||||
configDir: string;
|
||||
cacheDir: string;
|
||||
dataDir: string;
|
||||
tempDir: string;
|
||||
userProfileDir: string;
|
||||
appDataDir: string;
|
||||
localAppDataDir: string;
|
||||
};
|
||||
|
||||
type BinaryResolution = {
|
||||
binaryPath: string | null;
|
||||
source: CloudflaredInstallSource | null;
|
||||
@@ -125,6 +137,24 @@ function getLogFilePath() {
|
||||
return path.join(getTunnelDir(), "quick-tunnel.log");
|
||||
}
|
||||
|
||||
export function getCloudflaredRuntimeDirs(): CloudflaredRuntimeDirs {
|
||||
const runtimeRoot = path.join(getTunnelDir(), "runtime");
|
||||
const homeDir = path.join(runtimeRoot, "home");
|
||||
const userProfileDir = path.join(runtimeRoot, "userprofile");
|
||||
|
||||
return {
|
||||
runtimeRoot,
|
||||
homeDir,
|
||||
configDir: path.join(runtimeRoot, "config"),
|
||||
cacheDir: path.join(runtimeRoot, "cache"),
|
||||
dataDir: path.join(runtimeRoot, "data"),
|
||||
tempDir: path.join(runtimeRoot, "tmp"),
|
||||
userProfileDir,
|
||||
appDataDir: path.join(userProfileDir, "AppData", "Roaming"),
|
||||
localAppDataDir: path.join(userProfileDir, "AppData", "Local"),
|
||||
};
|
||||
}
|
||||
|
||||
function getLocalTargetUrl() {
|
||||
const { apiPort } = getRuntimePorts();
|
||||
return `http://127.0.0.1:${apiPort}`;
|
||||
@@ -138,6 +168,13 @@ async function ensureTunnelDir() {
|
||||
await fs.mkdir(path.join(getTunnelDir(), "bin"), { recursive: true });
|
||||
}
|
||||
|
||||
async function ensureTunnelRuntimeDirs() {
|
||||
const runtimeDirs = getCloudflaredRuntimeDirs();
|
||||
await Promise.all(
|
||||
Object.values(runtimeDirs).map((dirPath) => fs.mkdir(dirPath, { recursive: true }))
|
||||
);
|
||||
}
|
||||
|
||||
async function readStateFile(): Promise<PersistedTunnelState> {
|
||||
try {
|
||||
const content = await fs.readFile(getStateFilePath(), "utf8");
|
||||
@@ -202,7 +239,8 @@ export function extractTryCloudflareUrl(text: string) {
|
||||
}
|
||||
|
||||
export function buildCloudflaredChildEnv(
|
||||
sourceEnv: NodeJS.ProcessEnv = process.env
|
||||
sourceEnv: NodeJS.ProcessEnv = process.env,
|
||||
runtimeDirs: CloudflaredRuntimeDirs = getCloudflaredRuntimeDirs()
|
||||
): NodeJS.ProcessEnv {
|
||||
const childEnv: NodeJS.ProcessEnv = {};
|
||||
|
||||
@@ -213,9 +251,25 @@ export function buildCloudflaredChildEnv(
|
||||
}
|
||||
}
|
||||
|
||||
childEnv.HOME = runtimeDirs.homeDir;
|
||||
childEnv.XDG_CONFIG_HOME = runtimeDirs.configDir;
|
||||
childEnv.XDG_CACHE_HOME = runtimeDirs.cacheDir;
|
||||
childEnv.XDG_DATA_HOME = runtimeDirs.dataDir;
|
||||
childEnv.USERPROFILE = runtimeDirs.userProfileDir;
|
||||
childEnv.APPDATA = runtimeDirs.appDataDir;
|
||||
childEnv.LOCALAPPDATA = runtimeDirs.localAppDataDir;
|
||||
|
||||
if (!childEnv.TMPDIR) childEnv.TMPDIR = runtimeDirs.tempDir;
|
||||
if (!childEnv.TMP) childEnv.TMP = runtimeDirs.tempDir;
|
||||
if (!childEnv.TEMP) childEnv.TEMP = runtimeDirs.tempDir;
|
||||
|
||||
return childEnv;
|
||||
}
|
||||
|
||||
export function getCloudflaredStartArgs(targetUrl: string) {
|
||||
return ["tunnel", "--url", targetUrl, "--no-autoupdate"];
|
||||
}
|
||||
|
||||
export function getCloudflaredAssetSpec(
|
||||
platform = process.platform,
|
||||
arch = process.arch
|
||||
@@ -493,6 +547,7 @@ export async function startCloudflaredTunnel(): Promise<CloudflaredTunnelStatus>
|
||||
|
||||
await stopExistingTunnel();
|
||||
await ensureTunnelDir();
|
||||
await ensureTunnelRuntimeDirs();
|
||||
await fs.writeFile(getLogFilePath(), "", "utf8");
|
||||
|
||||
await writeStateFile({
|
||||
@@ -509,7 +564,7 @@ export async function startCloudflaredTunnel(): Promise<CloudflaredTunnelStatus>
|
||||
|
||||
const child = spawn(
|
||||
binary.binaryPath as string,
|
||||
["tunnel", "--url", targetUrl, "--no-autoupdate", "--protocol", "http2"],
|
||||
getCloudflaredStartArgs(targetUrl),
|
||||
{
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
env: buildCloudflaredChildEnv(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import assert from "node:assert/strict";
|
||||
import {
|
||||
buildCloudflaredChildEnv,
|
||||
extractTryCloudflareUrl,
|
||||
getCloudflaredStartArgs,
|
||||
getCloudflaredAssetSpec,
|
||||
} from "../../src/lib/cloudflaredTunnel.ts";
|
||||
|
||||
@@ -47,18 +48,45 @@ test("getCloudflaredAssetSpec returns null for unsupported platforms", () => {
|
||||
assert.equal(getCloudflaredAssetSpec("freebsd", "x64"), null);
|
||||
});
|
||||
|
||||
test("buildCloudflaredChildEnv keeps runtime essentials but drops secrets", () => {
|
||||
test("buildCloudflaredChildEnv keeps runtime essentials, isolates runtime dirs, and drops secrets", () => {
|
||||
const env = buildCloudflaredChildEnv({
|
||||
PATH: "/usr/bin",
|
||||
HOME: "/tmp/home",
|
||||
HTTPS_PROXY: "http://proxy.internal:8080",
|
||||
JWT_SECRET: "top-secret",
|
||||
API_KEY_SECRET: "another-secret",
|
||||
}, {
|
||||
runtimeRoot: "/managed/runtime",
|
||||
homeDir: "/managed/runtime/home",
|
||||
configDir: "/managed/runtime/config",
|
||||
cacheDir: "/managed/runtime/cache",
|
||||
dataDir: "/managed/runtime/data",
|
||||
tempDir: "/managed/runtime/tmp",
|
||||
userProfileDir: "/managed/runtime/userprofile",
|
||||
appDataDir: "/managed/runtime/userprofile/AppData/Roaming",
|
||||
localAppDataDir: "/managed/runtime/userprofile/AppData/Local",
|
||||
});
|
||||
|
||||
assert.deepEqual(env, {
|
||||
PATH: "/usr/bin",
|
||||
HOME: "/tmp/home",
|
||||
HTTPS_PROXY: "http://proxy.internal:8080",
|
||||
HOME: "/managed/runtime/home",
|
||||
XDG_CONFIG_HOME: "/managed/runtime/config",
|
||||
XDG_CACHE_HOME: "/managed/runtime/cache",
|
||||
XDG_DATA_HOME: "/managed/runtime/data",
|
||||
USERPROFILE: "/managed/runtime/userprofile",
|
||||
APPDATA: "/managed/runtime/userprofile/AppData/Roaming",
|
||||
LOCALAPPDATA: "/managed/runtime/userprofile/AppData/Local",
|
||||
TMPDIR: "/managed/runtime/tmp",
|
||||
TMP: "/managed/runtime/tmp",
|
||||
TEMP: "/managed/runtime/tmp",
|
||||
});
|
||||
});
|
||||
|
||||
test("getCloudflaredStartArgs relies on cloudflared protocol auto-negotiation", () => {
|
||||
assert.deepEqual(getCloudflaredStartArgs("http://127.0.0.1:20128"), [
|
||||
"tunnel",
|
||||
"--url",
|
||||
"http://127.0.0.1:20128",
|
||||
"--no-autoupdate",
|
||||
]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user