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"; import { execSync } from "node:child_process"; import path from "node:path"; import grabHostPublicIPAddress from "./grab-host-public-ip-address"; import setupWireguardHost from "./setup-wireguard-host"; import type { APIResponseObject } from "@moduletrace/bunext/types"; import BunSQLite from "@moduletrace/bun-sqlite"; import type { TableType } from "@/src/types"; const { WGUI_LIB_CLIENTS_CONFIGS_DIR, WIREGUARD_HOST_CONFIG_DIR, WIREGUARD_PRIVATE_KEY_FILE_NAME, WIREGUARD_PUBLIC_KEY_FILE_NAME, WGUI_LIB_KEYS_DIR, WIREGUARD_CLIENT_CONFIG_FILE_NAME, } = grabDirNames(); type Params = { client: BUN_SQLITE_WGUI_CLIENTS; host?: BUN_SQLITE_WGUI_HOSTS; variables?: BUN_SQLITE_WGUI_VARIABLES[]; }; /** * Function to setup a wireguard client. This * function will eventually call the setupWireguardHost * function afterwards to update it * @param param0 * @returns */ export default async function setupWireguardClient({ client, host, variables, }: Params): Promise { const host_id = host?.id || AppData["WireguardHostID"]; const CLIENT_WG_IP = client?.wg_ip_address; if (!CLIENT_WG_IP) { return { success: false, msg: `No Client Private IP address provided`, }; } const HOST_WG_IP = host?.wg_ip_address || variables?.find((v) => v.key == "main_host_wg_ip_address")?.value; if (!HOST_WG_IP) { return { success: false, msg: `No Host Private IP address provided`, }; } const CLIENT_DIR = path.join(WGUI_LIB_CLIENTS_CONFIGS_DIR, `${client.id}`); const CLIENT_PRIVATE_KEY_FILE = path.join( CLIENT_DIR, WIREGUARD_PRIVATE_KEY_FILE_NAME, ); const CLIENT_PUBLIC_KEY_FILE = path.join( CLIENT_DIR, WIREGUARD_PUBLIC_KEY_FILE_NAME, ); const CLIENT_CONFIG_FILE = path.join( CLIENT_DIR, WIREGUARD_CLIENT_CONFIG_FILE_NAME, ); let pre_sh = ``; pre_sh += `mkdir -p ${CLIENT_DIR}\n`; pre_sh += `if [ ! -f ${CLIENT_PRIVATE_KEY_FILE} ]; then\n`; pre_sh += ` wg genkey | tee ${CLIENT_PRIVATE_KEY_FILE} | wg pubkey > ${CLIENT_PUBLIC_KEY_FILE}\n`; pre_sh += `fi\n`; try { const exec_pre_setup = execSync(pre_sh, { encoding: "utf-8" }); } catch (error: any) { return { success: false, msg: error.message, }; } try { const CLIENT_PRIVATE_KEY = client?.private_key || execSync(`cat ${CLIENT_PRIVATE_KEY_FILE}`, { encoding: "utf-8", }).trim(); if (CLIENT_PRIVATE_KEY && !client.private_key && client.id) { await BunSQLite.update({ data: { private_key: CLIENT_PRIVATE_KEY }, table: "clients", targetId: client.id, }); } const CLIENT_PUBLIC_KEY = client?.public_key || execSync(`cat ${CLIENT_PUBLIC_KEY_FILE}`, { encoding: "utf-8", }).trim(); if (CLIENT_PUBLIC_KEY && !client.public_key && client.id) { await BunSQLite.update({ data: { public_key: CLIENT_PUBLIC_KEY }, table: "clients", targetId: client.id, }); } const HOST_PUBLIC_KEY = host?.public_key || execSync( `cat ${path.join( WIREGUARD_HOST_CONFIG_DIR, WIREGUARD_PUBLIC_KEY_FILE_NAME, )}`, { encoding: "utf-8" }, ).trim(); const ALLOWED_IPS = client?.allowed_ips || `0.0.0.0/0`; const PUBLIC_IP_ADDRESS = (await grabHostPublicIPAddress()) || client?.public_ip_address || HOST_WG_IP; const sh = ` cd ${CLIENT_DIR} cat > ${WIREGUARD_CLIENT_CONFIG_FILE_NAME} << EOF [Interface] Address = ${CLIENT_WG_IP}/32 PrivateKey = ${CLIENT_PRIVATE_KEY} DNS = 1.1.1.1 [Peer] PublicKey = ${HOST_PUBLIC_KEY} Endpoint = ${PUBLIC_IP_ADDRESS}:51820 AllowedIPs = ${ALLOWED_IPS} EOF `; const exec = execSync(sh, { encoding: "utf-8" }); const CLIENT_CONFIG = execSync(`cat ${CLIENT_CONFIG_FILE}`, { encoding: "utf-8", }); const host_setup_res = await setupWireguardHost({ host, variables }); if (!host_setup_res.success) { return { success: false, msg: `Client config created but Host update failed: ${host_setup_res.msg}`, }; } return { success: true, msg: `Client ${client.name} setup complete`, stringRes: CLIENT_CONFIG, }; } catch (error: any) { return { success: false, msg: error.message, }; } }