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:
@@ -1,5 +1,5 @@
|
||||
import _ from "lodash";
|
||||
import { execSync } from "node:child_process";
|
||||
import { rmSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { AdminCrudAPIParams, TableType } from "@/src/types";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
@@ -14,7 +14,7 @@ import type {
|
||||
BUN_SQLITE_WGUI_HOSTS,
|
||||
} from "@/db/types/db";
|
||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||
import type { ServerQueryParam } from "@moduletrace/bun-sqlite/dist/types";
|
||||
import type { ServerQueryParam } from "@moduletrace/bun-sqlite/types";
|
||||
import grabClientDirnames from "@/src/functions/backend/setup/grab-client-dir-names";
|
||||
|
||||
const { WGUI_LIB_HOSTS_CONFIGS_DIR, WGUI_LIB_HOST_CLIENTS_DIR_NAME } =
|
||||
@@ -72,7 +72,7 @@ export default async function (
|
||||
});
|
||||
|
||||
try {
|
||||
execSync(`rm -rf ${CLIENT_DIR}`, { encoding: "utf-8" });
|
||||
rmSync(CLIENT_DIR, { recursive: true, force: true });
|
||||
} catch (error) {}
|
||||
|
||||
affected_host_ids.add(host_id);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import getInterfaceLocalIP from "@/src/functions/backend/setup/get-interface-local-ip";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
import adminApiGuard from "@/src/functions/backend/auth/admin-api-guard";
|
||||
import type {
|
||||
APIResponseObject,
|
||||
BunextAPIRouteHandler,
|
||||
@@ -11,6 +11,13 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
|
||||
if (params.req.method !== "GET") {
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
const unauthorized_res = await adminApiGuard({ req: params.req });
|
||||
|
||||
if (unauthorized_res) {
|
||||
return unauthorized_res;
|
||||
}
|
||||
|
||||
const url = new URL(params.req.url || "");
|
||||
const iface = url.searchParams.get("interface") || undefined;
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import grabHostNetworkInterfaces from "@/src/functions/backend/setup/grab-host-network-interfaces";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
import adminApiGuard from "@/src/functions/backend/auth/admin-api-guard";
|
||||
import type {
|
||||
APIResponseObject,
|
||||
BunextAPIRouteHandler,
|
||||
@@ -11,6 +11,13 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
|
||||
if (params.req.method !== "GET") {
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
const unauthorized_res = await adminApiGuard({ req: params.req });
|
||||
|
||||
if (unauthorized_res) {
|
||||
return unauthorized_res;
|
||||
}
|
||||
|
||||
try {
|
||||
const interfaces = await grabHostNetworkInterfaces();
|
||||
return { success: true, stringRes: JSON.stringify(interfaces) };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import getNextAvailableListenPort from "@/src/functions/backend/setup/get-next-available-listen-port";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
import adminApiGuard from "@/src/functions/backend/auth/admin-api-guard";
|
||||
import type {
|
||||
APIResponseObject,
|
||||
BunextAPIRouteHandler,
|
||||
@@ -11,6 +11,13 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
|
||||
if (params.req.method !== "GET") {
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
const unauthorized_res = await adminApiGuard({ req: params.req });
|
||||
|
||||
if (unauthorized_res) {
|
||||
return unauthorized_res;
|
||||
}
|
||||
|
||||
try {
|
||||
const port = await getNextAvailableListenPort();
|
||||
return { success: true, numberRes: port };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import grabHostPublicIPAddress from "@/src/functions/backend/setup/grab-host-public-ip-address";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
import adminApiGuard from "@/src/functions/backend/auth/admin-api-guard";
|
||||
import type {
|
||||
APIResponseObject,
|
||||
BunextAPIRouteHandler,
|
||||
@@ -11,6 +11,13 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
|
||||
if (params.req.method !== "GET") {
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
const unauthorized_res = await adminApiGuard({ req: params.req });
|
||||
|
||||
if (unauthorized_res) {
|
||||
return unauthorized_res;
|
||||
}
|
||||
|
||||
const url = new URL(params.req.url || "");
|
||||
const iface = url.searchParams.get("interface") || undefined;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user