From 346f2db5fbf406b14ab19ffda10710170843d438 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Fri, 21 Feb 2025 11:57:01 -0500 Subject: [PATCH] add client olm relationship --- server/db/schema.ts | 46 +++++++++++++++---- server/routers/client/index.ts | 1 + .../pickClientDefaults.ts} | 46 +++++++++++-------- server/routers/external.ts | 4 +- server/routers/olm/index.ts | 3 +- 5 files changed, 69 insertions(+), 31 deletions(-) create mode 100644 server/routers/client/index.ts rename server/routers/{olm/pickOlmDefaults.ts => client/pickClientDefaults.ts} (75%) diff --git a/server/db/schema.ts b/server/db/schema.ts index 9564fdff..931bf6a4 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -61,7 +61,9 @@ export const resources = sqliteTable("resources", { .notNull() .default(false), isBaseDomain: integer("isBaseDomain", { mode: "boolean" }), - applyRules: integer("applyRules", { mode: "boolean" }).notNull().default(false) + applyRules: integer("applyRules", { mode: "boolean" }) + .notNull() + .default(false) }); export const targets = sqliteTable("targets", { @@ -114,22 +116,27 @@ export const newts = sqliteTable("newt", { }) }); -export const olms = sqliteTable("olms", { - olmId: text("id").primaryKey(), - secretHash: text("secretHash").notNull(), - dateCreated: text("dateCreated").notNull(), +export const clients = sqliteTable("clients", { + clientId: integer("id").primaryKey({ autoIncrement: true }), siteId: integer("siteId").references(() => sites.siteId, { onDelete: "cascade" }), - - // wgstuff pubKey: text("pubKey"), subnet: text("subnet").notNull(), megabytesIn: integer("bytesIn"), megabytesOut: integer("bytesOut"), lastBandwidthUpdate: text("lastBandwidthUpdate"), - type: text("type").notNull(), // "newt" or "wireguard" - online: integer("online", { mode: "boolean" }).notNull().default(false), + type: text("type").notNull(), // "olm" + online: integer("online", { mode: "boolean" }).notNull().default(false) +}); + +export const olms = sqliteTable("olms", { + olmId: text("id").primaryKey(), + secretHash: text("secretHash").notNull(), + dateCreated: text("dateCreated").notNull(), + clientId: integer("clientId").references(() => clients.clientId, { + onDelete: "cascade" + }) }); export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", { @@ -259,6 +266,24 @@ export const userSites = sqliteTable("userSites", { .references(() => sites.siteId, { onDelete: "cascade" }) }); +export const userClients = sqliteTable("userClients", { + userId: text("userId") + .notNull() + .references(() => users.userId, { onDelete: "cascade" }), + clientId: integer("clientId") + .notNull() + .references(() => clients.clientId, { onDelete: "cascade" }) +}); + +export const roleClients = sqliteTable("roleClients", { + roleId: integer("roleId") + .notNull() + .references(() => roles.roleId, { onDelete: "cascade" }), + clientId: integer("clientId") + .notNull() + .references(() => clients.clientId, { onDelete: "cascade" }) +}); + export const roleResources = sqliteTable("roleResources", { roleId: integer("roleId") .notNull() @@ -451,3 +476,6 @@ export type ResourceAccessToken = InferSelectModel; export type ResourceWhitelist = InferSelectModel; export type VersionMigration = InferSelectModel; export type ResourceRule = InferSelectModel; +export type Client = InferSelectModel; +export type RoleClient = InferSelectModel; +export type UserClient = InferSelectModel; diff --git a/server/routers/client/index.ts b/server/routers/client/index.ts new file mode 100644 index 00000000..5b493724 --- /dev/null +++ b/server/routers/client/index.ts @@ -0,0 +1 @@ +export * from "./pickClientDefaults"; diff --git a/server/routers/olm/pickOlmDefaults.ts b/server/routers/client/pickClientDefaults.ts similarity index 75% rename from server/routers/olm/pickOlmDefaults.ts rename to server/routers/client/pickClientDefaults.ts index 24ddcace..fd048259 100644 --- a/server/routers/olm/pickOlmDefaults.ts +++ b/server/routers/client/pickClientDefaults.ts @@ -1,6 +1,6 @@ import { Request, Response, NextFunction } from "express"; import { db } from "@server/db"; -import { olms, sites } from "@server/db/schema"; +import { clients, olms, sites } from "@server/db/schema"; import { eq } from "drizzle-orm"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; @@ -30,7 +30,7 @@ export type PickClientDefaultsResponse = { clientSecret: string; }; -export async function pickOlmDefaults( +export async function pickClientDefaults( req: Request, res: Response, next: NextFunction @@ -58,29 +58,39 @@ export async function pickOlmDefaults( } // make sure all the required fields are present - if ( - !site.address || - !site.publicKey || - !site.listenPort || - !site.endpoint - ) { + + const sitesRequiredFields = z.object({ + address: z.string(), + publicKey: z.string(), + listenPort: z.number(), + endpoint: z.string() + }); + + const parsedSite = sitesRequiredFields.safeParse(site); + if (!parsedSite.success) { return next( - createHttpError(HttpCode.BAD_REQUEST, "Site has no address") + createHttpError( + HttpCode.BAD_REQUEST, + "Unable to pick client defaults because: " + + fromError(parsedSite.error).toString() + ) ); } + const { address, publicKey, listenPort, endpoint } = parsedSite.data; + const clientsQuery = await db .select({ - subnet: olms.subnet + subnet: clients.subnet }) - .from(olms) - .where(eq(olms.siteId, site.siteId)); + .from(clients) + .where(eq(clients.siteId, site.siteId)); let subnets = clientsQuery.map((client) => client.subnet); // exclude the exit node address by replacing after the / with a site block size subnets.push( - site.address.replace( + address.replace( /\/\d+$/, `/${config.getRawConfig().wg_site.block_size}` ) @@ -88,7 +98,7 @@ export async function pickOlmDefaults( const newSubnet = findNextAvailableCidr( subnets, config.getRawConfig().wg_site.block_size, - site.address + address ); if (!newSubnet) { return next( @@ -105,11 +115,11 @@ export async function pickOlmDefaults( return response(res, { data: { siteId: site.siteId, - address: site.address, - publicKey: site.publicKey, + address: address, + publicKey: publicKey, name: site.name, - listenPort: site.listenPort, - endpoint: site.endpoint, + listenPort: listenPort, + endpoint: endpoint, subnet: newSubnet, clientId, clientSecret: secret diff --git a/server/routers/external.ts b/server/routers/external.ts index cb5fbfd7..778bf288 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -7,7 +7,7 @@ import * as target from "./target"; import * as user from "./user"; import * as auth from "./auth"; import * as role from "./role"; -import * as olm from "./olm"; +import * as client from "./client"; import * as accessToken from "./accessToken"; import HttpCode from "@server/types/HttpCode"; import { @@ -100,7 +100,7 @@ authenticated.get( "/site/:siteId/pick-client-defaults", verifyOrgAccess, verifyUserHasAction(ActionsEnum.createClient), - olm.pickOlmDefaults + client.pickClientDefaults ); // authenticated.get( diff --git a/server/routers/olm/index.ts b/server/routers/olm/index.ts index 4c073152..d29a2ef1 100644 --- a/server/routers/olm/index.ts +++ b/server/routers/olm/index.ts @@ -1,2 +1 @@ -export * from "./pickOlmDefaults"; -export * from "./handleOlmRegisterMessage"; \ No newline at end of file +export * from "./handleOlmRegisterMessage";