diff --git a/src/app.css b/src/app.css index 3b8985c..45f699a 100644 --- a/src/app.css +++ b/src/app.css @@ -88,7 +88,7 @@ --sidebar-border: 240 3.7% 15.9%; --sidebar-ring: 217.2 91.2% 59.8%; - --surface: 217.2 40.6% 10.5%; + --surface: 217.2 40.6% 11.5%; } } } diff --git a/src/lib/connections.ts b/src/lib/connections.ts new file mode 100644 index 0000000..ff3a768 --- /dev/null +++ b/src/lib/connections.ts @@ -0,0 +1,10 @@ +export type ConnectionDetails = { + deviceId: number; + deviceName: string; + devicePublicKey: string; + deviceIps: string[]; + endpoint: string; + transferRx: number; + transferTx: number; + latestHandshake: number; +}; diff --git a/src/lib/types/device.ts b/src/lib/types/device.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/routes/api/connections/+server.ts b/src/routes/api/connections/+server.ts index 08727f4..0da2b6d 100644 --- a/src/routes/api/connections/+server.ts +++ b/src/routes/api/connections/+server.ts @@ -2,11 +2,54 @@ import { error } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; import { opnsenseAuth, opnsenseUrl } from '$lib/server/opnsense'; import type { OpnsenseWgPeers } from '$lib/opnsense/wg'; +import { findDevices } from '$lib/server/devices'; +import type { ConnectionDetails } from '$lib/connections'; export const GET: RequestHandler = async (event) => { if (!event.locals.user) { return error(401, 'Unauthorized'); } + console.debug('/api/connections'); + const peers = await fetchOpnsensePeers(event.locals.user.username); + console.debug('/api/connections: fetched opnsense peers', peers.rowCount); + const devices = await findDevices(event.locals.user.id); + console.debug('/api/connections: fetched db devices'); + + if (!peers) { + return error(500, 'Error getting info from OPNsense API'); + } + + // TODO: this is all garbage performance + // filter devices with no recent handshakes + peers.rows = peers.rows.filter((peer) => peer['latest-handshake']); + + // start from devices, to treat db as the source of truth + const connections: ConnectionDetails[] = []; + for (const device of devices) { + const peerData = peers.rows.find((peer) => peer['public-key'] === device.publicKey); + if (!peerData) continue; + connections.push({ + deviceId: device.id, + deviceName: device.name, + devicePublicKey: device.publicKey, + deviceIps: peerData['allowed-ips'].split(','), + endpoint: peerData['endpoint'], + // swap rx and tx, since the opnsense values are from the server perspective + transferRx: peerData['transfer-tx'], + transferTx: peerData['transfer-rx'], + latestHandshake: peerData['latest-handshake'] * 1000, + }); + } + + return new Response(JSON.stringify(connections), { + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'max-age=5', + }, + }); +}; + +async function fetchOpnsensePeers(username: string) { const apiUrl = `${opnsenseUrl}/api/wireguard/service/show`; const options: RequestInit = { method: 'POST', @@ -16,28 +59,17 @@ export const GET: RequestHandler = async (event) => { 'Content-Type': 'application/json', }, body: JSON.stringify({ - 'current': 1, + current: 1, // "rowCount": 7, - 'sort': {}, + sort: {}, // TODO: use a more unique search phrase // unfortunately 64 character limit, // but it should be fine if users can't change their own username - 'searchPhrase': `vpgen-${event.locals.user.username}`, - 'type': ['peer'], + searchPhrase: `vpgen-${username}`, + type: ['peer'], }), }; const res = await fetch(apiUrl, options); - const peers = await res.json() as OpnsenseWgPeers; - peers.rows = peers.rows.filter(peer => peer['latest-handshake']) - - if (!peers) { - return error(500, 'Error getting info from OPNsense API'); - } - return new Response(JSON.stringify(peers), { - headers: { - 'Content-Type': 'application/json', - 'Cache-Control': 'max-age=5', - } - }); -}; + return (await res.json()) as OpnsenseWgPeers; +} diff --git a/src/routes/connections/+page.svelte b/src/routes/connections/+page.svelte index 139e0bf..1c34d0c 100644 --- a/src/routes/connections/+page.svelte +++ b/src/routes/connections/+page.svelte @@ -16,7 +16,7 @@ return () => clearInterval(interval); }); - function getSize(size: number) { + function toSizeString(size: number) { let sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; for (let i = 1; i < sizes.length; i++) { @@ -34,35 +34,31 @@