This commit is contained in:
2026-09-20 10:49:14 +01:00
parent 3d122036ce
commit 6e3319b21c
23 changed files with 1331 additions and 223 deletions
@@ -0,0 +1,96 @@
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";
type Params = {
wg_ip_address?: string | null;
user: User;
};
/**
* Create a new WireGuard host record and run the
* full host setup (keys, config, iptables, tunnel).
*
* The host record is rolled back if the setup fails.
* @param param0
* @returns
*/
export default async function createWireguardHost({
wg_ip_address,
user,
}: Params): Promise<APIResponseObject> {
const wg_ip = (wg_ip_address || "").trim();
if (!wg_ip) {
return {
success: false,
msg: `No WireGuard IP address provided`,
};
}
const public_ip_address = await grabHostPublicIPAddress();
try {
const insert_host = await BunSQLite.insert<
BUN_SQLITE_WGUI_HOSTS,
TableType
>({
table: "hosts",
data: [
{
user_id: user.id,
wg_ip_address: wg_ip,
public_ip_address: public_ip_address || undefined,
},
],
});
if (!insert_host.success) {
return {
success: false,
msg: `Could not create the host record: ${insert_host.msg}`,
};
}
const host_id = Number(insert_host.postInsertReturn?.insertId);
const host: BUN_SQLITE_WGUI_HOSTS = {
id: host_id,
user_id: user.id,
wg_ip_address: wg_ip,
public_ip_address: public_ip_address || undefined,
};
const setup_res = await setupWireguardHost({
host,
wg_subnet_ip: wg_ip,
user,
});
if (!setup_res.success) {
await BunSQLite.delete<BUN_SQLITE_WGUI_HOSTS, TableType>({
table: "hosts",
targetId: host_id,
});
return {
success: false,
msg: setup_res.msg,
};
}
return {
success: true,
msg: `New host created`,
numberRes: host_id,
};
} catch (error: any) {
return {
success: false,
msg: error.message,
};
}
}
@@ -0,0 +1,181 @@
import type {
BUN_SQLITE_WGUI_HOSTS,
BUN_SQLITE_WGUI_VARIABLES,
} from "@/db/types/db";
import { AppData } from "@/src/data/app-data";
import BunSQLite from "@moduletrace/bun-sqlite";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import type { TableType, User } from "@/src/types";
import checkPrivateIPAvailability from "./check-private-ip-availability";
import setupWireguardHost from "./setup-wireguard-host";
const IP_V4_REGEX = /^\d{1,3}(\.\d{1,3}){3}$/;
type Params = {
host_id?: string | number | null;
wg_ip_address?: string | null;
user: User;
};
/**
* 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
*/
export default async function updateWireguardHost({
host_id,
wg_ip_address,
user,
}: Params): Promise<APIResponseObject> {
const final_host_id = Number(host_id || AppData["WireguardHostID"]);
const ip = (wg_ip_address || "").trim();
if (!ip || !IP_V4_REGEX.test(ip)) {
return {
success: false,
msg: `Invalid WireGuard IP address provided`,
};
}
let host: BUN_SQLITE_WGUI_HOSTS | undefined;
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",
});
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;
if (!host) {
return {
success: false,
msg: `Host record not found`,
};
}
current_wg_ip = host.wg_ip_address || undefined;
}
} catch (error: any) {
return {
success: false,
msg: error.message,
};
}
if (ip != current_wg_ip) {
const availability_res = await checkPrivateIPAvailability({
ip_address: ip,
});
if (!availability_res.success) {
return {
success: false,
msg: availability_res.msg,
};
}
}
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,
});
if (!update_variables.success) {
throw new Error(`Couldn't update host variables`);
}
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;
}
}
} catch (error: any) {
return {
success: false,
msg: error.message,
};
}
let setup_res: APIResponseObject;
try {
setup_res = await setupWireguardHost({
host,
user,
is_update_after_client_setup: true,
});
} catch (error: any) {
return {
success: false,
msg: error.message,
};
}
if (!setup_res.success) {
return {
success: false,
msg: setup_res.msg,
};
}
return {
success: true,
msg: `Host IP updated to ${ip}`,
};
}