Initialize client forms
This commit is contained in:
@@ -195,6 +195,10 @@ const schema: BUN_SQLITE_DatabaseSchemaType = {
|
|||||||
fieldName: "user_id",
|
fieldName: "user_id",
|
||||||
dataType: "INTEGER",
|
dataType: "INTEGER",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldName: "public_ip_address",
|
||||||
|
dataType: "TEXT",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldName: "wg_ip_address",
|
fieldName: "wg_ip_address",
|
||||||
dataType: "TEXT",
|
dataType: "TEXT",
|
||||||
|
|||||||
+2
-1
@@ -130,6 +130,7 @@ export type BUN_SQLITE_WGUI_HOSTS = {
|
|||||||
*/
|
*/
|
||||||
updated_at?: number | "";
|
updated_at?: number | "";
|
||||||
user_id?: number | "";
|
user_id?: number | "";
|
||||||
|
public_ip_address?: string;
|
||||||
wg_ip_address?: string;
|
wg_ip_address?: string;
|
||||||
public_key?: string;
|
public_key?: string;
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,7 @@ export type BUN_SQLITE_WGUI_VARIABLES = {
|
|||||||
* The time when the record was updated. (Unix Timestamp)
|
* The time when the record was updated. (Unix Timestamp)
|
||||||
*/
|
*/
|
||||||
updated_at?: number | "";
|
updated_at?: number | "";
|
||||||
key?: "main_host_wg_ip_address" | "main_host_wg_public_key" | "main_host_wg_private_key" | "";
|
key?: "main_host_wg_ip_address" | "main_host_public_ip_address" | "main_host_wg_public_key" | "main_host_wg_private_key" | "";
|
||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function AdminHero({ title, description, buttons }: Props) {
|
export default function AdminHero({ title, description, buttons }: Props) {
|
||||||
const { pageProps } = useContext(AppContext);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<Stack className="w-full items-stretch">
|
<Stack className="w-full items-stretch">
|
||||||
@@ -30,18 +28,6 @@ export default function AdminHero({ title, description, buttons }: Props) {
|
|||||||
description
|
description
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
<Breadcrumbs
|
|
||||||
dividerProps={{
|
|
||||||
className: "-skew-10",
|
|
||||||
}}
|
|
||||||
currentLinkProps={{
|
|
||||||
className:
|
|
||||||
"text-slate-400! pointer-events-none",
|
|
||||||
}}
|
|
||||||
pageUrl={pageProps?.url?.pathname}
|
|
||||||
backButton
|
|
||||||
skipHome
|
|
||||||
/>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
<Row>{buttons}</Row>
|
<Row>{buttons}</Row>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import Span from "../twui/layout/Span";
|
import Span from "../twui/layout/Span";
|
||||||
import Tag from "../twui/elements/Tag";
|
import Tag from "../twui/elements/Tag";
|
||||||
import { AppData } from "@/src/data/app-data";
|
import { AppData } from "@/src/data/app-data";
|
||||||
|
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
button_props?: Omit<ComponentProps<typeof Button>, "title">;
|
button_props?: Omit<ComponentProps<typeof Button>, "title">;
|
||||||
@@ -205,11 +206,18 @@ export default function SetupMainHostButton({ button_props }: Props) {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setStatus(undefined);
|
setStatus(undefined);
|
||||||
|
|
||||||
fetchApi<ApiReqParams>(`/api/admin/setup-main-host`, {
|
fetchApi<ApiReqParams, APIResponseObject>(
|
||||||
|
`/api/admin/setup-main-host`,
|
||||||
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: { ip_address: wgIP },
|
body: { ip_address: wgIP },
|
||||||
})
|
},
|
||||||
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
setStatus({
|
setStatus({
|
||||||
success: res.success,
|
success: res.success,
|
||||||
error: !res.success,
|
error: !res.success,
|
||||||
|
|||||||
@@ -19,4 +19,5 @@ export const AppData = {
|
|||||||
|
|
||||||
WireguardHostID: 0,
|
WireguardHostID: 0,
|
||||||
DefaultPrivateIP: `10.1.0.1`,
|
DefaultPrivateIP: `10.1.0.1`,
|
||||||
|
DefaultWGListenPort: 51820,
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ export const Variables = [
|
|||||||
value: "main_host_wg_ip_address",
|
value: "main_host_wg_ip_address",
|
||||||
description: `Private IP address to use for the main Wireguard host. Eg. 10.1.0.1`,
|
description: `Private IP address to use for the main Wireguard host. Eg. 10.1.0.1`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: `Main Host Public IP Address`,
|
||||||
|
value: "main_host_public_ip_address",
|
||||||
|
description: `Private IP address to use for the main Public host. Eg. 10.1.0.1`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: `Main Host Wireguard Public Key`,
|
title: `Main Host Wireguard Public Key`,
|
||||||
value: "main_host_wg_public_key",
|
value: "main_host_wg_public_key",
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { AppData } from "@/src/data/app-data";
|
||||||
|
import deriveWireguardInterfaceName from "@/src/utils/derive-wireguard-interface-name";
|
||||||
|
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||||
|
import path from "path";
|
||||||
|
import grabDirNames from "@/src/utils/grab-dir-names";
|
||||||
|
|
||||||
|
type Params = {
|
||||||
|
host?: BUN_SQLITE_WGUI_HOSTS;
|
||||||
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
WGUI_LIB_HOSTS_CONFIGS_DIR,
|
||||||
|
WGUI_LIB_HOST_CLIENTS_DIR_NAME,
|
||||||
|
WGUI_LIB_HOST_IPTABLES_DIR_NAME,
|
||||||
|
WIREGUARD_PUBLIC_KEY_FILE_NAME,
|
||||||
|
WIREGUARD_PRIVATE_KEY_FILE_NAME,
|
||||||
|
} = grabDirNames();
|
||||||
|
|
||||||
|
export default function grabHostDirnames({ host }: Params) {
|
||||||
|
const HOST_ID = host?.id || AppData["WireguardHostID"];
|
||||||
|
|
||||||
|
const INTERFACE_NAME = deriveWireguardInterfaceName({ host_id: HOST_ID });
|
||||||
|
|
||||||
|
const HOST_CONFIG_DIR = path.join(
|
||||||
|
WGUI_LIB_HOSTS_CONFIGS_DIR,
|
||||||
|
String(HOST_ID),
|
||||||
|
);
|
||||||
|
|
||||||
|
const HOST_CLIENTS_DIR = path.join(
|
||||||
|
HOST_CONFIG_DIR,
|
||||||
|
WGUI_LIB_HOST_CLIENTS_DIR_NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
const HOST_IPTABLES_DIR = path.join(
|
||||||
|
HOST_CONFIG_DIR,
|
||||||
|
WGUI_LIB_HOST_IPTABLES_DIR_NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
const HOST_CONFIG_FILE = path.join(
|
||||||
|
HOST_CONFIG_DIR,
|
||||||
|
`${INTERFACE_NAME}.conf`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const HOST_PUBLIC_KEY_FILE = path.join(
|
||||||
|
HOST_CONFIG_DIR,
|
||||||
|
WIREGUARD_PUBLIC_KEY_FILE_NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
const HOST_PRIVATE_KEY_FILE = path.join(
|
||||||
|
HOST_CONFIG_DIR,
|
||||||
|
WIREGUARD_PRIVATE_KEY_FILE_NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
const POST_UP_PATH = path.join(HOST_IPTABLES_DIR, `up.sh`);
|
||||||
|
const POST_DOWN_PATH = path.join(HOST_IPTABLES_DIR, `down.sh`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
HOST_ID,
|
||||||
|
HOST_CONFIG_DIR,
|
||||||
|
HOST_CLIENTS_DIR,
|
||||||
|
HOST_IPTABLES_DIR,
|
||||||
|
HOST_CONFIG_FILE,
|
||||||
|
HOST_PUBLIC_KEY_FILE,
|
||||||
|
HOST_PRIVATE_KEY_FILE,
|
||||||
|
INTERFACE_NAME,
|
||||||
|
POST_UP_PATH,
|
||||||
|
POST_DOWN_PATH,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,25 +3,18 @@ import type {
|
|||||||
BUN_SQLITE_WGUI_HOSTS,
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
BUN_SQLITE_WGUI_VARIABLES,
|
BUN_SQLITE_WGUI_VARIABLES,
|
||||||
} from "@/db/types/db";
|
} from "@/db/types/db";
|
||||||
import { AppData } from "@/src/data/app-data";
|
|
||||||
import grabDirNames from "@/src/utils/grab-dir-names";
|
import grabDirNames from "@/src/utils/grab-dir-names";
|
||||||
import deriveWireguardInterfaceName from "@/src/utils/derive-wireguard-interface-name";
|
|
||||||
import { execSync } from "node:child_process";
|
import { execSync } from "node:child_process";
|
||||||
import path from "node:path";
|
|
||||||
import grabHostNetworkInterface from "./grab-host-network-interface";
|
import grabHostNetworkInterface from "./grab-host-network-interface";
|
||||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
import type { TableType, User } from "@/src/types";
|
import type { TableType, User } from "@/src/types";
|
||||||
import checkPrivateIPAvailability from "./check-private-ip-availability";
|
import checkPrivateIPAvailability from "./check-private-ip-availability";
|
||||||
import manageWireguardHost from "./manage-wireguard-host";
|
import manageWireguardHost from "./manage-wireguard-host";
|
||||||
|
import grabHostDirnames from "./grab-host-dir-names";
|
||||||
|
|
||||||
const {
|
const { WIREGUARD_PRIVATE_KEY_FILE_NAME, WIREGUARD_PUBLIC_KEY_FILE_NAME } =
|
||||||
WGUI_LIB_HOSTS_CONFIGS_DIR,
|
grabDirNames();
|
||||||
WIREGUARD_PRIVATE_KEY_FILE_NAME,
|
|
||||||
WIREGUARD_PUBLIC_KEY_FILE_NAME,
|
|
||||||
WGUI_LIB_HOST_CLIENTS_DIR_NAME,
|
|
||||||
WGUI_LIB_HOST_IPTABLES_DIR_NAME,
|
|
||||||
} = grabDirNames();
|
|
||||||
|
|
||||||
type Params = {
|
type Params = {
|
||||||
host?: BUN_SQLITE_WGUI_HOSTS;
|
host?: BUN_SQLITE_WGUI_HOSTS;
|
||||||
@@ -34,29 +27,18 @@ export default async function setupWireguardHost({
|
|||||||
wg_subnet_ip,
|
wg_subnet_ip,
|
||||||
user,
|
user,
|
||||||
}: Params): Promise<APIResponseObject> {
|
}: Params): Promise<APIResponseObject> {
|
||||||
const host_id = host?.id || AppData["WireguardHostID"];
|
const {
|
||||||
|
HOST_CLIENTS_DIR,
|
||||||
const INTERFACE_NAME = deriveWireguardInterfaceName({ host_id });
|
|
||||||
|
|
||||||
const HOST_CONFIG_DIR = path.join(
|
|
||||||
WGUI_LIB_HOSTS_CONFIGS_DIR,
|
|
||||||
String(host_id),
|
|
||||||
);
|
|
||||||
|
|
||||||
const HOST_CLIENTS_DIR = path.join(
|
|
||||||
WGUI_LIB_HOSTS_CONFIGS_DIR,
|
|
||||||
WGUI_LIB_HOST_CLIENTS_DIR_NAME,
|
|
||||||
);
|
|
||||||
|
|
||||||
const HOST_IPTABLES_DIR = path.join(
|
|
||||||
WGUI_LIB_HOSTS_CONFIGS_DIR,
|
|
||||||
WGUI_LIB_HOST_IPTABLES_DIR_NAME,
|
|
||||||
);
|
|
||||||
|
|
||||||
const HOST_CONFIG_FILE = path.join(
|
|
||||||
HOST_CONFIG_DIR,
|
HOST_CONFIG_DIR,
|
||||||
`${INTERFACE_NAME}.conf`,
|
HOST_CONFIG_FILE,
|
||||||
);
|
HOST_ID,
|
||||||
|
HOST_IPTABLES_DIR,
|
||||||
|
HOST_PRIVATE_KEY_FILE,
|
||||||
|
HOST_PUBLIC_KEY_FILE,
|
||||||
|
INTERFACE_NAME,
|
||||||
|
POST_DOWN_PATH,
|
||||||
|
POST_UP_PATH,
|
||||||
|
} = grabHostDirnames({ host });
|
||||||
|
|
||||||
const variables_res = await BunSQLite.select<
|
const variables_res = await BunSQLite.select<
|
||||||
BUN_SQLITE_WGUI_VARIABLES,
|
BUN_SQLITE_WGUI_VARIABLES,
|
||||||
@@ -75,7 +57,7 @@ export default async function setupWireguardHost({
|
|||||||
query: {
|
query: {
|
||||||
query: {
|
query: {
|
||||||
host_id: {
|
host_id: {
|
||||||
value: host_id,
|
value: HOST_ID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -111,6 +93,8 @@ export default async function setupWireguardHost({
|
|||||||
|
|
||||||
pre_sh += `set -e\n`;
|
pre_sh += `set -e\n`;
|
||||||
pre_sh += `mkdir -p ${HOST_CONFIG_DIR}\n`;
|
pre_sh += `mkdir -p ${HOST_CONFIG_DIR}\n`;
|
||||||
|
pre_sh += `mkdir -p ${HOST_CLIENTS_DIR}\n`;
|
||||||
|
pre_sh += `mkdir -p ${HOST_IPTABLES_DIR}\n`;
|
||||||
pre_sh += `cd ${HOST_CONFIG_DIR}\n`;
|
pre_sh += `cd ${HOST_CONFIG_DIR}\n`;
|
||||||
pre_sh += `if [ ! -f ${WIREGUARD_PRIVATE_KEY_FILE_NAME} ]; then\n`;
|
pre_sh += `if [ ! -f ${WIREGUARD_PRIVATE_KEY_FILE_NAME} ]; then\n`;
|
||||||
pre_sh += ` wg genkey | tee ${WIREGUARD_PRIVATE_KEY_FILE_NAME} | wg pubkey > ${WIREGUARD_PUBLIC_KEY_FILE_NAME}\n`;
|
pre_sh += ` wg genkey | tee ${WIREGUARD_PRIVATE_KEY_FILE_NAME} | wg pubkey > ${WIREGUARD_PUBLIC_KEY_FILE_NAME}\n`;
|
||||||
@@ -126,17 +110,15 @@ export default async function setupWireguardHost({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const HOST_PUBLIC_KEY = execSync(
|
const HOST_PUBLIC_KEY = execSync(`cat ${HOST_PUBLIC_KEY_FILE}`, {
|
||||||
`cat ${path.join(HOST_CONFIG_DIR, WIREGUARD_PUBLIC_KEY_FILE_NAME)}`,
|
encoding: "utf-8",
|
||||||
{ encoding: "utf-8" },
|
}).trim();
|
||||||
).trim();
|
|
||||||
|
|
||||||
const HOST_PRIVATE_KEY = execSync(
|
const HOST_PRIVATE_KEY = execSync(`cat ${HOST_PRIVATE_KEY_FILE}`, {
|
||||||
`cat ${path.join(HOST_CONFIG_DIR, WIREGUARD_PRIVATE_KEY_FILE_NAME)}`,
|
encoding: "utf-8",
|
||||||
{ encoding: "utf-8" },
|
}).trim();
|
||||||
).trim();
|
|
||||||
|
|
||||||
if (host_id == 0) {
|
if (HOST_ID == 0) {
|
||||||
const update_variables = await BunSQLite.insert<
|
const update_variables = await BunSQLite.insert<
|
||||||
BUN_SQLITE_WGUI_VARIABLES,
|
BUN_SQLITE_WGUI_VARIABLES,
|
||||||
TableType
|
TableType
|
||||||
@@ -155,12 +137,10 @@ export default async function setupWireguardHost({
|
|||||||
update_on_duplicate: true,
|
update_on_duplicate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("update_variables", update_variables);
|
|
||||||
|
|
||||||
if (!update_variables.success) {
|
if (!update_variables.success) {
|
||||||
throw new Error(`Couldn't update host variables`);
|
throw new Error(`Couldn't update host variables`);
|
||||||
}
|
}
|
||||||
} else if (host_id) {
|
} else if (HOST_ID) {
|
||||||
const update_host = await BunSQLite.insert<
|
const update_host = await BunSQLite.insert<
|
||||||
BUN_SQLITE_WGUI_HOSTS,
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
TableType
|
TableType
|
||||||
@@ -168,7 +148,7 @@ export default async function setupWireguardHost({
|
|||||||
table: "hosts",
|
table: "hosts",
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: host_id,
|
id: HOST_ID,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
wg_ip_address: HOST_WG_IP,
|
wg_ip_address: HOST_WG_IP,
|
||||||
public_key: HOST_PUBLIC_KEY,
|
public_key: HOST_PUBLIC_KEY,
|
||||||
@@ -182,9 +162,6 @@ export default async function setupWireguardHost({
|
|||||||
|
|
||||||
sh += `set -e\n`;
|
sh += `set -e\n`;
|
||||||
|
|
||||||
const POST_UP_PATH = path.join(HOST_IPTABLES_DIR, `up.sh`);
|
|
||||||
const POST_DOWN_PATH = path.join(HOST_IPTABLES_DIR, `down.sh`);
|
|
||||||
|
|
||||||
sh += `cd ${HOST_CONFIG_DIR}\n`;
|
sh += `cd ${HOST_CONFIG_DIR}\n`;
|
||||||
|
|
||||||
sh += `cat > ${POST_UP_PATH} << EOF\n`;
|
sh += `cat > ${POST_UP_PATH} << EOF\n`;
|
||||||
@@ -247,7 +224,7 @@ export default async function setupWireguardHost({
|
|||||||
const exec = execSync(sh, { encoding: "utf-8" });
|
const exec = execSync(sh, { encoding: "utf-8" });
|
||||||
|
|
||||||
const manage_res = manageWireguardHost({
|
const manage_res = manageWireguardHost({
|
||||||
host_id,
|
host_id: HOST_ID,
|
||||||
action: "restart",
|
action: "restart",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ export default function checkIfMainHostIsSet({ variables }: Params) {
|
|||||||
Boolean(
|
Boolean(
|
||||||
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value,
|
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value,
|
||||||
) &&
|
) &&
|
||||||
Boolean(
|
|
||||||
variables?.find((v) => v.key == "main_host_wg_private_key")?.value,
|
|
||||||
) &&
|
|
||||||
Boolean(
|
Boolean(
|
||||||
variables?.find((v) => v.key == "main_host_wg_public_key")?.value,
|
variables?.find((v) => v.key == "main_host_wg_public_key")?.value,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { AppContext } from "@/src/pages/__root";
|
|
||||||
import { ChevronRight } from "lucide-react";
|
|
||||||
import { useContext } from "react";
|
|
||||||
|
|
||||||
const SECTION_TITLES: Record<string, string> = {
|
|
||||||
"/admin": "Dashboard",
|
|
||||||
"/admin/clients": "Clients",
|
|
||||||
"/admin/host": "Host",
|
|
||||||
"/admin/settings": "Settings",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function HeaderPageTitle() {
|
|
||||||
const { pageProps } = useContext(AppContext);
|
|
||||||
const pathname = pageProps?.url?.pathname || "/admin";
|
|
||||||
const title = SECTION_TITLES[pathname] || "Admin";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className="hidden xl:flex items-center gap-2 text-[14px] font-semibold text-foreground-light dark:text-foreground-dark">
|
|
||||||
<span className="font-medium text-foreground-light/50 dark:text-foreground-dark/50">
|
|
||||||
Admin
|
|
||||||
</span>
|
|
||||||
<ChevronRight
|
|
||||||
size={14}
|
|
||||||
className="text-foreground-light/30 dark:text-foreground-dark/30"
|
|
||||||
/>
|
|
||||||
<span>{title}</span>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -2,15 +2,16 @@ import Row from "@/src/components/twui/layout/Row";
|
|||||||
import HeaderUser from "../../main/(partials)/header-user";
|
import HeaderUser from "../../main/(partials)/header-user";
|
||||||
import LogoIcon from "@/src/components/general/logo-icon";
|
import LogoIcon from "@/src/components/general/logo-icon";
|
||||||
import MobileNav from "../(partials)/MobileNav";
|
import MobileNav from "../(partials)/MobileNav";
|
||||||
import HeaderPageTitle from "../(partials)/header-page-title";
|
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
import Breadcrumbs from "@/src/components/twui/elements/Breadcrumbs";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
export default function Header({}: Props) {
|
export default function Header({}: Props) {
|
||||||
/**
|
const { pageProps } = useContext(AppContext);
|
||||||
* Render component
|
|
||||||
*/
|
|
||||||
return (
|
return (
|
||||||
<header className="h-20">
|
<header className="h-20">
|
||||||
<Row
|
<Row
|
||||||
@@ -25,7 +26,17 @@ export default function Header({}: Props) {
|
|||||||
img_props={{ className: "flex xl:hidden" }}
|
img_props={{ className: "flex xl:hidden" }}
|
||||||
/>
|
/>
|
||||||
<MobileNav />
|
<MobileNav />
|
||||||
<HeaderPageTitle />
|
<Breadcrumbs
|
||||||
|
dividerProps={{
|
||||||
|
className: "-skew-10",
|
||||||
|
}}
|
||||||
|
currentLinkProps={{
|
||||||
|
className: "text-slate-400! pointer-events-none",
|
||||||
|
}}
|
||||||
|
pageUrl={pageProps?.url?.pathname}
|
||||||
|
backButton
|
||||||
|
skipHome
|
||||||
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
<Row className="flex-nowrap">
|
<Row className="flex-nowrap">
|
||||||
<HeaderUser />
|
<HeaderUser />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||||
import type { PagePropsType } from "../types";
|
import type { PagePropsType } from "../types";
|
||||||
import userAuth from "../functions/backend/auth/user-auth";
|
import userAuth from "../functions/backend/auth/user-auth";
|
||||||
|
import grabHostDirnames from "../functions/backend/setup/grab-host-dir-names";
|
||||||
|
|
||||||
const server: BunextPageServerFn<PagePropsType> = async ({ req, url }) => {
|
const server: BunextPageServerFn<PagePropsType> = async ({ req, url }) => {
|
||||||
const { user, user_types } = await userAuth({ req });
|
const { user, user_types } = await userAuth({ req });
|
||||||
@@ -27,6 +28,8 @@ const server: BunextPageServerFn<PagePropsType> = async ({ req, url }) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const main_host_dir_names = grabHostDirnames({});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
environment: process.env.NODE_ENV,
|
environment: process.env.NODE_ENV,
|
||||||
@@ -36,6 +39,7 @@ const server: BunextPageServerFn<PagePropsType> = async ({ req, url }) => {
|
|||||||
},
|
},
|
||||||
user,
|
user,
|
||||||
user_types,
|
user_types,
|
||||||
|
main_host_dir_names,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,16 +2,12 @@ import { AppData } from "@/src/data/app-data";
|
|||||||
import deriveWireguardInterfaceName from "@/src/utils/derive-wireguard-interface-name";
|
import deriveWireguardInterfaceName from "@/src/utils/derive-wireguard-interface-name";
|
||||||
import type {
|
import type {
|
||||||
BUN_SQLITE_WGUI_CLIENTS,
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
BUN_SQLITE_WGUI_HOSTS,
|
|
||||||
BUN_SQLITE_WGUI_VARIABLES,
|
BUN_SQLITE_WGUI_VARIABLES,
|
||||||
} from "@/db/types/db";
|
} from "@/db/types/db";
|
||||||
|
import type { BUN_SQLITE_WGUI_HOSTS_JOIN } from "@/src/types/sql-joins";
|
||||||
const LISTEN_PORT = 51820;
|
|
||||||
const IP_TABLES_DIR = `/var/lib/wgui/iptables`;
|
|
||||||
const HOSTS_CONFIG_DIR = `/var/lib/wgui/hosts`;
|
|
||||||
|
|
||||||
type Params = {
|
type Params = {
|
||||||
host?: BUN_SQLITE_WGUI_HOSTS;
|
host?: BUN_SQLITE_WGUI_HOSTS_JOIN;
|
||||||
variables?: BUN_SQLITE_WGUI_VARIABLES[];
|
variables?: BUN_SQLITE_WGUI_VARIABLES[];
|
||||||
clients?: BUN_SQLITE_WGUI_CLIENTS[];
|
clients?: BUN_SQLITE_WGUI_CLIENTS[];
|
||||||
};
|
};
|
||||||
@@ -23,18 +19,42 @@ export default function deriveHostConfig({ host, variables, clients }: Params) {
|
|||||||
host?.wg_ip_address ||
|
host?.wg_ip_address ||
|
||||||
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value;
|
variables?.find((v) => v.key == "main_host_wg_ip_address")?.value;
|
||||||
|
|
||||||
|
const public_key =
|
||||||
|
host?.public_key ||
|
||||||
|
variables?.find((v) => v.key == "main_host_wg_public_key")?.value;
|
||||||
|
|
||||||
const interface_name = deriveWireguardInterfaceName({ host_id });
|
const interface_name = deriveWireguardInterfaceName({ host_id });
|
||||||
|
|
||||||
|
// const HOST_CONFIG_DIR = path.join(
|
||||||
|
// WGUI_LIB_HOSTS_CONFIGS_DIR,
|
||||||
|
// String(host_id),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const HOST_CLIENTS_DIR = path.join(
|
||||||
|
// HOST_CONFIG_DIR,
|
||||||
|
// WGUI_LIB_HOST_CLIENTS_DIR_NAME,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const HOST_IPTABLES_DIR = path.join(
|
||||||
|
// HOST_CONFIG_DIR,
|
||||||
|
// WGUI_LIB_HOST_IPTABLES_DIR_NAME,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const HOST_CONFIG_FILE = path.join(
|
||||||
|
// HOST_CONFIG_DIR,
|
||||||
|
// `${interface_name}.conf`,
|
||||||
|
// );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
host_id,
|
host_id,
|
||||||
interface_name,
|
interface_name,
|
||||||
config_path: `${HOSTS_CONFIG_DIR}/${interface_name}.conf`,
|
config_path: host?.dir_names?.HOST_CONFIG_FILE,
|
||||||
|
|
||||||
address: wg_ip_address ? `${wg_ip_address}/24` : undefined,
|
address: wg_ip_address ? `${wg_ip_address}/24` : undefined,
|
||||||
listen_port: LISTEN_PORT,
|
listen_port: AppData["DefaultWGListenPort"],
|
||||||
post_up: `${IP_TABLES_DIR}/${host_id}-up.sh`,
|
post_up: host?.dir_names?.POST_UP_PATH,
|
||||||
post_down: `${IP_TABLES_DIR}/${host_id}-down.sh`,
|
post_down: host?.dir_names?.POST_DOWN_PATH,
|
||||||
public_key: host?.public_key,
|
public_key: public_key,
|
||||||
client_count:
|
client_count:
|
||||||
clients?.filter((client) => (client.host_id || 0) == host_id)
|
clients?.filter((client) => (client.host_id || 0) == host_id)
|
||||||
.length || 0,
|
.length || 0,
|
||||||
|
|||||||
@@ -13,9 +13,14 @@ import type {
|
|||||||
BUN_SQLITE_WGUI_HOSTS,
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
BUN_SQLITE_WGUI_VARIABLES,
|
BUN_SQLITE_WGUI_VARIABLES,
|
||||||
} from "@/db/types/db";
|
} from "@/db/types/db";
|
||||||
|
import Divider from "@/src/components/twui/layout/Divider";
|
||||||
|
import H3 from "@/src/components/twui/layout/H3";
|
||||||
|
import type { BUN_SQLITE_WGUI_HOSTS_JOIN } from "@/src/types/sql-joins";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
host?: BUN_SQLITE_WGUI_HOSTS;
|
host?: BUN_SQLITE_WGUI_HOSTS_JOIN;
|
||||||
variables?: BUN_SQLITE_WGUI_VARIABLES[];
|
variables?: BUN_SQLITE_WGUI_VARIABLES[];
|
||||||
clients?: BUN_SQLITE_WGUI_CLIENTS[];
|
clients?: BUN_SQLITE_WGUI_CLIENTS[];
|
||||||
};
|
};
|
||||||
@@ -25,12 +30,23 @@ export default function InterfaceConfigSection({
|
|||||||
variables,
|
variables,
|
||||||
clients,
|
clients,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const config = deriveHostConfig({ host, variables, clients });
|
const { pageProps } = useContext(AppContext);
|
||||||
|
|
||||||
|
const final_host: BUN_SQLITE_WGUI_HOSTS_JOIN = host
|
||||||
|
? host
|
||||||
|
: {
|
||||||
|
dir_names: pageProps?.main_host_dir_names || undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = deriveHostConfig({ host: final_host, variables, clients });
|
||||||
|
|
||||||
const rows = [
|
const rows = [
|
||||||
{ keyName: "Address", value: config.address || "—" },
|
{ keyName: "Address", value: config.address || "—" },
|
||||||
{ keyName: "ListenPort", value: String(config.listen_port) },
|
{ keyName: "ListenPort", value: String(config.listen_port) },
|
||||||
,
|
{
|
||||||
|
keyName: "PublicKey",
|
||||||
|
value: config.public_key ? config.public_key : "Not set",
|
||||||
|
},
|
||||||
{ keyName: "PostUp", value: config.post_up },
|
{ keyName: "PostUp", value: config.post_up },
|
||||||
{ keyName: "PostDown", value: config.post_down },
|
{ keyName: "PostDown", value: config.post_down },
|
||||||
];
|
];
|
||||||
@@ -51,11 +67,10 @@ export default function InterfaceConfigSection({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AdminCard className="w-full overflow-hidden">
|
<AdminCard className="w-full overflow-hidden">
|
||||||
<Row className="justify-between gap-3 px-5 h-12 flex-wrap">
|
<Stack className="w-full items-stretch py-4">
|
||||||
|
<Row className="justify-between gap-3 px-5 flex-wrap">
|
||||||
<Stack className="gap-0.5">
|
<Stack className="gap-0.5">
|
||||||
<H2 className="text-[13.5px] font-medium text-foreground-light/60 dark:text-foreground-dark/60 mb-0!">
|
<H3>Interface configuration</H3>
|
||||||
Interface configuration
|
|
||||||
</H2>
|
|
||||||
<P
|
<P
|
||||||
noMargin
|
noMargin
|
||||||
className="font-mono text-[11.5px] text-foreground-light/40 dark:text-foreground-dark/40"
|
className="font-mono text-[11.5px] text-foreground-light/40 dark:text-foreground-dark/40"
|
||||||
@@ -72,12 +87,12 @@ export default function InterfaceConfigSection({
|
|||||||
Copy config
|
Copy config
|
||||||
</AdminButton>
|
</AdminButton>
|
||||||
</Row>
|
</Row>
|
||||||
<div className="border-t border-slate-200 dark:border-white/10">
|
<Divider />
|
||||||
<Span className="px-5 py-3 font-mono text-[12.5px] font-semibold text-secondary dark:text-secondary block">
|
<Span className="px-5 py-3 font-mono text-[12.5px] font-semibold text-secondary dark:text-secondary block">
|
||||||
[Interface]
|
[Interface]
|
||||||
</Span>
|
</Span>
|
||||||
{rows.map((row) => {
|
{rows.map((row) => {
|
||||||
if (!row) return;
|
if (!row?.value) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InterfaceConfigRow
|
<InterfaceConfigRow
|
||||||
@@ -95,7 +110,7 @@ export default function InterfaceConfigSection({
|
|||||||
: "Not generated"}
|
: "Not generated"}
|
||||||
</Span>
|
</Span>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</Stack>
|
||||||
</AdminCard>
|
</AdminCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import Loading from "@/src/components/twui/elements/Loading";
|
||||||
|
import Paper from "@/src/components/twui/elements/Paper";
|
||||||
|
import Center from "@/src/components/twui/layout/Center";
|
||||||
|
import Span from "@/src/components/twui/layout/Span";
|
||||||
|
import Stack from "@/src/components/twui/layout/Stack";
|
||||||
|
import { useAdminCrudGet } from "@/src/hooks/use-admin-crud-get";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
import { useContext } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
host_id: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ClientsList({ host_id }: Props) {
|
||||||
|
const { pageProps } = useContext(AppContext);
|
||||||
|
|
||||||
|
const { res: clients } = useAdminCrudGet({
|
||||||
|
table: "clients",
|
||||||
|
sql_query: {
|
||||||
|
query: {
|
||||||
|
host_id: { value: host_id },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initial_res: pageProps?.clients || undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!clients) {
|
||||||
|
return (
|
||||||
|
<Paper>
|
||||||
|
<Center>
|
||||||
|
<Loading />
|
||||||
|
</Center>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clients[0]) {
|
||||||
|
return (
|
||||||
|
<Paper>
|
||||||
|
<Center>
|
||||||
|
<Span variant="faded">No Clients added yet</Span>
|
||||||
|
</Center>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Stack>{}</Stack>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import H2 from "@/src/components/twui/layout/H2";
|
||||||
|
import Section from "@/src/components/twui/layout/Section";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import ClientsList from "../(partials)/clients-list";
|
||||||
|
|
||||||
|
export default function ClientsListSection() {
|
||||||
|
const { pageProps } = useContext(AppContext);
|
||||||
|
|
||||||
|
const clients = pageProps?.clients || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section>
|
||||||
|
<H2>{clients.length} Clients</H2>
|
||||||
|
<ClientsList host_id={pageProps?.host?.id || 0} />
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db";
|
||||||
|
import Input from "@/src/components/twui/form/Input";
|
||||||
|
import useFormInit from "@/src/hooks/use-form-init";
|
||||||
|
|
||||||
|
export default function AddClientFormTitle({
|
||||||
|
form,
|
||||||
|
setForm,
|
||||||
|
}: ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_CLIENTS>>) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
title="Client Display Name"
|
||||||
|
placeholder="Eg. Pixel 2XL Phone"
|
||||||
|
showLabel
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db";
|
||||||
|
import Form from "@/src/components/twui/form/Form";
|
||||||
|
import Stack from "@/src/components/twui/layout/Stack";
|
||||||
|
import useFormInit from "@/src/hooks/use-form-init";
|
||||||
|
import AddClientFormTitle from "./add-client-form-title";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
existing_client?: BUN_SQLITE_WGUI_CLIENTS;
|
||||||
|
existing_client_full?: BUN_SQLITE_WGUI_CLIENTS;
|
||||||
|
host_id?: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AddClientForm({
|
||||||
|
existing_client,
|
||||||
|
existing_client_full,
|
||||||
|
host_id,
|
||||||
|
}: Props) {
|
||||||
|
const init = useFormInit<BUN_SQLITE_WGUI_CLIENTS>({
|
||||||
|
existing: existing_client,
|
||||||
|
existing_full: existing_client_full,
|
||||||
|
title: "Add Client",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form>
|
||||||
|
<Stack>
|
||||||
|
<AddClientFormTitle {...init} />
|
||||||
|
</Stack>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
import Section from "@/src/components/twui/layout/Section";
|
||||||
|
import AddClientForm from "../(partials)/client-form/add-client-form";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
|
||||||
|
export default function AddClientFormSection() {
|
||||||
|
const { pageProps, query } = useContext(AppContext);
|
||||||
|
|
||||||
|
const host_id = query?.host_id || 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section>
|
||||||
|
<AddClientForm host_id={host_id} />
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||||
|
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
||||||
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
|
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||||
|
|
||||||
|
const server: BunextPageServerFn<PagePropsType> = async ({ query }) => {
|
||||||
|
const page_query = query as PageQueryObject;
|
||||||
|
|
||||||
|
const host_record_res = await BunSQLite.select<
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
TableType
|
||||||
|
>({ table: "hosts", targetId: page_query.host_id });
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
host: host_record_res.singleRes || null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default server;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
|
||||||
|
import AdminHero from "@/src/components/general/admin-hero";
|
||||||
|
import { SiteData } from "@/src/data/site-data";
|
||||||
|
import Divider from "@/src/components/twui/layout/Divider";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
import AddClientFormSection from "./(sections)/add-client-form-section";
|
||||||
|
|
||||||
|
export default function AdminSingleHostPage() {
|
||||||
|
const { pageProps } = useContext(AppContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AdminHero
|
||||||
|
title="Add New Client"
|
||||||
|
description={`Add a new Client to host ${pageProps?.host?.id || 0}`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider className="mb-6" />
|
||||||
|
|
||||||
|
<AddClientFormSection />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const meta: BunextPageModuleMeta = {
|
||||||
|
title: `Add new Client | ${SiteData["SiteName"]}`,
|
||||||
|
description: `WireGuard add new host client page`,
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import type {
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
} from "@/db/types/db";
|
||||||
|
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
||||||
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
|
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||||
|
|
||||||
|
const server: BunextPageServerFn<PagePropsType> = async ({
|
||||||
|
req,
|
||||||
|
url,
|
||||||
|
query,
|
||||||
|
}) => {
|
||||||
|
const page_query = query as PageQueryObject;
|
||||||
|
|
||||||
|
const host_record_res = await BunSQLite.select<
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
TableType
|
||||||
|
>({ table: "hosts", targetId: page_query.host_id });
|
||||||
|
|
||||||
|
const host_clients = await BunSQLite.select<
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
TableType
|
||||||
|
>({
|
||||||
|
table: "clients",
|
||||||
|
query: {
|
||||||
|
query: {
|
||||||
|
host_id: {
|
||||||
|
value: page_query.host_id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
host: host_record_res.singleRes || null,
|
||||||
|
clients: host_clients.payload || null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default server;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
|
||||||
|
import AdminHero from "@/src/components/general/admin-hero";
|
||||||
|
import { SiteData } from "@/src/data/site-data";
|
||||||
|
import Button from "@/src/components/twui/layout/Button";
|
||||||
|
import Divider from "@/src/components/twui/layout/Divider";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AppContext } from "@/src/pages/__root";
|
||||||
|
import ClientsListSection from "./(sections)/clients-list-section";
|
||||||
|
|
||||||
|
export default function AdminSingleHostPage() {
|
||||||
|
const { pageProps } = useContext(AppContext);
|
||||||
|
|
||||||
|
const host_id = pageProps?.host?.id || 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AdminHero
|
||||||
|
title="Clients"
|
||||||
|
description={`Clients for host ${pageProps?.host?.id || 0}`}
|
||||||
|
buttons={
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
title="Add New Client"
|
||||||
|
variant="outlined"
|
||||||
|
href={`/admin/hosts/${host_id}/clients/add-client`}
|
||||||
|
>
|
||||||
|
Add New Client
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider className="mb-6" />
|
||||||
|
|
||||||
|
<ClientsListSection />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const meta: BunextPageModuleMeta = {
|
||||||
|
title: `Host Clients | ${SiteData["SiteName"]}`,
|
||||||
|
description: `WireGuard host clients page`,
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import type {
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
} from "@/db/types/db";
|
||||||
|
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
||||||
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
|
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||||
|
|
||||||
|
const server: BunextPageServerFn<PagePropsType> = async ({
|
||||||
|
req,
|
||||||
|
url,
|
||||||
|
query,
|
||||||
|
}) => {
|
||||||
|
const page_query = query as PageQueryObject;
|
||||||
|
|
||||||
|
const host_record_res = await BunSQLite.select<
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
TableType
|
||||||
|
>({ table: "hosts", targetId: page_query.host_id });
|
||||||
|
|
||||||
|
const host_clients = await BunSQLite.select<
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
TableType
|
||||||
|
>({
|
||||||
|
table: "clients",
|
||||||
|
query: {
|
||||||
|
query: {
|
||||||
|
host_id: {
|
||||||
|
value: page_query.host_id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
host: host_record_res.singleRes || null,
|
||||||
|
clients: host_clients.payload || null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default server;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
|
||||||
|
import AdminHero from "@/src/components/general/admin-hero";
|
||||||
|
import { SiteData } from "@/src/data/site-data";
|
||||||
|
import Button from "@/src/components/twui/layout/Button";
|
||||||
|
import Divider from "@/src/components/twui/layout/Divider";
|
||||||
|
|
||||||
|
export default function AdminSingleHostPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AdminHero
|
||||||
|
title="Host"
|
||||||
|
description="WireGuard server configuration and interface details"
|
||||||
|
buttons={
|
||||||
|
<>
|
||||||
|
<Button title="Add New Host" variant="outlined">
|
||||||
|
Add New Host
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider className="mb-6" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const meta: BunextPageModuleMeta = {
|
||||||
|
title: `Host | ${SiteData["SiteName"]}`,
|
||||||
|
description: `WireGuard host page`,
|
||||||
|
};
|
||||||
@@ -12,6 +12,8 @@ import EmptyContent from "@/src/components/twui/elements/EmptyContent";
|
|||||||
import Span from "@/src/components/twui/layout/Span";
|
import Span from "@/src/components/twui/layout/Span";
|
||||||
import checkIfMainHostIsSet from "@/src/functions/check-if-main-host-is-set";
|
import checkIfMainHostIsSet from "@/src/functions/check-if-main-host-is-set";
|
||||||
import SetupMainHostButton from "@/src/components/general/setup-main-host-button";
|
import SetupMainHostButton from "@/src/components/general/setup-main-host-button";
|
||||||
|
import Row from "@/src/components/twui/layout/Row";
|
||||||
|
import { Plus } from "lucide-react";
|
||||||
|
|
||||||
export default function AdminHostPage() {
|
export default function AdminHostPage() {
|
||||||
const { hosts, variables, clients } = useHostData();
|
const { hosts, variables, clients } = useHostData();
|
||||||
@@ -41,7 +43,9 @@ export default function AdminHostPage() {
|
|||||||
description="WireGuard server configuration and interface details"
|
description="WireGuard server configuration and interface details"
|
||||||
buttons={
|
buttons={
|
||||||
<>
|
<>
|
||||||
<Button title="Add New Host">Add New Host</Button>
|
<Button title="Add New Host" variant="outlined">
|
||||||
|
Add New Host
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -49,7 +53,20 @@ export default function AdminHostPage() {
|
|||||||
<Divider className="mb-6" />
|
<Divider className="mb-6" />
|
||||||
|
|
||||||
<Stack className="w-full px-6 pb-8 gap-5 items-stretch">
|
<Stack className="w-full px-6 pb-8 gap-5 items-stretch">
|
||||||
|
<Row className="w-full justify-between">
|
||||||
<H2>Main Host</H2>
|
<H2>Main Host</H2>
|
||||||
|
|
||||||
|
<Row>
|
||||||
|
<Button
|
||||||
|
title="Add Client"
|
||||||
|
beforeIcon={<Plus />}
|
||||||
|
size="small"
|
||||||
|
href={`/admin/hosts/0/clients/add`}
|
||||||
|
>
|
||||||
|
Add Client
|
||||||
|
</Button>
|
||||||
|
</Row>
|
||||||
|
</Row>
|
||||||
<MainHostStatusSection
|
<MainHostStatusSection
|
||||||
variables={variables}
|
variables={variables}
|
||||||
clients={clients}
|
clients={clients}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type {
|
import type {
|
||||||
BUN_SQLITE_WGUI_ALL_TYPEDEFS,
|
BUN_SQLITE_WGUI_ALL_TYPEDEFS,
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
BUN_SQLITE_WGUI_MEDIA,
|
BUN_SQLITE_WGUI_MEDIA,
|
||||||
BUN_SQLITE_WGUI_USER_TYPES,
|
BUN_SQLITE_WGUI_USER_TYPES,
|
||||||
BUN_SQLITE_WGUI_USERS,
|
BUN_SQLITE_WGUI_USERS,
|
||||||
@@ -12,6 +14,7 @@ import type { BunextPageModuleServerReturnURLObject } from "@moduletrace/bunext/
|
|||||||
import type { BUN_SQLITE_WGUI_USERS_JOIN } from "./sql-joins";
|
import type { BUN_SQLITE_WGUI_USERS_JOIN } from "./sql-joins";
|
||||||
import type { ImageInputToBase64FunctionReturn } from "../components/twui/utils/form/imageInputToBase64";
|
import type { ImageInputToBase64FunctionReturn } from "../components/twui/utils/form/imageInputToBase64";
|
||||||
import type { ServerQueryParam } from "@moduletrace/bun-sqlite/dist/types";
|
import type { ServerQueryParam } from "@moduletrace/bun-sqlite/dist/types";
|
||||||
|
import type grabHostDirnames from "../functions/backend/setup/grab-host-dir-names";
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -33,12 +36,17 @@ export type PagePropsType = {
|
|||||||
user_types?: BUN_SQLITE_WGUI_USER_TYPES[] | null;
|
user_types?: BUN_SQLITE_WGUI_USER_TYPES[] | null;
|
||||||
person?: BUN_SQLITE_WGUI_USERS_JOIN | null;
|
person?: BUN_SQLITE_WGUI_USERS_JOIN | null;
|
||||||
persons?: BUN_SQLITE_WGUI_USERS_JOIN[] | null;
|
persons?: BUN_SQLITE_WGUI_USERS_JOIN[] | null;
|
||||||
|
host?: BUN_SQLITE_WGUI_HOSTS | null;
|
||||||
|
hosts?: BUN_SQLITE_WGUI_HOSTS[] | null;
|
||||||
|
client?: BUN_SQLITE_WGUI_CLIENTS | null;
|
||||||
|
clients?: BUN_SQLITE_WGUI_CLIENTS[] | null;
|
||||||
environment?: string;
|
environment?: string;
|
||||||
envs?: {
|
envs?: {
|
||||||
R2_PUBLIC_DOMAIN?: string;
|
R2_PUBLIC_DOMAIN?: string;
|
||||||
PAYSTACK_PUBLIC_KEY?: string;
|
PAYSTACK_PUBLIC_KEY?: string;
|
||||||
};
|
};
|
||||||
url?: BunextPageModuleServerReturnURLObject;
|
url?: BunextPageModuleServerReturnURLObject;
|
||||||
|
main_host_dir_names?: ReturnType<typeof grabHostDirnames> | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AppContextObject = {
|
export type AppContextObject = {
|
||||||
@@ -283,6 +291,7 @@ export type UserFormObject = BUN_SQLITE_WGUI_USERS & {
|
|||||||
|
|
||||||
export type PageQueryObject = {
|
export type PageQueryObject = {
|
||||||
user_id?: string;
|
user_id?: string;
|
||||||
|
host_id?: string;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
user_type?: UserType;
|
user_type?: UserType;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import type {
|
import type {
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
BUN_SQLITE_WGUI_MEDIA,
|
BUN_SQLITE_WGUI_MEDIA,
|
||||||
BUN_SQLITE_WGUI_MEDIA_PARADIGMS,
|
BUN_SQLITE_WGUI_MEDIA_PARADIGMS,
|
||||||
BUN_SQLITE_WGUI_USERS,
|
BUN_SQLITE_WGUI_USERS,
|
||||||
} from "@/db/types/db";
|
} from "@/db/types/db";
|
||||||
|
import type grabHostDirnames from "../functions/backend/setup/grab-host-dir-names";
|
||||||
|
|
||||||
export type BUN_SQLITE_WGUI_USERS_JOIN = BUN_SQLITE_WGUI_USERS & {
|
export type BUN_SQLITE_WGUI_USERS_JOIN = BUN_SQLITE_WGUI_USERS & {
|
||||||
user_types?: string;
|
user_types?: string;
|
||||||
@@ -20,3 +22,7 @@ export type BUN_SQLITE_WGUI_MEDIA_JOIN = BUN_SQLITE_WGUI_MEDIA & {
|
|||||||
media_paradigms?: string;
|
media_paradigms?: string;
|
||||||
user?: BUN_SQLITE_WGUI_USERS_JOIN;
|
user?: BUN_SQLITE_WGUI_USERS_JOIN;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type BUN_SQLITE_WGUI_HOSTS_JOIN = BUN_SQLITE_WGUI_HOSTS & {
|
||||||
|
dir_names?: ReturnType<typeof grabHostDirnames>;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user