diff --git a/bruno/Auth/verify-user.bru b/bruno/Auth/verify-user.bru index 80bb845..3895544 100644 --- a/bruno/Auth/verify-user.bru +++ b/bruno/Auth/verify-user.bru @@ -5,11 +5,11 @@ meta { } get { - url: http://localhost:3000/badger/verify-user?sessionId=asdf + url: http://localhost:3001/api/v1/badger/verify-user?sessionId=mb52273jkb6t3oys2bx6ur5x7rcrkl26c7warg3e body: none auth: none } params:query { - sessionId: asdf + sessionId: mb52273jkb6t3oys2bx6ur5x7rcrkl26c7warg3e } diff --git a/bruno/Traefik/traefik-config.bru b/bruno/Traefik/traefik-config.bru index e0d584b..a50b7aa 100644 --- a/bruno/Traefik/traefik-config.bru +++ b/bruno/Traefik/traefik-config.bru @@ -5,7 +5,7 @@ meta { } get { - url: http://localhost:3000/api/v1/traefik-config + url: http://localhost:3001/api/v1/traefik-config body: none auth: none } diff --git a/scripts/hydrate.ts b/scripts/hydrate.ts index ddd3103..defdf73 100644 --- a/scripts/hydrate.ts +++ b/scripts/hydrate.ts @@ -8,42 +8,31 @@ import { targets, } from "@server/db/schema"; import db from "@server/db"; +import { createSuperuserRole } from "@server/db/ensureActions"; async function insertDummyData() { // Insert dummy orgs const org1 = db .insert(orgs) .values({ - name: "Fossorial", - domain: "localhost", - }) - .returning() - .get(); - - const org2 = db - .insert(orgs) - .values({ - name: "Fosrl", + name: "Default", domain: "fosrl.io", }) .returning() .get(); - // Insert dummy users - // await db.insert(users).values([ - // { - // email: "john@fossorial.com", - // groups: "admin,developer", - // }, - // { - // email: "jane@fossorial.com", - // groups: "developer", - // }, - // { - // email: "bob@fosrl.io", - // groups: "admin", - // }, - // ]); + await createSuperuserRole(org1.orgId); + + const org2 = db + .insert(orgs) + .values({ + name: "Fossorial", + domain: "fossorial.io", + }) + .returning() + .get(); + + await createSuperuserRole(org2.orgId); // Insert dummy exit nodes const exitNode1 = db diff --git a/server/auth/actions.ts b/server/auth/actions.ts index 02f1382..890982f 100644 --- a/server/auth/actions.ts +++ b/server/auth/actions.ts @@ -26,7 +26,6 @@ export enum ActionsEnum { getTarget = "getTarget", listTargets = "listTargets", updateTarget = "updateTarget", - getUser = "getUser", deleteUser = "deleteUser", listUsers = "listUsers" } diff --git a/server/db/ensureActions.ts b/server/db/ensureActions.ts index 0ed233b..aa60364 100644 --- a/server/db/ensureActions.ts +++ b/server/db/ensureActions.ts @@ -1,38 +1,60 @@ import { ActionsEnum } from "@server/auth/actions"; import { db } from "@server/db"; -import { actions } from "./schema"; -import { eq } from "drizzle-orm"; +import { actions, roles, roleActions } from "./schema"; +import { eq, and, inArray, notInArray } from "drizzle-orm"; -// Ensure actions are in the database export async function ensureActions() { const actionIds = Object.values(ActionsEnum); - for (const actionId of actionIds) { - const existing = await db - .select() - .from(actions) - .where(eq(actions.name, actionId)) + const existingActions = await db.select().from(actions).execute(); + const existingActionIds = existingActions.map(action => action.actionId); + + const actionsToAdd = actionIds.filter(id => !existingActionIds.includes(id)); + const actionsToRemove = existingActionIds.filter(id => !actionIds.includes(id as ActionsEnum)); + + const defaultRoles = await db + .select() + .from(roles) + .where(eq(roles.isSuperuserRole, true)) + .execute(); + + // Add new actions + for (const actionId of actionsToAdd) { + await db.insert(actions).values({ actionId }).execute(); + // Add new actions to the Default role + await db.insert(roleActions) + .values(defaultRoles.map(role => ({ roleId: role.roleId!, actionId, orgId: role.orgId! }))) .execute(); - if (existing.length === 0) { - await db - .insert(actions) - .values({ - actionId - }) - .execute(); - } } - // make sure all actions are in the database - const existingActions = await db - .select() - .from(actions) - .execute(); - for (const action of existingActions) { - if (!actionIds.includes(action.actionId as ActionsEnum)) { - await db - .delete(actions) - .where(eq(actions.actionId, action.actionId)) - .execute(); - } + // Remove deprecated actions + if (actionsToRemove.length > 0) { + await db.delete(actions).where(inArray(actions.actionId, actionsToRemove)).execute(); + await db.delete(roleActions).where(inArray(roleActions.actionId, actionsToRemove)).execute(); } +} + +export async function createSuperuserRole(orgId: number) { + // Create the Default role if it doesn't exist + const [insertedRole] = await db + .insert(roles) + .values({ + orgId, + isSuperuserRole: true, + name: 'Superuser', + description: 'Superuser role with all actions' + }) + .returning({ roleId: roles.roleId }) + .execute(); + + const roleId = insertedRole.roleId; + + // Add all current actions to the new Default role + const actionIds = Object.values(ActionsEnum); + await db.insert(roleActions) + .values(actionIds.map(actionId => ({ + roleId, + actionId: actionId, + orgId + }))) + .execute(); } \ No newline at end of file diff --git a/server/db/schema.ts b/server/db/schema.ts index 440832f..178b3f9 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -138,6 +138,7 @@ export const actions = sqliteTable("actions", { export const roles = sqliteTable("roles", { roleId: integer("roleId").primaryKey({ autoIncrement: true }), orgId: integer("orgId").references(() => orgs.orgId, { onDelete: "cascade" }), + isSuperuserRole: integer("isSuperuserRole", { mode: "boolean" }), name: text("name").notNull(), description: text("description"), }); diff --git a/server/index.ts b/server/index.ts index 71292f2..86191d6 100644 --- a/server/index.ts +++ b/server/index.ts @@ -14,6 +14,7 @@ import internal from "@server/routers/internal"; import { authenticated, unauthenticated } from "@server/routers/external"; import cookieParser from "cookie-parser"; import { User } from "@server/db/schema"; +import { ensureActions } from "./db/ensureActions"; const dev = environment.ENVIRONMENT !== "prod"; @@ -25,6 +26,8 @@ const internalPort = environment.INTERNAL_PORT; app.prepare().then(() => { + ensureActions(); // This loads the actions into the database + // External server const externalServer = express(); externalServer.set("trust proxy", 1); diff --git a/server/routers/org/createOrg.ts b/server/routers/org/createOrg.ts index fafe197..ae0afcc 100644 --- a/server/routers/org/createOrg.ts +++ b/server/routers/org/createOrg.ts @@ -7,6 +7,7 @@ import HttpCode from '@server/types/HttpCode'; import createHttpError from 'http-errors'; import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions'; import logger from '@server/logger'; +import { createSuperuserRole } from '@server/db/ensureActions'; const createOrgSchema = z.object({ name: z.string().min(1).max(255), @@ -50,6 +51,8 @@ export async function createOrg(req: Request, res: Response, next: NextFunction) domain, }).returning(); + await createSuperuserRole(newOrg[0].orgId); + return response(res, { data: newOrg[0], success: true, diff --git a/server/routers/user/getUser.ts b/server/routers/user/getUser.ts index 41d62b0..11dd428 100644 --- a/server/routers/user/getUser.ts +++ b/server/routers/user/getUser.ts @@ -18,12 +18,6 @@ export async function getUser(req: Request, res: Response, next: NextFunction): return next(createHttpError(HttpCode.UNAUTHORIZED, "User not found")); } - // // Check if the user has permission to list sites - // const hasPermission = await checkUserActionPermission(ActionsEnum.getUser, req); - // if (!hasPermission) { - // return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to list sites')); - // } - const user = await db.select() .from(users) .where(eq(users.id, userId))