new clients page
This commit is contained in:
parent
bdea663178
commit
5015246a24
@ -67,3 +67,41 @@ export interface OpnsenseWgServers {
|
|||||||
uuid: string;
|
uuid: string;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample response for OPNsense WireGuard clients
|
||||||
|
* ```json
|
||||||
|
* {
|
||||||
|
* "rows": [
|
||||||
|
* {
|
||||||
|
* "uuid": "d99334de-7671-4ca7-9c9b-5f5578acae70",
|
||||||
|
* "enabled": "1",
|
||||||
|
* "name": "Yura-TPX13",
|
||||||
|
* "pubkey": "iJa5JmJbMHNlbEluNwoB2Q8LyrPAfb7S/mluanMcI08=",
|
||||||
|
* "tunneladdress": "fd00::1/112,10.6.0.3/32",
|
||||||
|
* "serveraddress": "",
|
||||||
|
* "serverport": "",
|
||||||
|
* "servers": "wg0"
|
||||||
|
* }
|
||||||
|
* ],
|
||||||
|
* "rowCount": 1,
|
||||||
|
* "total": 10,
|
||||||
|
* "current": 1
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export interface OpnsenseWgClients {
|
||||||
|
rowCount: number;
|
||||||
|
total: number;
|
||||||
|
current: number;
|
||||||
|
rows: {
|
||||||
|
uuid: string;
|
||||||
|
enabled: string;
|
||||||
|
name: string;
|
||||||
|
pubkey: string;
|
||||||
|
tunneladdress: string;
|
||||||
|
serveraddress: string;
|
||||||
|
serverport: string;
|
||||||
|
servers: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
@ -49,7 +49,14 @@ export const wgClients = sqliteTable('wg_clients', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const wgClientsRelations = relations(wgClients, ({ one }) => ({
|
export const wgClientsRelations = relations(wgClients, ({ one }) => ({
|
||||||
ipAllocation: one(ipAllocations),
|
user: one(users, {
|
||||||
|
fields: [wgClients.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
ipAllocation: one(ipAllocations, {
|
||||||
|
fields: [wgClients.id],
|
||||||
|
references: [ipAllocations.clientId],
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type WgClient = typeof wgClients.$inferSelect;
|
export type WgClient = typeof wgClients.$inferSelect;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { users, wgClients } from './schema';
|
import { ipAllocations, users, wgClients } from './schema';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { drizzle } from 'drizzle-orm/libsql';
|
import { drizzle } from 'drizzle-orm/libsql';
|
||||||
@ -7,23 +7,27 @@ import * as schema from '$lib/server/db/schema';
|
|||||||
assert(process.env.DATABASE_URL, 'DATABASE_URL is not set');
|
assert(process.env.DATABASE_URL, 'DATABASE_URL is not set');
|
||||||
const db = drizzle(process.env.DATABASE_URL, { schema });
|
const db = drizzle(process.env.DATABASE_URL, { schema });
|
||||||
|
|
||||||
export async function seed() {
|
async function seed() {
|
||||||
const user = await db.query.users.findFirst({ where: eq(users.username, 'CaZzzer') });
|
const user = await db.query.users.findFirst({ where: eq(users.username, 'CaZzzer') });
|
||||||
assert(user, 'User not found');
|
assert(user, 'User not found');
|
||||||
|
|
||||||
const clients = [
|
const clients: typeof wgClients.$inferInsert[] = [
|
||||||
{
|
{
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
name: 'Client1',
|
name: 'Client1',
|
||||||
publicKey: 'BJ5faPVJsDP4CCxNYilmKnwlQXOtXEOJjqIwb4U/CgM=',
|
publicKey: 'BJ5faPVJsDP4CCxNYilmKnwlQXOtXEOJjqIwb4U/CgM=',
|
||||||
privateKey: 'KKqsHDu30WCSrVsyzMkOKbE3saQ+wlx0sBwGs61UGXk=',
|
privateKey: 'KKqsHDu30WCSrVsyzMkOKbE3saQ+wlx0sBwGs61UGXk=',
|
||||||
preSharedKey: '0LWopbrISXBNHUxr+WOhCSAg+0hD8j3TLmpyzHkBHCQ=',
|
preSharedKey: '0LWopbrISXBNHUxr+WOhCSAg+0hD8j3TLmpyzHkBHCQ=',
|
||||||
ipIndex: 1,
|
// ipIndex: 1,
|
||||||
// allowedIps: '10.18.11.101/32,fd00::1/112',
|
// allowedIps: '10.18.11.101/32,fd00::1/112',
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
const returned = await db.insert(wgClients).values(clients).returning({ insertedId: wgClients.id });
|
||||||
|
|
||||||
await db.insert(wgClients).values(clients);
|
const ipAllocation: typeof ipAllocations.$inferInsert = {
|
||||||
|
clientId: returned[0].insertedId,
|
||||||
|
};
|
||||||
|
await db.insert(ipAllocations).values(ipAllocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
seed();
|
seed();
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
{#if user}
|
{#if user}
|
||||||
<a href="/user" class={getNavClass("/user")}>Profile</a>
|
<a href="/user" class={getNavClass("/user")}>Profile</a>
|
||||||
<a href="/connections" class={getNavClass("/connections")}>Connections</a>
|
<a href="/connections" class={getNavClass("/connections")}>Connections</a>
|
||||||
|
<a href="/clients" class={getNavClass("/clients")}>Clients</a>
|
||||||
{/if}
|
{/if}
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
28
src/routes/api/clients/+server.ts
Normal file
28
src/routes/api/clients/+server.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { error, type RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { wgClients } from '$lib/server/db/schema';
|
||||||
|
import { db } from '$lib/server/db';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async (event) => {
|
||||||
|
if (!event.locals.user) {
|
||||||
|
return error(401, 'Unauthorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const clients = await findClients(event.locals.user.id);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
clients,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function findClients(userId: string) {
|
||||||
|
return db.query.wgClients.findMany({
|
||||||
|
where: eq(wgClients.userId, userId),
|
||||||
|
with: {
|
||||||
|
ipAllocation: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Clients = Awaited<ReturnType<typeof findClients>>;
|
34
src/routes/clients/+page.svelte
Normal file
34
src/routes/clients/+page.svelte
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import * as Table from '$lib/components/ui/table';
|
||||||
|
import { Badge } from '$lib/components/ui/badge';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
|
const { data }: { data: PageData } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Clients</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<Table.Root class="bg-accent rounded-xl">
|
||||||
|
<Table.Header>
|
||||||
|
<Table.Head>Name</Table.Head>
|
||||||
|
<Table.Head>Public Key</Table.Head>
|
||||||
|
<Table.Head>Private Key</Table.Head>
|
||||||
|
<Table.Head>Pre-Shared Key</Table.Head>
|
||||||
|
<Table.Head>IP Allocation</Table.Head>
|
||||||
|
</Table.Header>
|
||||||
|
<Table.Body>
|
||||||
|
{#each data.clients as client}
|
||||||
|
<Table.Row class="border-y-2 border-background">
|
||||||
|
<Table.Cell>{client.name}</Table.Cell>
|
||||||
|
<Table.Cell class="truncate max-w-[10ch]">{client.publicKey}</Table.Cell>
|
||||||
|
<Table.Cell class="truncate max-w-[10ch]">{client.privateKey}</Table.Cell>
|
||||||
|
<Table.Cell class="truncate max-w-[10ch]">{client.preSharedKey}</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Badge class="bg-background" variant="secondary">{client.ipAllocation.id}</Badge>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
{/each}
|
||||||
|
</Table.Body>
|
||||||
|
</Table.Root>
|
9
src/routes/clients/+page.ts
Normal file
9
src/routes/clients/+page.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { PageLoad } from './$types';
|
||||||
|
import type { Clients } from '../api/clients/+server';
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ fetch }) => {
|
||||||
|
const res = await fetch('/api/clients');
|
||||||
|
const { clients } = await res.json() as { clients: Clients };
|
||||||
|
|
||||||
|
return { clients };
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user