Refactor main host setup

This commit is contained in:
2026-09-20 15:37:57 +01:00
parent 3c1d2b61f6
commit 69111e461e
47 changed files with 669 additions and 591 deletions
@@ -98,10 +98,10 @@ function acceptLines({
const port_chunks = ports[0] ? chunkPorts({ ports }) : [[]];
for (let p = 0; p < protocols.length; p++) {
const proto = protocols[p];
const proto = protocols[p];
for (let c = 0; c < port_chunks.length; c++) {
const chunk = port_chunks[c] || [];
for (let c = 0; c < port_chunks.length; c++) {
const chunk = port_chunks[c] || [];
lines.push(
joinArgs([
@@ -1,12 +1,10 @@
import type {
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
import BunSQLite from "@moduletrace/bun-sqlite";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import type { TableType, User } from "@/src/types";
import setupWireguardHost from "./setup-wireguard-host";
import grabHostPublicIPAddress from "./grab-host-public-ip-address";
import { AppData } from "@/src/data/app-data";
type Params = {
wg_ip_address?: string | null;
@@ -64,10 +62,10 @@ export default async function createWireguardHost({
};
if (is_main_host) {
insert_data.id = 0;
insert_data.id = AppData["WireguardMainHostID"];
}
const insert_host = await BunSQLite.insert<
const insert_host_res = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
@@ -76,15 +74,17 @@ export default async function createWireguardHost({
update_on_duplicate: true,
});
if (!insert_host.success || !insert_host.postInsertReturn?.insertId) {
const host_id = is_main_host
? AppData["WireguardMainHostID"]
: insert_host_res.postInsertReturn?.insertId;
if (typeof host_id !== "number") {
return {
success: false,
msg: `Could not create the host record: ${insert_host.msg}`,
msg: `Could not create the host record: ${insert_host_res.msg}`,
};
}
const host_id = Number(insert_host.postInsertReturn?.insertId);
const host: BUN_SQLITE_WGUI_HOSTS = {
id: host_id,
user_id: user.id,
@@ -96,19 +96,6 @@ export default async function createWireguardHost({
listen_port: listen_port != null ? listen_port : undefined,
};
if (host_id === 0 && final_interface) {
await BunSQLite.insert<BUN_SQLITE_WGUI_VARIABLES, TableType>({
table: "variables",
data: [
{
key: "main_host_public_interface",
value: final_interface,
},
],
update_on_duplicate: true,
});
}
const setup_res = await setupWireguardHost({
host,
wg_subnet_ip: wg_ip,
@@ -0,0 +1,96 @@
import type {
BUN_SQLITE_WGUI_CLIENTS,
BUN_SQLITE_WGUI_CLIENT_RULES,
BUN_SQLITE_WGUI_HOSTS,
} from "@/db/types/db";
import BunSQLite from "@moduletrace/bun-sqlite";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import type { TableType, User } from "@/src/types";
import manageWireguardHost from "./manage-wireguard-host";
import grabHostDirnames from "./grab-host-dir-names";
import grabClientDirnames from "./grab-client-dir-names";
import { execSync } from "node:child_process";
type Params = {
host_id: number;
user: User;
};
export default async function deleteWireguardHost({
host_id,
user,
}: Params): Promise<APIResponseObject> {
try {
const host_clients_res = await BunSQLite.select<
BUN_SQLITE_WGUI_CLIENTS,
TableType
>({
table: "clients",
query: {
query: {
host_id: { value: String(host_id) },
},
},
});
const clients = host_clients_res.payload || [];
for (let i = 0; i < clients.length; i++) {
const client = clients[i];
if (!client?.id) continue;
await BunSQLite.delete<BUN_SQLITE_WGUI_CLIENT_RULES, TableType>({
table: "client_rules",
query: {
query: {
client_id: { value: String(client.id) },
},
},
});
const { CLIENT_DIR } = grabClientDirnames({
client,
host_id,
});
try {
execSync(`rm -rf ${CLIENT_DIR}`, { encoding: "utf-8" });
} catch {}
await BunSQLite.delete<BUN_SQLITE_WGUI_CLIENTS, TableType>({
table: "clients",
targetId: client.id,
});
}
const { HOST_CONFIG_DIR, INTERFACE_NAME } = grabHostDirnames({
host: { id: host_id },
});
try {
manageWireguardHost({
action: "down",
host_id,
});
} catch {}
try {
execSync(`rm -rf ${HOST_CONFIG_DIR}`, { encoding: "utf-8" });
} catch {}
const del_host = await BunSQLite.sql({
sql: `DELETE FROM HOSTS WHERE id=?`,
values: [host_id],
});
return {
success: true,
msg: `Host ${host_id} deleted`,
};
} catch (error: any) {
return {
success: false,
msg: error.message,
};
}
}
@@ -17,7 +17,7 @@ const {
} = grabDirNames();
export default function grabHostDirnames({ host }: Params) {
const HOST_ID = host?.id || AppData["WireguardHostID"];
const HOST_ID = host?.id || AppData["WireguardMainHostID"];
const INTERFACE_NAME = deriveWireguardInterfaceName({ host_id: HOST_ID });
@@ -1,7 +1,6 @@
import type {
BUN_SQLITE_WGUI_CLIENTS,
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import BunSQLite from "@moduletrace/bun-sqlite";
@@ -21,18 +20,7 @@ type Params = {
export default async function grabNextAvailableClientIPAddress({
host,
}: Params): Promise<APIResponseObject> {
const variables_res = await BunSQLite.select<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
});
const variables = variables_res.payload;
const HOST_WG_IP =
host?.wg_ip_address ||
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value;
const HOST_WG_IP = host?.wg_ip_address;
if (!HOST_WG_IP) {
return {
@@ -97,6 +85,6 @@ export default async function grabNextAvailableClientIPAddress({
return {
success: true,
msg: `${subnet}${next_last_octet}`,
stringRes: `${subnet}${next_last_octet}`,
};
}
}
@@ -18,7 +18,7 @@ type Params = {
export default function manageWireguardHost({
action,
host_id = AppData["WireguardHostID"],
host_id = AppData["WireguardMainHostID"],
}: Params): APIResponseObject {
const { HOST_CONFIG_FILE, INTERFACE_NAME } = grabHostDirnames({
host: { id: host_id },
@@ -1,7 +1,6 @@
import type {
BUN_SQLITE_WGUI_CLIENTS,
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import { AppData } from "@/src/data/app-data";
import grabDirNames from "@/src/utils/grab-dir-names";
@@ -42,16 +41,20 @@ export default async function setupWireguardClient({
user,
skip_host_setup,
}: Params): Promise<APIResponseObject> {
const host_id = host?.id || AppData["WireguardHostID"];
const host_id = host?.id || AppData["WireguardMainHostID"];
const variables_res = await BunSQLite.select<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
});
let resolved_host = host;
const variables = variables_res.payload;
if (!resolved_host) {
const host_res = await BunSQLite.select<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
targetId: host_id,
});
resolved_host = host_res.singleRes || undefined;
}
const {
CLIENT_WG_IP,
@@ -69,9 +72,7 @@ export default async function setupWireguardClient({
};
}
const HOST_WG_IP = host?.id
? host?.wg_ip_address
: variables?.find((v) => v.key == "main_host_wg_ip_address")?.value;
const HOST_WG_IP = resolved_host?.wg_ip_address;
if (!HOST_WG_IP) {
return {
@@ -98,9 +99,7 @@ export default async function setupWireguardClient({
try {
const PUBLIC_IP_ADDRESS =
host?.public_ip_address ||
variables?.find((v) => v.key == "main_host_public_ip_address")
?.value ||
resolved_host?.public_ip_address ||
(await grabHostPublicIPAddress()) ||
client?.public_ip_address ||
HOST_WG_IP;
@@ -130,7 +129,7 @@ export default async function setupWireguardClient({
sh += `\n`;
sh += `[Peer]\n`;
sh += `PublicKey = ${HOST_PUBLIC_KEY}\n`;
sh += `Endpoint = ${PUBLIC_IP_ADDRESS}:${host?.listen_port || AppData["DefaultWGListenPort"]}\n`;
sh += `Endpoint = ${PUBLIC_IP_ADDRESS}:${resolved_host?.listen_port || AppData["DefaultWGListenPort"]}\n`;
if (client?.allow_all_ips == 1) {
sh += `AllowedIPs = 0.0.0.0/0, ::/0\n`;
@@ -154,7 +153,7 @@ export default async function setupWireguardClient({
const host_setup_res = skip_host_setup
? { success: true }
: await setupWireguardHost({
host,
host: resolved_host,
user,
is_update_after_client_setup: true,
});
@@ -2,7 +2,6 @@ import type {
BUN_SQLITE_WGUI_CLIENTS,
BUN_SQLITE_WGUI_CLIENT_RULES,
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import grabDirNames from "@/src/utils/grab-dir-names";
import { execSync } from "node:child_process";
@@ -46,15 +45,6 @@ export default async function setupWireguardHost({
POST_UP_PATH,
} = grabHostDirnames({ host });
const variables_res = await BunSQLite.select<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
});
const variables = variables_res.payload;
const host_clients_res = await BunSQLite.select<
BUN_SQLITE_WGUI_CLIENTS,
TableType
@@ -103,10 +93,7 @@ export default async function setupWireguardHost({
const TARGET_INTERFACE =
host?.interface || (await grabHostNetworkInterface());
const HOST_WG_IP =
host?.wg_ip_address ||
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value ||
wg_subnet_ip;
const HOST_WG_IP = host?.wg_ip_address || wg_subnet_ip;
if (!HOST_WG_IP) {
return {
@@ -159,37 +146,7 @@ export default async function setupWireguardHost({
encoding: "utf-8",
}).trim();
if (HOST_ID == 0 && !is_update_after_client_setup) {
const variables_data: Array<{ key: string; value: string }> = [
{
key: "main_host_wg_ip_address",
value: HOST_WG_IP,
},
{
key: "main_host_wg_public_key",
value: HOST_PUBLIC_KEY,
},
];
if (host?.interface) {
variables_data.push({
key: "main_host_public_interface",
value: host.interface,
});
}
const update_variables = await BunSQLite.insert<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
data: variables_data as BUN_SQLITE_WGUI_VARIABLES[],
update_on_duplicate: true,
});
if (!update_variables.success) {
throw new Error(`Couldn't update host variables`);
}
} else if (HOST_ID && !is_update_after_client_setup) {
if (!is_update_after_client_setup) {
const update_host = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
@@ -2,12 +2,8 @@ import grabDirNames from "@/src/utils/grab-dir-names";
import fs from "node:fs";
import manageWireguardHost from "./manage-wireguard-host";
import BunSQLite from "@moduletrace/bun-sqlite";
import type {
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
import type { TableType } from "@/src/types";
import { AppData } from "@/src/data/app-data";
import bunext from "@moduletrace/bunext";
const HOST_CONFIG_FILE_NAME_PATTERN = /^wgui(\d+)\.conf$/;
@@ -24,44 +20,22 @@ export default async function syncWireguardHosts() {
HOST_CONFIG_FILE_NAME_PATTERN.test(file_name),
);
const variables = await BunSQLite.select<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
});
const hosts = await BunSQLite.select<BUN_SQLITE_WGUI_HOSTS, TableType>({
table: "hosts",
});
const main_host_ip = variables.payload?.find(
(v) => v.key == "main_host_wg_ip_address",
)?.value;
const main_host = hosts.payload?.find((h) => h.id === 0);
const main_host_public_ip = variables.payload?.find(
(v) => v.key == "main_host_public_ip_address",
)?.value;
const main_host_interface = variables.payload?.find(
(v) => v.key == "main_host_public_interface",
)?.value;
if (!main_host_ip) {
if (!main_host?.wg_ip_address) {
throw new Error(`Main Host not set yet`);
}
const all_hosts: BUN_SQLITE_WGUI_HOSTS[] = [
{
id: 0,
public_ip_address: main_host_public_ip,
wg_ip_address: main_host_ip,
interface: main_host_interface,
},
...(hosts.payload || []),
const sorted_hosts = [
main_host,
...(hosts.payload || []).filter((h) => h.id !== 0),
];
for (const host of all_hosts) {
for (const host of sorted_hosts) {
if (typeof host.id == "number") {
const res = manageWireguardHost({
action: "up",
@@ -1,9 +1,4 @@
import type {
BUN_SQLITE_WGUI_CLIENTS,
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import { AppData } from "@/src/data/app-data";
import type { BUN_SQLITE_WGUI_CLIENTS, BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
import BunSQLite from "@moduletrace/bun-sqlite";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import type { TableType, User } from "@/src/types";
@@ -29,7 +24,7 @@ export default async function updateWireguardHostPublicIP({
public_ip_address,
user,
}: Params): Promise<APIResponseObject> {
const final_host_id = Number(host_id || AppData["WireguardHostID"]);
const final_host_id = Number(host_id || 0);
const ip = (public_ip_address || "").trim();
if (!ip || !IP_V4_REGEX.test(ip)) {
@@ -42,65 +37,43 @@ export default async function updateWireguardHostPublicIP({
let host: BUN_SQLITE_WGUI_HOSTS | undefined;
try {
if (final_host_id == AppData["WireguardHostID"]) {
const update_variables = await BunSQLite.insert<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
data: [
{
key: "main_host_public_ip_address",
value: ip,
},
],
update_on_duplicate: true,
});
const host_res = await BunSQLite.select<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
targetId: final_host_id,
});
// console.log("update_variables", update_variables);
host = host_res.singleRes || undefined;
// if (!update_variables.success) {
// throw new Error(`Couldn't update host public IP variable`);
// }
} else {
const host_res = await BunSQLite.select<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
targetId: final_host_id,
});
host = host_res.singleRes || undefined;
if (!host) {
return {
success: false,
msg: `Host record not found`,
};
}
const update_host = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
data: [
{
id: host.id,
user_id: user.id,
public_ip_address: ip,
},
],
update_on_duplicate: true,
});
if (!update_host.success) {
throw new Error(`Couldn't update host record`);
}
host.public_ip_address = ip;
if (!host) {
return {
success: false,
msg: `Host record not found`,
};
}
const update_host = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
data: [
{
id: host.id,
user_id: user.id,
public_ip_address: ip,
},
],
update_on_duplicate: true,
});
if (!update_host.success) {
throw new Error(`Couldn't update host record`);
}
host.public_ip_address = ip;
} catch (error: any) {
return {
success: false,
@@ -1,7 +1,4 @@
import type {
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
import { AppData } from "@/src/data/app-data";
import BunSQLite from "@moduletrace/bun-sqlite";
import type { APIResponseObject } from "@moduletrace/bunext/types";
@@ -20,9 +17,6 @@ type Params = {
/**
* Update the private WireGuard subnet IP of a host
* and regenerate the host config + restart the tunnel.
*
* For the main host (id 0) the value is stored in the
* variables table, otherwise the hosts record is updated.
* @param param0
* @returns
*/
@@ -31,7 +25,7 @@ export default async function updateWireguardHost({
wg_ip_address,
user,
}: Params): Promise<APIResponseObject> {
const final_host_id = Number(host_id || AppData["WireguardHostID"]);
const final_host_id = Number(host_id || AppData["WireguardMainHostID"]);
const ip = (wg_ip_address || "").trim();
if (!ip || !IP_V4_REGEX.test(ip)) {
@@ -45,37 +39,24 @@ export default async function updateWireguardHost({
let current_wg_ip: string | undefined;
try {
if (final_host_id == AppData["WireguardHostID"]) {
const variables_res = await BunSQLite.select<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
});
const host_res = await BunSQLite.select<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
targetId: final_host_id,
});
current_wg_ip = variables_res.payload?.find(
(v) => v.key == "main_host_wg_ip_address",
)?.value;
} else {
const host_res = await BunSQLite.select<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
targetId: final_host_id,
});
host = host_res.singleRes || undefined;
host = host_res.singleRes || undefined;
if (!host) {
return {
success: false,
msg: `Host record not found`,
};
}
current_wg_ip = host.wg_ip_address || undefined;
if (!host) {
return {
success: false,
msg: `Host record not found`,
};
}
current_wg_ip = host.wg_ip_address || undefined;
} catch (error: any) {
return {
success: false,
@@ -97,53 +78,27 @@ export default async function updateWireguardHost({
}
try {
if (final_host_id == AppData["WireguardHostID"]) {
const update_variables = await BunSQLite.insert<
BUN_SQLITE_WGUI_VARIABLES,
TableType
>({
table: "variables",
data: [
{
key: "main_host_wg_ip_address",
value: ip,
},
],
update_on_duplicate: true,
});
const update_host = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
data: [
{
id: host?.id,
user_id: user.id,
wg_ip_address: ip,
},
],
update_on_duplicate: true,
});
if (!update_variables.success) {
throw new Error(`Couldn't update host variables`);
}
if (!update_host.success) {
throw new Error(`Couldn't update host record`);
}
host = {
id: AppData["WireguardHostID"],
user_id: user.id,
wg_ip_address: ip,
};
} else {
const update_host = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
data: [
{
id: host?.id,
user_id: user.id,
wg_ip_address: ip,
},
],
update_on_duplicate: true,
});
if (!update_host.success) {
throw new Error(`Couldn't update host record`);
}
if (host) {
host.wg_ip_address = ip;
}
if (host) {
host.wg_ip_address = ip;
}
} catch (error: any) {
return {
@@ -178,4 +133,4 @@ export default async function updateWireguardHost({
success: true,
msg: `Host IP updated to ${ip}`,
};
}
}