Harden admin API routes and shell usage
- Require admin auth on interface-local-ip, network-interfaces, next-listen-port and public-ip (interface-local-ip and public-ip allowed unauthenticated command injection as root) - Validate interface names and call ip/curl via execFileSync - Write host/client WireGuard configs with fs instead of shell heredocs, validating IPs, AllowedIPs, endpoint and listen port - Replace rm -rf/cat/mkdir/chmod/test shell calls with fs APIs - Refuse private media requested through the public media route Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -5,7 +5,11 @@ import type {
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import grabDirNames from "@/src/utils/grab-dir-names";
|
||||
import { execSync } from "node:child_process";
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import validateIpv4 from "@/src/utils/validate-ipv4";
|
||||
import validateAllowedIps from "@/src/utils/validate-allowed-ips";
|
||||
import validateEndpointHost from "@/src/utils/validate-endpoint-host";
|
||||
import grabHostPublicIPAddress from "./grab-host-public-ip-address";
|
||||
import setupWireguardHost from "./setup-wireguard-host";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
@@ -72,6 +76,24 @@ export default async function setupWireguardClient({
|
||||
};
|
||||
}
|
||||
|
||||
if (!validateIpv4({ ip: CLIENT_WG_IP })) {
|
||||
return {
|
||||
success: false,
|
||||
msg: `Invalid Client Private IP address: ${CLIENT_WG_IP}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
client?.allow_all_ips != 1 &&
|
||||
client?.allowed_ips &&
|
||||
!validateAllowedIps({ value: client.allowed_ips })
|
||||
) {
|
||||
return {
|
||||
success: false,
|
||||
msg: `Invalid Allowed IPs: ${client.allowed_ips}`,
|
||||
};
|
||||
}
|
||||
|
||||
const HOST_WG_IP = resolved_host?.wg_ip_address;
|
||||
|
||||
if (!HOST_WG_IP) {
|
||||
@@ -104,53 +126,57 @@ export default async function setupWireguardClient({
|
||||
client?.public_ip_address ||
|
||||
HOST_WG_IP;
|
||||
|
||||
const CLIENT_PRIVATE_KEY = execSync(`cat ${CLIENT_PRIVATE_KEY_FILE}`, {
|
||||
encoding: "utf-8",
|
||||
}).trim();
|
||||
if (!validateEndpointHost({ value: PUBLIC_IP_ADDRESS })) {
|
||||
return {
|
||||
success: false,
|
||||
msg: `Invalid Host public IP address: ${PUBLIC_IP_ADDRESS}`,
|
||||
};
|
||||
}
|
||||
|
||||
const CLIENT_PUBLIC_KEY = execSync(`cat ${CLIENT_PUBLIC_KEY_FILE}`, {
|
||||
encoding: "utf-8",
|
||||
}).trim();
|
||||
const LISTEN_PORT = Number(
|
||||
resolved_host?.listen_port || AppData["DefaultWGListenPort"],
|
||||
);
|
||||
|
||||
const HOST_PUBLIC_KEY = execSync(
|
||||
`cat ${path.join(HOST_CONFIG_DIR, WIREGUARD_PUBLIC_KEY_FILE_NAME)}`,
|
||||
{ encoding: "utf-8" },
|
||||
if (!Number.isInteger(LISTEN_PORT)) {
|
||||
return {
|
||||
success: false,
|
||||
msg: `Invalid Host listen port: ${resolved_host?.listen_port}`,
|
||||
};
|
||||
}
|
||||
|
||||
const CLIENT_PRIVATE_KEY = readFileSync(
|
||||
CLIENT_PRIVATE_KEY_FILE,
|
||||
"utf-8",
|
||||
).trim();
|
||||
|
||||
let sh = ``;
|
||||
const HOST_PUBLIC_KEY = readFileSync(
|
||||
path.join(HOST_CONFIG_DIR, WIREGUARD_PUBLIC_KEY_FILE_NAME),
|
||||
"utf-8",
|
||||
).trim();
|
||||
|
||||
sh += `cd ${CLIENT_DIR}\n`;
|
||||
sh += `cat > ${WIREGUARD_CLIENT_CONFIG_FILE_NAME} << EOF\n`;
|
||||
sh += `\n`;
|
||||
sh += `[Interface]\n`;
|
||||
sh += `Address = ${CLIENT_WG_IP}/32\n`;
|
||||
sh += `PrivateKey = ${CLIENT_PRIVATE_KEY}\n`;
|
||||
let CLIENT_CONFIG = ``;
|
||||
|
||||
CLIENT_CONFIG += `\n`;
|
||||
CLIENT_CONFIG += `[Interface]\n`;
|
||||
CLIENT_CONFIG += `Address = ${CLIENT_WG_IP}/32\n`;
|
||||
CLIENT_CONFIG += `PrivateKey = ${CLIENT_PRIVATE_KEY}\n`;
|
||||
if (client?.allow_all_ips == 1) {
|
||||
sh += `DNS = 1.1.1.1\n`;
|
||||
CLIENT_CONFIG += `DNS = 1.1.1.1\n`;
|
||||
}
|
||||
sh += `\n`;
|
||||
sh += `[Peer]\n`;
|
||||
sh += `PublicKey = ${HOST_PUBLIC_KEY}\n`;
|
||||
sh += `Endpoint = ${PUBLIC_IP_ADDRESS}:${resolved_host?.listen_port || AppData["DefaultWGListenPort"]}\n`;
|
||||
CLIENT_CONFIG += `\n`;
|
||||
CLIENT_CONFIG += `[Peer]\n`;
|
||||
CLIENT_CONFIG += `PublicKey = ${HOST_PUBLIC_KEY}\n`;
|
||||
CLIENT_CONFIG += `Endpoint = ${PUBLIC_IP_ADDRESS}:${LISTEN_PORT}\n`;
|
||||
|
||||
if (client?.allow_all_ips == 1) {
|
||||
sh += `AllowedIPs = 0.0.0.0/0, ::/0\n`;
|
||||
CLIENT_CONFIG += `AllowedIPs = 0.0.0.0/0, ::/0\n`;
|
||||
} else if (client?.allowed_ips) {
|
||||
sh += `AllowedIPs = ${client.allowed_ips}\n`;
|
||||
CLIENT_CONFIG += `AllowedIPs = ${client.allowed_ips}\n`;
|
||||
}
|
||||
|
||||
sh += `PersistentKeepalive = 25\n`;
|
||||
CLIENT_CONFIG += `PersistentKeepalive = 25\n`;
|
||||
|
||||
sh += `EOF\n`;
|
||||
sh += `\n`;
|
||||
|
||||
const exec = execSync(sh, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
|
||||
const CLIENT_CONFIG = execSync(`cat ${CLIENT_CONFIG_FILE}`, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
writeFileSync(CLIENT_CONFIG_FILE, CLIENT_CONFIG, { mode: 0o600 });
|
||||
|
||||
const host_setup_res = skip_host_setup
|
||||
? { success: true }
|
||||
|
||||
Reference in New Issue
Block a user