Updates
This commit is contained in:
@@ -76,7 +76,9 @@ export default function ClientRow({ client, rules }: Props) {
|
|||||||
{client.wg_ip_address || "—"}
|
{client.wg_ip_address || "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-[9px] tabular text-[13px] text-foreground-light/45 dark:text-foreground-dark/45 whitespace-nowrap">
|
<td className="px-4 py-[9px] tabular text-[13px] text-foreground-light/45 dark:text-foreground-dark/45 whitespace-nowrap">
|
||||||
{client.allowed_ips || "—"}
|
{client.allow_all_ips
|
||||||
|
? "0.0.0.0/0, ::/0"
|
||||||
|
: client.allowed_ips || "—"}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-[9px] whitespace-nowrap">
|
<td className="px-4 py-[9px] whitespace-nowrap">
|
||||||
<Span
|
<Span
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ export default async function setupWireguardHost({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const is_ip_available = is_update_after_client_setup
|
const is_ip_available = is_update_after_client_setup
|
||||||
|
? { success: true }
|
||||||
|
: host?.wg_ip_address
|
||||||
? { success: true }
|
? { success: true }
|
||||||
: await checkPrivateIPAvailability({
|
: await checkPrivateIPAvailability({
|
||||||
ip_address: HOST_WG_IP,
|
ip_address: HOST_WG_IP,
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import Stack from "@/src/components/twui/layout/Stack";
|
|||||||
import Span from "@/src/components/twui/layout/Span";
|
import Span from "@/src/components/twui/layout/Span";
|
||||||
import AdminCard from "@/src/components/general/admin-card";
|
import AdminCard from "@/src/components/general/admin-card";
|
||||||
import ClientRow from "@/src/components/general/client-row";
|
import ClientRow from "@/src/components/general/client-row";
|
||||||
import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db";
|
import type {
|
||||||
|
BUN_SQLITE_WGUI_CLIENT_RULES,
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
} from "@/db/types/db";
|
||||||
|
import { useAdminCrudGet } from "@/src/hooks/use-admin-crud-get";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
clients?: BUN_SQLITE_WGUI_CLIENTS[];
|
clients?: BUN_SQLITE_WGUI_CLIENTS[];
|
||||||
@@ -23,6 +28,34 @@ const RECENT_LIMIT = 8;
|
|||||||
export default function PeersTableSection({ clients }: Props) {
|
export default function PeersTableSection({ clients }: Props) {
|
||||||
const recent = (clients || []).slice(0, RECENT_LIMIT);
|
const recent = (clients || []).slice(0, RECENT_LIMIT);
|
||||||
|
|
||||||
|
const { res: client_rules } = useAdminCrudGet<BUN_SQLITE_WGUI_CLIENT_RULES>(
|
||||||
|
{
|
||||||
|
table: "client_rules",
|
||||||
|
sql_query: {
|
||||||
|
limit: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const rules_by_client_id = useMemo(() => {
|
||||||
|
const map = new Map<number, BUN_SQLITE_WGUI_CLIENT_RULES[]>();
|
||||||
|
|
||||||
|
for (let i = 0; i < (client_rules || []).length; i++) {
|
||||||
|
const rule = client_rules?.[i];
|
||||||
|
const client_id = Number(rule?.client_id);
|
||||||
|
|
||||||
|
if (!rule || !client_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = map.get(client_id) || [];
|
||||||
|
existing.push(rule);
|
||||||
|
map.set(client_id, existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}, [client_rules]);
|
||||||
|
|
||||||
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">
|
<Row className="justify-between gap-3 px-5 h-12 flex-wrap">
|
||||||
@@ -40,24 +73,40 @@ export default function PeersTableSection({ clients }: Props) {
|
|||||||
{recent.length ? (
|
{recent.length ? (
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<table className="w-full min-w-[860px]">
|
<table className="w-full min-w-[860px]">
|
||||||
<thead>
|
<thead className="w-full">
|
||||||
<tr className="border-y border-slate-200 dark:border-white/10 bg-foreground-light/[0.02] dark:bg-foreground-dark/[0.03]">
|
<tr className="border-y border-slate-200 dark:border-white/10 bg-foreground-light/[0.02] dark:bg-foreground-dark/[0.03] w-full">
|
||||||
<th className={thClass}>Client</th>
|
<th className={thClass}>Client</th>
|
||||||
|
<th className={thClass}>Host</th>
|
||||||
<th className={thClass}>Tunnel IP</th>
|
<th className={thClass}>Tunnel IP</th>
|
||||||
<th className={thClass}>Allowed IPs</th>
|
<th className={thClass}>Allowed IPs</th>
|
||||||
|
<th className={thClass}>Access List</th>
|
||||||
<th className={thClass}>Public key</th>
|
<th className={thClass}>Public key</th>
|
||||||
<th className={thRightClass}>Created</th>
|
<th className={thRightClass}>Created</th>
|
||||||
|
<th className={thRightClass}>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{recent.map((client) => (
|
{recent.map((client) => (
|
||||||
<ClientRow key={client.id} client={client} />
|
<ClientRow
|
||||||
|
key={client.id}
|
||||||
|
client={client}
|
||||||
|
rules={
|
||||||
|
client.id
|
||||||
|
? rules_by_client_id.get(
|
||||||
|
Number(client.id),
|
||||||
|
)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Stack center className="w-full justify-center py-14 px-6 text-center gap-1">
|
<Stack
|
||||||
|
center
|
||||||
|
className="w-full justify-center py-14 px-6 text-center gap-1"
|
||||||
|
>
|
||||||
<Span className="text-[13.5px] font-medium text-foreground-light/50 dark:text-foreground-dark/50">
|
<Span className="text-[13.5px] font-medium text-foreground-light/50 dark:text-foreground-dark/50">
|
||||||
No clients yet
|
No clients yet
|
||||||
</Span>
|
</Span>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||||
|
import getInterfaceLocalIP from "@/src/functions/backend/setup/get-interface-local-ip";
|
||||||
|
import grabHostNetworkInterfaces from "@/src/functions/backend/setup/grab-host-network-interfaces";
|
||||||
|
import grabHostPublicIPAddress from "@/src/functions/backend/setup/grab-host-public-ip-address";
|
||||||
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
||||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||||
@@ -8,19 +11,23 @@ const server: BunextPageServerFn<PagePropsType> = async ({ query }) => {
|
|||||||
|
|
||||||
const host_id = Number(page_query.host_id || 0);
|
const host_id = Number(page_query.host_id || 0);
|
||||||
|
|
||||||
const host_res = await BunSQLite.select<
|
const host_res = await BunSQLite.select<BUN_SQLITE_WGUI_HOSTS, TableType>({
|
||||||
BUN_SQLITE_WGUI_HOSTS,
|
|
||||||
TableType
|
|
||||||
>({
|
|
||||||
table: "hosts",
|
table: "hosts",
|
||||||
targetId: host_id,
|
targetId: host_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const host = host_res.singleRes || null;
|
const host = host_res.singleRes || null;
|
||||||
|
|
||||||
|
const network_interfaces = await grabHostNetworkInterfaces();
|
||||||
|
const local_ip = host?.interface
|
||||||
|
? await getInterfaceLocalIP(host?.interface)
|
||||||
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
host,
|
host,
|
||||||
|
network_interfaces,
|
||||||
|
is_local_ip: local_ip == host?.public_ip_address,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { ArrowLeft } from "lucide-react";
|
|||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { AppContext } from "@/src/pages/__root";
|
import { AppContext } from "@/src/pages/__root";
|
||||||
import EditHostFormSection from "./(sections)/edit-host-form-section";
|
import EditHostFormSection from "./(sections)/edit-host-form-section";
|
||||||
|
import AddHostForm from "../../add/(partials)/add-host-form/add-host-form";
|
||||||
|
import _ from "lodash";
|
||||||
|
import type { BUN_SQLITE_WGUI_HOSTS_JOIN } from "@/src/types/sql-joins";
|
||||||
|
|
||||||
export default function AdminEditHostPage() {
|
export default function AdminEditHostPage() {
|
||||||
const { pageProps, query } = useContext(AppContext);
|
const { pageProps, query } = useContext(AppContext);
|
||||||
@@ -40,7 +43,13 @@ export default function AdminEditHostPage() {
|
|||||||
|
|
||||||
<Stack className="w-full px-6 pb-8 gap-5 items-stretch">
|
<Stack className="w-full px-6 pb-8 gap-5 items-stretch">
|
||||||
{pageProps?.host ? (
|
{pageProps?.host ? (
|
||||||
<EditHostFormSection />
|
<AddHostForm
|
||||||
|
existing_host={_.pick<
|
||||||
|
BUN_SQLITE_WGUI_HOSTS_JOIN,
|
||||||
|
keyof BUN_SQLITE_WGUI_HOSTS_JOIN
|
||||||
|
>(pageProps.host, ["name", "short_description"])}
|
||||||
|
existing_host_full={pageProps.host}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyContent title="Host not found" />
|
<EmptyContent title="Host not found" />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import type { BUN_SQLITE_WGUI_CLIENTS, BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
import type {
|
||||||
|
BUN_SQLITE_WGUI_CLIENTS,
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
} from "@/db/types/db";
|
||||||
import grabHostDirnames from "@/src/functions/backend/setup/grab-host-dir-names";
|
import grabHostDirnames from "@/src/functions/backend/setup/grab-host-dir-names";
|
||||||
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
import type { PagePropsType, PageQueryObject, TableType } from "@/src/types";
|
||||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
|
||||||
|
|
||||||
const server: BunextPageServerFn<PagePropsType> = async ({
|
const server: BunextPageServerFn<PagePropsType> = async ({ query }) => {
|
||||||
req,
|
|
||||||
url,
|
|
||||||
query,
|
|
||||||
}) => {
|
|
||||||
const page_query = query as PageQueryObject;
|
const page_query = query as PageQueryObject;
|
||||||
|
|
||||||
const host_record_res = await BunSQLite.select<
|
const host_record_res = await BunSQLite.select<
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default function AdminSingleHostPage() {
|
|||||||
color="primary"
|
color="primary"
|
||||||
href={`/admin/hosts/${host_id}/clients`}
|
href={`/admin/hosts/${host_id}/clients`}
|
||||||
>
|
>
|
||||||
View Clients
|
Clients
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
title="Add Client"
|
title="Add Client"
|
||||||
|
|||||||
@@ -10,19 +10,31 @@ export default async function submitAddHostForm({
|
|||||||
form,
|
form,
|
||||||
app_context,
|
app_context,
|
||||||
clearLocalForm,
|
clearLocalForm,
|
||||||
|
existing_full,
|
||||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>>) {
|
}: ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>>) {
|
||||||
try {
|
try {
|
||||||
if (!window.confirm("Create this new host?")) {
|
const confirm_msg = existing_full?.id
|
||||||
|
? `Update this host?`
|
||||||
|
: `Create this new host?`;
|
||||||
|
|
||||||
|
if (!window.confirm(confirm_msg)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const res = await fetchApi<ApiReqParams, APIResponseObject>(
|
const res = await fetchApi<ApiReqParams, APIResponseObject>(
|
||||||
`/api/admin/add-host`,
|
existing_full?.id
|
||||||
|
? `/api/admin/update-host`
|
||||||
|
: `/api/admin/add-host`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: {
|
body: existing_full?.id
|
||||||
|
? {
|
||||||
|
host_id: existing_full.id,
|
||||||
|
update_data: form,
|
||||||
|
}
|
||||||
|
: {
|
||||||
wg_ip_address: form.wg_ip_address || "",
|
wg_ip_address: form.wg_ip_address || "",
|
||||||
public_ip_address: form.public_ip_address || "",
|
public_ip_address: form.public_ip_address || "",
|
||||||
interface: form.interface || "",
|
interface: form.interface || "",
|
||||||
@@ -37,9 +49,14 @@ export default async function submitAddHostForm({
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const host_id =
|
||||||
|
typeof existing_full?.id == "number"
|
||||||
|
? existing_full.id
|
||||||
|
: res.numberRes;
|
||||||
|
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
clearLocalForm();
|
clearLocalForm();
|
||||||
window.location.pathname = `/admin/hosts/${res.numberRes}`;
|
window.location.pathname = `/admin/hosts/${host_id}`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type Props = ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>> & {
|
|||||||
export default function AddHostFormAction({
|
export default function AddHostFormAction({
|
||||||
status,
|
status,
|
||||||
ipStatus,
|
ipStatus,
|
||||||
|
existing_full,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
if (status?.error) {
|
if (status?.error) {
|
||||||
return null;
|
return null;
|
||||||
@@ -19,9 +20,9 @@ export default function AddHostFormAction({
|
|||||||
<Button
|
<Button
|
||||||
title="Create Host"
|
title="Create Host"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={ipStatus !== "available"}
|
disabled={existing_full?.id ? false : ipStatus !== "available"}
|
||||||
>
|
>
|
||||||
Create Host
|
{existing_full?.id ? "Update Host" : "Create Host"}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||||
|
import Input from "@/src/components/twui/form/Input";
|
||||||
import Select from "@/src/components/twui/form/Select";
|
import Select from "@/src/components/twui/form/Select";
|
||||||
import Stack from "@/src/components/twui/layout/Stack";
|
import Stack from "@/src/components/twui/layout/Stack";
|
||||||
import useFormInit from "@/src/hooks/use-form-init";
|
import useFormInit from "@/src/hooks/use-form-init";
|
||||||
@@ -9,9 +10,21 @@ export default function AddHostFormInterface({
|
|||||||
form,
|
form,
|
||||||
setForm,
|
setForm,
|
||||||
app_context,
|
app_context,
|
||||||
|
existing_full,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const interfaces = app_context.pageProps?.network_interfaces || [];
|
const interfaces = app_context.pageProps?.network_interfaces || [];
|
||||||
|
|
||||||
|
if (existing_full?.id) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
value={existing_full.interface || "N/A"}
|
||||||
|
title="Network Interface"
|
||||||
|
readOnly
|
||||||
|
showLabel
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className="w-full gap-2 items-stretch">
|
<Stack className="w-full gap-2 items-stretch">
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@@ -12,9 +12,24 @@ import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
|||||||
|
|
||||||
type Props = ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>>;
|
type Props = ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>>;
|
||||||
|
|
||||||
export default function AddHostFormListenPort({ form, setForm }: Props) {
|
export default function AddHostFormListenPort({
|
||||||
|
form,
|
||||||
|
setForm,
|
||||||
|
existing_full,
|
||||||
|
}: Props) {
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
|
|
||||||
|
if (existing_full?.id) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
value={existing_full.listen_port || "N/A"}
|
||||||
|
title="Listen Port"
|
||||||
|
readOnly
|
||||||
|
showLabel
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function handleGrabNext() {
|
async function handleGrabNext() {
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||||
import Input from "@/src/components/twui/form/Input";
|
import Input from "@/src/components/twui/form/Input";
|
||||||
import Stack from "@/src/components/twui/layout/Stack";
|
import Stack from "@/src/components/twui/layout/Stack";
|
||||||
import Row from "@/src/components/twui/layout/Row";
|
|
||||||
import Span from "@/src/components/twui/layout/Span";
|
|
||||||
import Toggle from "@/src/components/twui/elements/Toggle";
|
|
||||||
import useFormInit from "@/src/hooks/use-form-init";
|
import useFormInit from "@/src/hooks/use-form-init";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import fetchApi from "@/src/components/twui/utils/fetch/fetchApi";
|
import fetchApi from "@/src/components/twui/utils/fetch/fetchApi";
|
||||||
@@ -16,10 +13,17 @@ import LoadingOverlay from "@/src/components/twui/elements/LoadingOverlay";
|
|||||||
|
|
||||||
type Props = ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>>;
|
type Props = ReturnType<typeof useFormInit<BUN_SQLITE_WGUI_HOSTS>>;
|
||||||
|
|
||||||
export default function AddHostFormPublicIP({ form, setForm }: Props) {
|
export default function AddHostFormPublicIP({
|
||||||
|
form,
|
||||||
|
setForm,
|
||||||
|
app_context,
|
||||||
|
existing_full,
|
||||||
|
}: Props) {
|
||||||
const [useLocalIP, setUseLocalIP] = useState(false);
|
const [useLocalIP, setUseLocalIP] = useState(false);
|
||||||
|
|
||||||
const { loading, setLoading } = useStatus({ initialLoading: true });
|
const { loading, setLoading } = useStatus({
|
||||||
|
initialLoading: existing_full?.id ? false : true,
|
||||||
|
});
|
||||||
|
|
||||||
function fetchIP(iface: string, local: boolean) {
|
function fetchIP(iface: string, local: boolean) {
|
||||||
if (!iface) return;
|
if (!iface) return;
|
||||||
@@ -53,6 +57,17 @@ export default function AddHostFormPublicIP({ form, setForm }: Props) {
|
|||||||
fetchIP(form.interface, useLocalIP);
|
fetchIP(form.interface, useLocalIP);
|
||||||
}, [form.interface, useLocalIP]);
|
}, [form.interface, useLocalIP]);
|
||||||
|
|
||||||
|
if (existing_full?.id) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
value={existing_full.public_ip_address || "N/A"}
|
||||||
|
title="IP Address"
|
||||||
|
readOnly
|
||||||
|
showLabel
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className={twMerge("w-full gap-2 relative")}>
|
<Stack className={twMerge("w-full gap-2 relative")}>
|
||||||
{loading ? <LoadingOverlay /> : null}
|
{loading ? <LoadingOverlay /> : null}
|
||||||
@@ -76,7 +91,9 @@ export default function AddHostFormPublicIP({ form, setForm }: Props) {
|
|||||||
label={
|
label={
|
||||||
<span className="text-base opacity-80">Use Local IP?</span>
|
<span className="text-base opacity-80">Use Local IP?</span>
|
||||||
}
|
}
|
||||||
defaultChecked={useLocalIP}
|
defaultChecked={
|
||||||
|
useLocalIP || Boolean(app_context.pageProps?.is_local_ip)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import GrabNextSubnetButton from "@/src/components/general/grab-next-subnet-butt
|
|||||||
import HostWgIpField, {
|
import HostWgIpField, {
|
||||||
type HostWgIpFieldStatus,
|
type HostWgIpFieldStatus,
|
||||||
} from "@/src/components/general/host-wg-ip-field";
|
} from "@/src/components/general/host-wg-ip-field";
|
||||||
|
import Input from "@/src/components/twui/form/Input";
|
||||||
import Stack from "@/src/components/twui/layout/Stack";
|
import Stack from "@/src/components/twui/layout/Stack";
|
||||||
import useFormInit from "@/src/hooks/use-form-init";
|
import useFormInit from "@/src/hooks/use-form-init";
|
||||||
|
|
||||||
@@ -14,6 +15,17 @@ export default function AddHostFormWgIpAddress({
|
|||||||
setIpStatus,
|
setIpStatus,
|
||||||
...props
|
...props
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
if (props.existing_full?.wg_ip_address) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
placeholder="WG IP address"
|
||||||
|
value={props.existing_full.wg_ip_address}
|
||||||
|
readOnly
|
||||||
|
showLabel
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className="w-full gap-2">
|
<Stack className="w-full gap-2">
|
||||||
<HostWgIpField
|
<HostWgIpField
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import useFormInit from "@/src/hooks/use-form-init";
|
|||||||
import { AppData } from "@/src/data/app-data";
|
import { AppData } from "@/src/data/app-data";
|
||||||
import submitAddHostForm from "../../(functions)/submit-add-host-form";
|
import submitAddHostForm from "../../(functions)/submit-add-host-form";
|
||||||
import AddHostFormAction from "./add-host-form-action";
|
import AddHostFormAction from "./add-host-form-action";
|
||||||
import AddHostFormSubnet from "./add-host-form-subnet";
|
|
||||||
import AddHostFormWgIpAddress from "./add-host-form-wg-ip-address";
|
import AddHostFormWgIpAddress from "./add-host-form-wg-ip-address";
|
||||||
import AddHostFormPublicIP from "./add-host-form-public-ip";
|
import AddHostFormPublicIP from "./add-host-form-public-ip";
|
||||||
import AddHostFormInterface from "./add-host-form-interface";
|
import AddHostFormInterface from "./add-host-form-interface";
|
||||||
@@ -18,7 +17,15 @@ import AddHostFormListenPort from "./add-host-form-listen-port";
|
|||||||
import LoadingRectangleBlock from "@/src/components/twui/layout/LoadingRectangleBlock";
|
import LoadingRectangleBlock from "@/src/components/twui/layout/LoadingRectangleBlock";
|
||||||
import type { HostWgIpFieldStatus } from "@/src/components/general/host-wg-ip-field";
|
import type { HostWgIpFieldStatus } from "@/src/components/general/host-wg-ip-field";
|
||||||
|
|
||||||
export default function AddHostForm() {
|
type Props = {
|
||||||
|
existing_host?: BUN_SQLITE_WGUI_HOSTS;
|
||||||
|
existing_host_full?: BUN_SQLITE_WGUI_HOSTS;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AddHostForm({
|
||||||
|
existing_host,
|
||||||
|
existing_host_full,
|
||||||
|
}: Props) {
|
||||||
const init = useFormInit<BUN_SQLITE_WGUI_HOSTS>({
|
const init = useFormInit<BUN_SQLITE_WGUI_HOSTS>({
|
||||||
default: {
|
default: {
|
||||||
wg_ip_address: AppData["DefaultPrivateIP"],
|
wg_ip_address: AppData["DefaultPrivateIP"],
|
||||||
@@ -26,6 +33,8 @@ export default function AddHostForm() {
|
|||||||
},
|
},
|
||||||
title: "new_host",
|
title: "new_host",
|
||||||
async before_ready_function(params) {
|
async before_ready_function(params) {
|
||||||
|
if (existing_host_full?.id) return;
|
||||||
|
|
||||||
params.setForm((prev) => ({
|
params.setForm((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
interface:
|
interface:
|
||||||
@@ -38,6 +47,8 @@ export default function AddHostForm() {
|
|||||||
undefined,
|
undefined,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
existing: existing_host,
|
||||||
|
existing_full: existing_host_full,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [ipStatus, setIpStatus] = useState<HostWgIpFieldStatus>("checking");
|
const [ipStatus, setIpStatus] = useState<HostWgIpFieldStatus>("checking");
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db";
|
||||||
|
import checkUserAccess from "@/src/functions/backend/auth/check-user-access";
|
||||||
|
import userAuth from "@/src/functions/backend/auth/user-auth";
|
||||||
|
import createWireguardHost from "@/src/functions/backend/setup/create-wireguard-host";
|
||||||
|
import setupWireguardHost from "@/src/functions/backend/setup/setup-wireguard-host";
|
||||||
|
import type { ApiReqParams, TableType } from "@/src/types";
|
||||||
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||||
|
import type {
|
||||||
|
APIResponseObject,
|
||||||
|
BunextAPIRouteHandler,
|
||||||
|
} from "@moduletrace/bunext/types";
|
||||||
|
|
||||||
|
export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
|
||||||
|
params,
|
||||||
|
) => {
|
||||||
|
const req = params.req;
|
||||||
|
const body = params.body as ApiReqParams;
|
||||||
|
|
||||||
|
if (req.method !== "POST") {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { user, user_types } = await userAuth({ req });
|
||||||
|
|
||||||
|
if (!user?.logged_in_status) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
msg: `Unauthorized`,
|
||||||
|
logoutUser: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const is_super_admin = checkUserAccess({ user_types });
|
||||||
|
|
||||||
|
if (!is_super_admin.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
msg: `Unauthorized`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof body.host_id !== "number") {
|
||||||
|
throw new Error(`Invalid host id`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const host_record_res = await BunSQLite.select<
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
TableType
|
||||||
|
>({
|
||||||
|
table: "hosts",
|
||||||
|
targetId: body.host_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const host = host_record_res.singleRes;
|
||||||
|
|
||||||
|
if (!host?.created_at) {
|
||||||
|
throw new Error(`Couldn't find host record`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!body.update_data) {
|
||||||
|
throw new Error(`No data to update`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const update_host_record = await BunSQLite.update<
|
||||||
|
BUN_SQLITE_WGUI_HOSTS,
|
||||||
|
TableType
|
||||||
|
>({
|
||||||
|
table: "hosts",
|
||||||
|
data: body.update_data,
|
||||||
|
targetId: String(host.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
const update = await setupWireguardHost({
|
||||||
|
host,
|
||||||
|
user,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
msg: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -70,6 +70,7 @@ export type PagePropsType = {
|
|||||||
is_main_host?: boolean | null;
|
is_main_host?: boolean | null;
|
||||||
main_host?: BUN_SQLITE_WGUI_HOSTS | null;
|
main_host?: BUN_SQLITE_WGUI_HOSTS | null;
|
||||||
next_available_client_ip?: string | null;
|
next_available_client_ip?: string | null;
|
||||||
|
is_local_ip?: boolean | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AppContextObject = {
|
export type AppContextObject = {
|
||||||
|
|||||||
Reference in New Issue
Block a user