Ensure the user's actions

This commit is contained in:
Owen Schwartz 2024-10-10 21:59:30 -04:00
parent 143a3b756e
commit 4fc630cf42
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
9 changed files with 74 additions and 63 deletions

View file

@ -5,11 +5,11 @@ meta {
} }
get { get {
url: http://localhost:3000/badger/verify-user?sessionId=asdf url: http://localhost:3001/api/v1/badger/verify-user?sessionId=mb52273jkb6t3oys2bx6ur5x7rcrkl26c7warg3e
body: none body: none
auth: none auth: none
} }
params:query { params:query {
sessionId: asdf sessionId: mb52273jkb6t3oys2bx6ur5x7rcrkl26c7warg3e
} }

View file

@ -5,7 +5,7 @@ meta {
} }
get { get {
url: http://localhost:3000/api/v1/traefik-config url: http://localhost:3001/api/v1/traefik-config
body: none body: none
auth: none auth: none
} }

View file

@ -8,42 +8,31 @@ import {
targets, targets,
} from "@server/db/schema"; } from "@server/db/schema";
import db from "@server/db"; import db from "@server/db";
import { createSuperuserRole } from "@server/db/ensureActions";
async function insertDummyData() { async function insertDummyData() {
// Insert dummy orgs // Insert dummy orgs
const org1 = db const org1 = db
.insert(orgs) .insert(orgs)
.values({ .values({
name: "Fossorial", name: "Default",
domain: "localhost",
})
.returning()
.get();
const org2 = db
.insert(orgs)
.values({
name: "Fosrl",
domain: "fosrl.io", domain: "fosrl.io",
}) })
.returning() .returning()
.get(); .get();
// Insert dummy users await createSuperuserRole(org1.orgId);
// await db.insert(users).values([
// { const org2 = db
// email: "john@fossorial.com", .insert(orgs)
// groups: "admin,developer", .values({
// }, name: "Fossorial",
// { domain: "fossorial.io",
// email: "jane@fossorial.com", })
// groups: "developer", .returning()
// }, .get();
// {
// email: "bob@fosrl.io", await createSuperuserRole(org2.orgId);
// groups: "admin",
// },
// ]);
// Insert dummy exit nodes // Insert dummy exit nodes
const exitNode1 = db const exitNode1 = db

View file

@ -26,7 +26,6 @@ export enum ActionsEnum {
getTarget = "getTarget", getTarget = "getTarget",
listTargets = "listTargets", listTargets = "listTargets",
updateTarget = "updateTarget", updateTarget = "updateTarget",
getUser = "getUser",
deleteUser = "deleteUser", deleteUser = "deleteUser",
listUsers = "listUsers" listUsers = "listUsers"
} }

View file

@ -1,38 +1,60 @@
import { ActionsEnum } from "@server/auth/actions"; import { ActionsEnum } from "@server/auth/actions";
import { db } from "@server/db"; import { db } from "@server/db";
import { actions } from "./schema"; import { actions, roles, roleActions } from "./schema";
import { eq } from "drizzle-orm"; import { eq, and, inArray, notInArray } from "drizzle-orm";
// Ensure actions are in the database
export async function ensureActions() { export async function ensureActions() {
const actionIds = Object.values(ActionsEnum); const actionIds = Object.values(ActionsEnum);
for (const actionId of actionIds) { const existingActions = await db.select().from(actions).execute();
const existing = await db const existingActionIds = existingActions.map(action => action.actionId);
.select()
.from(actions) const actionsToAdd = actionIds.filter(id => !existingActionIds.includes(id));
.where(eq(actions.name, actionId)) 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(); .execute();
if (existing.length === 0) {
await db
.insert(actions)
.values({
actionId
})
.execute();
}
} }
// make sure all actions are in the database // Remove deprecated actions
const existingActions = await db if (actionsToRemove.length > 0) {
.select() await db.delete(actions).where(inArray(actions.actionId, actionsToRemove)).execute();
.from(actions) await db.delete(roleActions).where(inArray(roleActions.actionId, actionsToRemove)).execute();
.execute();
for (const action of existingActions) {
if (!actionIds.includes(action.actionId as ActionsEnum)) {
await db
.delete(actions)
.where(eq(actions.actionId, action.actionId))
.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();
} }

View file

@ -138,6 +138,7 @@ export const actions = sqliteTable("actions", {
export const roles = sqliteTable("roles", { export const roles = sqliteTable("roles", {
roleId: integer("roleId").primaryKey({ autoIncrement: true }), roleId: integer("roleId").primaryKey({ autoIncrement: true }),
orgId: integer("orgId").references(() => orgs.orgId, { onDelete: "cascade" }), orgId: integer("orgId").references(() => orgs.orgId, { onDelete: "cascade" }),
isSuperuserRole: integer("isSuperuserRole", { mode: "boolean" }),
name: text("name").notNull(), name: text("name").notNull(),
description: text("description"), description: text("description"),
}); });

View file

@ -14,6 +14,7 @@ import internal from "@server/routers/internal";
import { authenticated, unauthenticated } from "@server/routers/external"; import { authenticated, unauthenticated } from "@server/routers/external";
import cookieParser from "cookie-parser"; import cookieParser from "cookie-parser";
import { User } from "@server/db/schema"; import { User } from "@server/db/schema";
import { ensureActions } from "./db/ensureActions";
const dev = environment.ENVIRONMENT !== "prod"; const dev = environment.ENVIRONMENT !== "prod";
@ -25,6 +26,8 @@ const internalPort = environment.INTERNAL_PORT;
app.prepare().then(() => { app.prepare().then(() => {
ensureActions(); // This loads the actions into the database
// External server // External server
const externalServer = express(); const externalServer = express();
externalServer.set("trust proxy", 1); externalServer.set("trust proxy", 1);

View file

@ -7,6 +7,7 @@ import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors'; import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions'; import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger'; import logger from '@server/logger';
import { createSuperuserRole } from '@server/db/ensureActions';
const createOrgSchema = z.object({ const createOrgSchema = z.object({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
@ -50,6 +51,8 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
domain, domain,
}).returning(); }).returning();
await createSuperuserRole(newOrg[0].orgId);
return response(res, { return response(res, {
data: newOrg[0], data: newOrg[0],
success: true, success: true,

View file

@ -18,12 +18,6 @@ export async function getUser(req: Request, res: Response, next: NextFunction):
return next(createHttpError(HttpCode.UNAUTHORIZED, "User not found")); 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() const user = await db.select()
.from(users) .from(users)
.where(eq(users.id, userId)) .where(eq(users.id, userId))