mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-19 00:40:40 +02:00
rename super user to admin and middleware refactoring
This commit is contained in:
parent
7b755a273c
commit
03051878ef
26 changed files with 790 additions and 529 deletions
|
@ -1,159 +1,130 @@
|
||||||
// import {
|
// import { orgs, sites, resources, exitNodes, targets } from "@server/db/schema";
|
||||||
// orgs,
|
|
||||||
// sites,
|
|
||||||
// resources,
|
|
||||||
// exitNodes,
|
|
||||||
// routes,
|
|
||||||
// targets,
|
|
||||||
// } from "@server/db/schema";
|
|
||||||
// import db from "@server/db";
|
// import db from "@server/db";
|
||||||
// import { createSuperUserRole } from "@server/db/ensureActions";
|
// import { crateAdminRole } from "@server/db/ensureActions";
|
||||||
|
|
||||||
async function insertDummyData() {
|
// async function insertDummyData() {
|
||||||
// // Insert dummy orgs
|
// const org1 = db
|
||||||
// const org1 = db
|
// .insert(orgs)
|
||||||
// .insert(orgs)
|
// .values({
|
||||||
// .values({
|
// orgId: "fossorial",
|
||||||
// orgId: "default",
|
// name: "Fossorial",
|
||||||
// name: "Default",
|
// domain: "fossorial.io",
|
||||||
// domain: "fosrl.io",
|
// })
|
||||||
// })
|
// .returning()
|
||||||
// .returning()
|
// .get();
|
||||||
// .get();
|
|
||||||
|
|
||||||
// await createSuperUserRole(org1.orgId!);
|
// await crateAdminRole(org1.orgId!);
|
||||||
|
|
||||||
// const org2 = db
|
// // Insert dummy exit nodes
|
||||||
// .insert(orgs)
|
// const exitNode1 = db
|
||||||
// .values({
|
// .insert(exitNodes)
|
||||||
// orgId: "fossorial",
|
// .values({
|
||||||
// name: "Fossorial",
|
// name: "Exit Node 1",
|
||||||
// domain: "fossorial.io",
|
// address: "10.0.0.1/24",
|
||||||
// })
|
// publicKey: "sKQlCNErB2n+dV8eLp5Yw/avsjK/zkrxJE0n48hjb10=",
|
||||||
// .returning()
|
// listenPort: 51820,
|
||||||
// .get();
|
// endpoint: "exitnode1.fossorial.io",
|
||||||
|
// })
|
||||||
|
// .returning()
|
||||||
|
// .get();
|
||||||
|
|
||||||
// await createSuperUserRole(org2.orgId!);
|
// // Insert dummy sites
|
||||||
|
// const site1 = db
|
||||||
|
// .insert(sites)
|
||||||
|
// .values({
|
||||||
|
// orgId: org1.orgId,
|
||||||
|
|
||||||
// // Insert dummy exit nodes
|
// exitNodeId: exitNode1.exitNodeId,
|
||||||
// const exitNode1 = db
|
// name: "Main Site",
|
||||||
// .insert(exitNodes)
|
// subdomain: "main",
|
||||||
// .values({
|
// pubKey: "Kn4eD0kvcTwjO//zqH/CtNVkMNdMiUkbqFxysEym2D8=",
|
||||||
// name: "Exit Node 1",
|
// subnet: "10.0.0.16/28",
|
||||||
// address: "10.0.0.1/24",
|
// })
|
||||||
// privateKey: "sKQlCNErB2n+dV8eLp5Yw/avsjK/zkrxJE0n48hjb10=",
|
// .returning()
|
||||||
// listenPort: 51820,
|
// .get();
|
||||||
// })
|
|
||||||
// .returning()
|
|
||||||
// .get();
|
|
||||||
|
|
||||||
// const exitNode2 = db
|
// const site2 = db
|
||||||
// .insert(exitNodes)
|
// .insert(sites)
|
||||||
// .values({
|
// .values({
|
||||||
// name: "Exit Node 2",
|
// orgId: org2.orgId,
|
||||||
// address: "172.16.1.1/24",
|
// exitNode: exitNode2.exitNodeId,
|
||||||
// privateKey: "ACaw+q5vHVm8Xb0jIgIkMzlkJiriC7cURuOiNbGsGHg=",
|
// name: "Dev Site",
|
||||||
// listenPort: 51820,
|
// subdomain: "dev",
|
||||||
// })
|
// pubKey: "V329Uf/vhnBwYxAuT/ZlMZuLokHy5tug/sGsLfIMK1w=",
|
||||||
// .returning()
|
// subnet: "172.16.1.16/28",
|
||||||
// .get();
|
// })
|
||||||
|
// .returning()
|
||||||
|
// .get();
|
||||||
|
|
||||||
// // Insert dummy sites
|
// // Insert dummy resources
|
||||||
// const site1 = db
|
// const resource1 = db
|
||||||
// .insert(sites)
|
// .insert(resources)
|
||||||
// .values({
|
// .values({
|
||||||
// orgId: org1.orgId,
|
// resourceId: `web.${site1.subdomain}.${org1.domain}`,
|
||||||
// exitNode: exitNode1.exitNodeId,
|
// siteId: site1.siteId,
|
||||||
// name: "Main Site",
|
// orgId: site1.orgId,
|
||||||
// subdomain: "main",
|
// name: "Web Server",
|
||||||
// pubKey: "Kn4eD0kvcTwjO//zqH/CtNVkMNdMiUkbqFxysEym2D8=",
|
// subdomain: "web",
|
||||||
// subnet: "10.0.0.16/28",
|
// })
|
||||||
// })
|
// .returning()
|
||||||
// .returning()
|
// .get();
|
||||||
// .get();
|
|
||||||
|
|
||||||
// const site2 = db
|
// const resource2 = db
|
||||||
// .insert(sites)
|
// .insert(resources)
|
||||||
// .values({
|
// .values({
|
||||||
// orgId: org2.orgId,
|
// resourceId: `web2.${site1.subdomain}.${org1.domain}`,
|
||||||
// exitNode: exitNode2.exitNodeId,
|
// siteId: site1.siteId,
|
||||||
// name: "Dev Site",
|
// orgId: site1.orgId,
|
||||||
// subdomain: "dev",
|
// name: "Web Server 2",
|
||||||
// pubKey: "V329Uf/vhnBwYxAuT/ZlMZuLokHy5tug/sGsLfIMK1w=",
|
// subdomain: "web2",
|
||||||
// subnet: "172.16.1.16/28",
|
// })
|
||||||
// })
|
// .returning()
|
||||||
// .returning()
|
// .get();
|
||||||
// .get();
|
|
||||||
|
|
||||||
// // Insert dummy resources
|
// const resource3 = db
|
||||||
// const resource1 = db
|
// .insert(resources)
|
||||||
// .insert(resources)
|
// .values({
|
||||||
// .values({
|
// resourceId: `db.${site2.subdomain}.${org2.domain}`,
|
||||||
// resourceId: `web.${site1.subdomain}.${org1.domain}`,
|
// siteId: site2.siteId,
|
||||||
// siteId: site1.siteId,
|
// orgId: site2.orgId,
|
||||||
// orgId: site1.orgId,
|
// name: "Database",
|
||||||
// name: "Web Server",
|
// subdomain: "db",
|
||||||
// subdomain: "web",
|
// })
|
||||||
// })
|
// .returning()
|
||||||
// .returning()
|
// .get();
|
||||||
// .get();
|
|
||||||
|
|
||||||
// const resource2 = db
|
// // Insert dummy routes
|
||||||
// .insert(resources)
|
// await db.insert(routes).values([
|
||||||
// .values({
|
// { exitNodeId: exitNode1.exitNodeId, subnet: "10.0.0.0/24" },
|
||||||
// resourceId: `web2.${site1.subdomain}.${org1.domain}`,
|
// { exitNodeId: exitNode2.exitNodeId, subnet: "172.16.1.1/24" },
|
||||||
// siteId: site1.siteId,
|
// ]);
|
||||||
// orgId: site1.orgId,
|
|
||||||
// name: "Web Server 2",
|
|
||||||
// subdomain: "web2",
|
|
||||||
// })
|
|
||||||
// .returning()
|
|
||||||
// .get();
|
|
||||||
|
|
||||||
// const resource3 = db
|
// // Insert dummy targets
|
||||||
// .insert(resources)
|
// await db.insert(targets).values([
|
||||||
// .values({
|
// {
|
||||||
// resourceId: `db.${site2.subdomain}.${org2.domain}`,
|
// resourceId: resource1.resourceId,
|
||||||
// siteId: site2.siteId,
|
// ip: "10.0.0.16",
|
||||||
// orgId: site2.orgId,
|
// method: "http",
|
||||||
// name: "Database",
|
// port: 4200,
|
||||||
// subdomain: "db",
|
// protocol: "TCP",
|
||||||
// })
|
// },
|
||||||
// .returning()
|
// {
|
||||||
// .get();
|
// resourceId: resource2.resourceId,
|
||||||
|
// ip: "10.0.0.17",
|
||||||
|
// method: "https",
|
||||||
|
// port: 443,
|
||||||
|
// protocol: "TCP",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// resourceId: resource3.resourceId,
|
||||||
|
// ip: "172.16.1.16",
|
||||||
|
// method: "http",
|
||||||
|
// port: 80,
|
||||||
|
// protocol: "TCP",
|
||||||
|
// },
|
||||||
|
// ]);
|
||||||
|
|
||||||
// // Insert dummy routes
|
// console.log("Dummy data inserted successfully");
|
||||||
// await db.insert(routes).values([
|
// }
|
||||||
// { exitNodeId: exitNode1.exitNodeId, subnet: "10.0.0.0/24" },
|
|
||||||
// { exitNodeId: exitNode2.exitNodeId, subnet: "172.16.1.1/24" },
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// // Insert dummy targets
|
// insertDummyData().catch(console.error);
|
||||||
// await db.insert(targets).values([
|
|
||||||
// {
|
|
||||||
// resourceId: resource1.resourceId,
|
|
||||||
// ip: "10.0.0.16",
|
|
||||||
// method: "http",
|
|
||||||
// port: 4200,
|
|
||||||
// protocol: "TCP",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// resourceId: resource2.resourceId,
|
|
||||||
// ip: "10.0.0.17",
|
|
||||||
// method: "https",
|
|
||||||
// port: 443,
|
|
||||||
// protocol: "TCP",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// resourceId: resource3.resourceId,
|
|
||||||
// ip: "172.16.1.16",
|
|
||||||
// method: "http",
|
|
||||||
// port: 80,
|
|
||||||
// protocol: "TCP",
|
|
||||||
// },
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// console.log("Dummy data inserted successfully");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertDummyData().catch(console.error);
|
|
||||||
|
|
|
@ -7,15 +7,19 @@ import logger from "@server/logger";
|
||||||
export async function ensureActions() {
|
export async function ensureActions() {
|
||||||
const actionIds = Object.values(ActionsEnum);
|
const actionIds = Object.values(ActionsEnum);
|
||||||
const existingActions = await db.select().from(actions).execute();
|
const existingActions = await db.select().from(actions).execute();
|
||||||
const existingActionIds = existingActions.map(action => action.actionId);
|
const existingActionIds = existingActions.map((action) => action.actionId);
|
||||||
|
|
||||||
const actionsToAdd = actionIds.filter(id => !existingActionIds.includes(id));
|
const actionsToAdd = actionIds.filter(
|
||||||
const actionsToRemove = existingActionIds.filter(id => !actionIds.includes(id as ActionsEnum));
|
(id) => !existingActionIds.includes(id)
|
||||||
|
);
|
||||||
|
const actionsToRemove = existingActionIds.filter(
|
||||||
|
(id) => !actionIds.includes(id as ActionsEnum)
|
||||||
|
);
|
||||||
|
|
||||||
const defaultRoles = await db
|
const defaultRoles = await db
|
||||||
.select()
|
.select()
|
||||||
.from(roles)
|
.from(roles)
|
||||||
.where(eq(roles.isSuperUserRole, true))
|
.where(eq(roles.isAdmin, true))
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
// Add new actions
|
// Add new actions
|
||||||
|
@ -24,29 +28,42 @@ export async function ensureActions() {
|
||||||
await db.insert(actions).values({ actionId }).execute();
|
await db.insert(actions).values({ actionId }).execute();
|
||||||
// Add new actions to the Default role
|
// Add new actions to the Default role
|
||||||
if (defaultRoles.length != 0) {
|
if (defaultRoles.length != 0) {
|
||||||
await db.insert(roleActions)
|
await db
|
||||||
.values(defaultRoles.map(role => ({ roleId: role.roleId!, actionId, orgId: role.orgId! })))
|
.insert(roleActions)
|
||||||
|
.values(
|
||||||
|
defaultRoles.map((role) => ({
|
||||||
|
roleId: role.roleId!,
|
||||||
|
actionId,
|
||||||
|
orgId: role.orgId!,
|
||||||
|
}))
|
||||||
|
)
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove deprecated actions
|
// Remove deprecated actions
|
||||||
if (actionsToRemove.length > 0) {
|
if (actionsToRemove.length > 0) {
|
||||||
logger.debug(`Removing actions: ${actionsToRemove.join(', ')}`);
|
logger.debug(`Removing actions: ${actionsToRemove.join(", ")}`);
|
||||||
await db.delete(actions).where(inArray(actions.actionId, actionsToRemove)).execute();
|
await db
|
||||||
await db.delete(roleActions).where(inArray(roleActions.actionId, actionsToRemove)).execute();
|
.delete(actions)
|
||||||
|
.where(inArray(actions.actionId, actionsToRemove))
|
||||||
|
.execute();
|
||||||
|
await db
|
||||||
|
.delete(roleActions)
|
||||||
|
.where(inArray(roleActions.actionId, actionsToRemove))
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createSuperUserRole(orgId: string) {
|
export async function createAdminRole(orgId: string) {
|
||||||
// Create the Default role if it doesn't exist
|
// Create the Default role if it doesn't exist
|
||||||
const [insertedRole] = await db
|
const [insertedRole] = await db
|
||||||
.insert(roles)
|
.insert(roles)
|
||||||
.values({
|
.values({
|
||||||
orgId,
|
orgId,
|
||||||
isSuperUserRole: true,
|
isAdmin: true,
|
||||||
name: 'Super User',
|
name: "Admin",
|
||||||
description: 'Super User role with all actions'
|
description: "Admin role most permissions",
|
||||||
})
|
})
|
||||||
.returning({ roleId: roles.roleId })
|
.returning({ roleId: roles.roleId })
|
||||||
.execute();
|
.execute();
|
||||||
|
@ -56,12 +73,19 @@ export async function createSuperUserRole(orgId: string) {
|
||||||
const actionIds = await db.select().from(actions).execute();
|
const actionIds = await db.select().from(actions).execute();
|
||||||
|
|
||||||
if (actionIds.length === 0) {
|
if (actionIds.length === 0) {
|
||||||
logger.info('No actions to assign to the Super User role');
|
logger.info("No actions to assign to the Admin role");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.insert(roleActions)
|
await db
|
||||||
.values(actionIds.map(action => ({ roleId, actionId: action.actionId, orgId })))
|
.insert(roleActions)
|
||||||
|
.values(
|
||||||
|
actionIds.map((action) => ({
|
||||||
|
roleId,
|
||||||
|
actionId: action.actionId,
|
||||||
|
orgId,
|
||||||
|
}))
|
||||||
|
)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
return roleId;
|
return roleId;
|
||||||
|
|
|
@ -99,6 +99,7 @@ export const userOrgs = sqliteTable("userOrgs", {
|
||||||
roleId: integer("roleId")
|
roleId: integer("roleId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => roles.roleId),
|
.references(() => roles.roleId),
|
||||||
|
isOwner: integer("isOwner", { mode: "boolean" }).notNull().default(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const emailVerificationCodes = sqliteTable("emailVerificationCodes", {
|
export const emailVerificationCodes = sqliteTable("emailVerificationCodes", {
|
||||||
|
@ -131,7 +132,7 @@ export const roles = sqliteTable("roles", {
|
||||||
orgId: text("orgId").references(() => orgs.orgId, {
|
orgId: text("orgId").references(() => orgs.orgId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
isSuperUserRole: integer("isSuperUserRole", { mode: "boolean" }),
|
isAdmin: integer("isAdmin", { mode: "boolean" }),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
description: text("description"),
|
description: text("description"),
|
||||||
});
|
});
|
||||||
|
@ -241,3 +242,4 @@ export type RoleResource = InferSelectModel<typeof roleResources>;
|
||||||
export type UserResource = InferSelectModel<typeof userResources>;
|
export type UserResource = InferSelectModel<typeof userResources>;
|
||||||
export type Limit = InferSelectModel<typeof limitsTable>;
|
export type Limit = InferSelectModel<typeof limitsTable>;
|
||||||
export type UserInvite = InferSelectModel<typeof userInvites>;
|
export type UserInvite = InferSelectModel<typeof userInvites>;
|
||||||
|
export type UserOrg = InferSelectModel<typeof userOrgs>;
|
||||||
|
|
|
@ -12,9 +12,9 @@ import {
|
||||||
} from "@server/middlewares";
|
} from "@server/middlewares";
|
||||||
import internal from "@server/routers/internal";
|
import internal from "@server/routers/internal";
|
||||||
import { authenticated, unauthenticated } from "@server/routers/external";
|
import { authenticated, unauthenticated } from "@server/routers/external";
|
||||||
import { router as wsRouter, handleWSUpgrade } from '@server/routers/ws';
|
import { router as wsRouter, handleWSUpgrade } from "@server/routers/ws";
|
||||||
import cookieParser from "cookie-parser";
|
import cookieParser from "cookie-parser";
|
||||||
import { User } from "@server/db/schema";
|
import { User, UserOrg } from "@server/db/schema";
|
||||||
import { ensureActions } from "./db/ensureActions";
|
import { ensureActions } from "./db/ensureActions";
|
||||||
import { logIncomingMiddleware } from "./middlewares/logIncoming";
|
import { logIncomingMiddleware } from "./middlewares/logIncoming";
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ declare global {
|
||||||
namespace Express {
|
namespace Express {
|
||||||
interface Request {
|
interface Request {
|
||||||
user?: User;
|
user?: User;
|
||||||
|
userOrg?: UserOrg;
|
||||||
userOrgRoleId?: number;
|
userOrgRoleId?: number;
|
||||||
userOrgId?: string;
|
userOrgId?: string;
|
||||||
userOrgIds?: string[];
|
userOrgIds?: string[];
|
||||||
|
|
|
@ -11,7 +11,7 @@ export * from "./verifyResourceAccess";
|
||||||
export * from "./verifyTargetAccess";
|
export * from "./verifyTargetAccess";
|
||||||
export * from "./verifyRoleAccess";
|
export * from "./verifyRoleAccess";
|
||||||
export * from "./verifyUserAccess";
|
export * from "./verifyUserAccess";
|
||||||
export * from "./verifySuperUser";
|
export * from "./verifyAdmin";
|
||||||
export * from "./verifyEmail";
|
export * from "./verifyEmail";
|
||||||
export * from "./requestEmailVerificationCode";
|
export * from "./requestEmailVerificationCode";
|
||||||
export * from "./changePassword";
|
export * from "./changePassword";
|
||||||
|
|
63
server/routers/auth/verifyAdmin.ts
Normal file
63
server/routers/auth/verifyAdmin.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
import { db } from "@server/db";
|
||||||
|
import { roles, userOrgs } from "@server/db/schema";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
|
export async function verifyAdmin(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const userId = req.user?.userId;
|
||||||
|
const orgId = req.userOrgId;
|
||||||
|
let userOrg = req.userOrg;
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User does not have orgId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userOrg) {
|
||||||
|
const userOrgRes = await db
|
||||||
|
.select()
|
||||||
|
.from(userOrgs)
|
||||||
|
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId!)))
|
||||||
|
.limit(1);
|
||||||
|
userOrg = userOrgRes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userOrg) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userRole = await db
|
||||||
|
.select()
|
||||||
|
.from(roles)
|
||||||
|
.where(eq(roles.roleId, userOrg.roleId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (userRole.length === 0 || !userRole[0].isAdmin) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have Admin access"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
|
@ -4,15 +4,15 @@ import { userOrgs } from "@server/db/schema";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { AuthenticatedRequest } from "@server/types/Auth";
|
|
||||||
|
|
||||||
export function verifyOrgAccess(
|
export async function verifyOrgAccess(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) {
|
) {
|
||||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
const userId = req.user!.userId;
|
||||||
const orgId = req.params.orgId;
|
const orgId = req.params.orgId;
|
||||||
|
let userOrg = req.userOrg;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(
|
return next(
|
||||||
|
@ -26,11 +26,18 @@ export function verifyOrgAccess(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.select()
|
try {
|
||||||
|
if (!userOrg) {
|
||||||
|
const userOrgRes = await db
|
||||||
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
|
.where(
|
||||||
.then((result) => {
|
and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId))
|
||||||
if (result.length === 0) {
|
);
|
||||||
|
userOrg = userOrgRes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userOrg) {
|
||||||
next(
|
next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
|
@ -39,17 +46,16 @@ export function verifyOrgAccess(
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// User has access, attach the user's role to the request for potential future use
|
// User has access, attach the user's role to the request for potential future use
|
||||||
req.userOrgRoleId = result[0].roleId;
|
req.userOrgRoleId = userOrg.roleId;
|
||||||
req.userOrgId = orgId;
|
req.userOrgId = orgId;
|
||||||
next();
|
return next();
|
||||||
}
|
}
|
||||||
})
|
} catch (e) {
|
||||||
.catch((error) => {
|
return next(
|
||||||
next(
|
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
"Error verifying organization access"
|
"Error verifying organization access"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,85 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { resources, userOrgs, userResources, roleResources } from '@server/db/schema';
|
import {
|
||||||
import { and, eq } from 'drizzle-orm';
|
resources,
|
||||||
import createHttpError from 'http-errors';
|
userOrgs,
|
||||||
import HttpCode from '@server/types/HttpCode';
|
userResources,
|
||||||
|
roleResources,
|
||||||
|
} from "@server/db/schema";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
export async function verifyResourceAccess(req: Request, res: Response, next: NextFunction) {
|
export async function verifyResourceAccess(
|
||||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
req: Request,
|
||||||
const resourceId = req.params.resourceId || req.body.resourceId || req.query.resourceId;
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const userId = req.user!.userId;
|
||||||
|
const resourceId =
|
||||||
|
req.params.resourceId || req.body.resourceId || req.query.resourceId;
|
||||||
|
let userOrg = req.userOrg;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get the resource
|
const resource = await db
|
||||||
const resource = await db.select()
|
.select()
|
||||||
.from(resources)
|
.from(resources)
|
||||||
.where(eq(resources.resourceId, resourceId))
|
.where(eq(resources.resourceId, resourceId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (resource.length === 0) {
|
if (resource.length === 0) {
|
||||||
return next(createHttpError(HttpCode.NOT_FOUND, `Resource with ID ${resourceId} not found`));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Resource with ID ${resourceId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resource[0].orgId) {
|
if (!resource[0].orgId) {
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, `Resource with ID ${resourceId} does not have an organization ID`));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
`Resource with ID ${resourceId} does not have an organization ID`
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user's role ID in the organization
|
if (!userOrg) {
|
||||||
const userOrgRole = await db.select()
|
const userOrgRole = await db
|
||||||
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, resource[0].orgId)))
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userOrgs.userId, userId),
|
||||||
|
eq(userOrgs.orgId, resource[0].orgId)
|
||||||
|
)
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
userOrg = userOrgRole[0];
|
||||||
if (userOrgRole.length === 0) {
|
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const userOrgRoleId = userOrgRole[0].roleId;
|
if (!userOrg) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userOrgRoleId = userOrg.roleId;
|
||||||
req.userOrgRoleId = userOrgRoleId;
|
req.userOrgRoleId = userOrgRoleId;
|
||||||
req.userOrgId = resource[0].orgId;
|
req.userOrgId = resource[0].orgId;
|
||||||
|
|
||||||
// Check role-based resource access first
|
const roleResourceAccess = await db
|
||||||
const roleResourceAccess = await db.select()
|
.select()
|
||||||
.from(roleResources)
|
.from(roleResources)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
|
@ -54,25 +90,36 @@ export async function verifyResourceAccess(req: Request, res: Response, next: Ne
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (roleResourceAccess.length > 0) {
|
if (roleResourceAccess.length > 0) {
|
||||||
// User's role has access to the resource
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If role doesn't have access, check user-specific resource access
|
const userResourceAccess = await db
|
||||||
const userResourceAccess = await db.select()
|
.select()
|
||||||
.from(userResources)
|
.from(userResources)
|
||||||
.where(and(eq(userResources.userId, userId), eq(userResources.resourceId, resourceId)))
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userResources.userId, userId),
|
||||||
|
eq(userResources.resourceId, resourceId)
|
||||||
|
)
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (userResourceAccess.length > 0) {
|
if (userResourceAccess.length > 0) {
|
||||||
// User has direct access to the resource
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reach here, the user doesn't have access to the resource
|
return next(
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this resource'));
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying resource access'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"Error verifying resource access"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,82 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { roles, userOrgs } from '@server/db/schema';
|
import { roles, userOrgs } from "@server/db/schema";
|
||||||
import { and, eq } from 'drizzle-orm';
|
import { and, eq } from "drizzle-orm";
|
||||||
import createHttpError from 'http-errors';
|
import createHttpError from "http-errors";
|
||||||
import HttpCode from '@server/types/HttpCode';
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import logger from '@server/logger';
|
import logger from "@server/logger";
|
||||||
|
|
||||||
export async function verifyRoleAccess(req: Request, res: Response, next: NextFunction) {
|
export async function verifyRoleAccess(
|
||||||
const userId = req.user?.userId; // Assuming you have user information in the request
|
req: Request,
|
||||||
const roleId = parseInt(req.params.roleId || req.body.roleId || req.query.roleId);
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const userId = req.user?.userId;
|
||||||
|
const roleId = parseInt(
|
||||||
|
req.params.roleId || req.body.roleId || req.query.roleId
|
||||||
|
);
|
||||||
|
let userOrg = req.userOrg;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNaN(roleId)) {
|
if (isNaN(roleId)) {
|
||||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid role ID'));
|
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid role ID"));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if the role exists and belongs to the specified organization
|
const role = await db
|
||||||
const role = await db.select()
|
.select()
|
||||||
.from(roles)
|
.from(roles)
|
||||||
.where(eq(roles.roleId, roleId))
|
.where(eq(roles.roleId, roleId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (role.length === 0) {
|
if (role.length === 0) {
|
||||||
return next(createHttpError(HttpCode.NOT_FOUND, `Role with ID ${roleId} not found`));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Role with ID ${roleId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user has a role in the organization
|
if (!userOrg) {
|
||||||
const userOrgRole = await db.select()
|
const userOrgRole = await db
|
||||||
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, role[0].orgId!)))
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userOrgs.userId, userId),
|
||||||
|
eq(userOrgs.orgId, role[0].orgId!)
|
||||||
|
)
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
userOrg = userOrgRole[0];
|
||||||
if (userOrgRole.length === 0) {
|
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req.userOrgRoleId = userOrgRole[0].roleId;
|
if (!userOrg) {
|
||||||
req.userOrgId = userOrgRole[0].orgId;
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
req.userOrgRoleId = userOrg.roleId;
|
||||||
|
req.userOrgId = userOrg.orgId;
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error verifying role access:', error);
|
logger.error("Error verifying role access:", error);
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"Error verifying role access"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,81 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { sites, userOrgs, userSites, roleSites, roles } from '@server/db/schema';
|
import {
|
||||||
import { and, eq, or } from 'drizzle-orm';
|
sites,
|
||||||
import createHttpError from 'http-errors';
|
userOrgs,
|
||||||
import HttpCode from '@server/types/HttpCode';
|
userSites,
|
||||||
|
roleSites,
|
||||||
|
roles,
|
||||||
|
} from "@server/db/schema";
|
||||||
|
import { and, eq, or } from "drizzle-orm";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
export async function verifySiteAccess(req: Request, res: Response, next: NextFunction) {
|
export async function verifySiteAccess(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
const userId = req.user!.userId; // Assuming you have user information in the request
|
||||||
const siteId = parseInt(req.params.siteId || req.body.siteId || req.query.siteId);
|
const siteId = parseInt(
|
||||||
|
req.params.siteId || req.body.siteId || req.query.siteId
|
||||||
|
);
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNaN(siteId)) {
|
if (isNaN(siteId)) {
|
||||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid site ID'));
|
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid site ID"));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get the site
|
// Get the site
|
||||||
const site = await db.select().from(sites).where(eq(sites.siteId, siteId)).limit(1);
|
const site = await db
|
||||||
|
.select()
|
||||||
|
.from(sites)
|
||||||
|
.where(eq(sites.siteId, siteId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
if (site.length === 0) {
|
if (site.length === 0) {
|
||||||
return next(createHttpError(HttpCode.NOT_FOUND, `Site with ID ${siteId} not found`));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Site with ID ${siteId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!site[0].orgId) {
|
if (!site[0].orgId) {
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, `Site with ID ${siteId} does not have an organization ID`));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
`Site with ID ${siteId} does not have an organization ID`
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user's role ID in the organization
|
// Get user's role ID in the organization
|
||||||
const userOrgRole = await db.select()
|
const userOrgRole = await db
|
||||||
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, site[0].orgId)))
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userOrgs.userId, userId),
|
||||||
|
eq(userOrgs.orgId, site[0].orgId)
|
||||||
|
)
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (userOrgRole.length === 0) {
|
if (userOrgRole.length === 0) {
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userOrgRoleId = userOrgRole[0].roleId;
|
const userOrgRoleId = userOrgRole[0].roleId;
|
||||||
|
@ -44,7 +83,8 @@ export async function verifySiteAccess(req: Request, res: Response, next: NextFu
|
||||||
req.userOrgId = site[0].orgId;
|
req.userOrgId = site[0].orgId;
|
||||||
|
|
||||||
// Check role-based site access first
|
// Check role-based site access first
|
||||||
const roleSiteAccess = await db.select()
|
const roleSiteAccess = await db
|
||||||
|
.select()
|
||||||
.from(roleSites)
|
.from(roleSites)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
|
@ -60,9 +100,12 @@ export async function verifySiteAccess(req: Request, res: Response, next: NextFu
|
||||||
}
|
}
|
||||||
|
|
||||||
// If role doesn't have access, check user-specific site access
|
// If role doesn't have access, check user-specific site access
|
||||||
const userSiteAccess = await db.select()
|
const userSiteAccess = await db
|
||||||
|
.select()
|
||||||
.from(userSites)
|
.from(userSites)
|
||||||
.where(and(eq(userSites.userId, userId), eq(userSites.siteId, siteId)))
|
.where(
|
||||||
|
and(eq(userSites.userId, userId), eq(userSites.siteId, siteId))
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (userSiteAccess.length > 0) {
|
if (userSiteAccess.length > 0) {
|
||||||
|
@ -71,9 +114,18 @@ export async function verifySiteAccess(req: Request, res: Response, next: NextFu
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reach here, the user doesn't have access to the site
|
// If we reach here, the user doesn't have access to the site
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this site'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this site"
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying site access'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"Error verifying site access"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
|
||||||
import { db } from '@server/db';
|
|
||||||
import { roles, userOrgs } from '@server/db/schema';
|
|
||||||
import { and, eq } from 'drizzle-orm';
|
|
||||||
import createHttpError from 'http-errors';
|
|
||||||
import HttpCode from '@server/types/HttpCode';
|
|
||||||
import logger from '@server/logger';
|
|
||||||
|
|
||||||
export async function verifySuperUser(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const userId = req.user?.userId; // Assuming you have user information in the request
|
|
||||||
const orgId = req.userOrgId;
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User does not have orgId'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Check if the user has a role in the organization
|
|
||||||
const userOrgRole = await db.select()
|
|
||||||
.from(userOrgs)
|
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId!)))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (userOrgRole.length === 0) {
|
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get userOrgRole[0].roleId
|
|
||||||
// Check if the user's role in the organization is a Super User role
|
|
||||||
const userRole = await db.select()
|
|
||||||
.from(roles)
|
|
||||||
.where(eq(roles.roleId, userOrgRole[0].roleId))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (userRole.length === 0 || !userRole[0].isSuperUserRole) {
|
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have Super User access'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error verifying role access:', error);
|
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +1,33 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { resources, targets, userOrgs } from '@server/db/schema';
|
import { resources, targets, userOrgs } from "@server/db/schema";
|
||||||
import { and, eq } from 'drizzle-orm';
|
import { and, eq } from "drizzle-orm";
|
||||||
import createHttpError from 'http-errors';
|
import createHttpError from "http-errors";
|
||||||
import HttpCode from '@server/types/HttpCode';
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
export async function verifyTargetAccess(req: Request, res: Response, next: NextFunction) {
|
export async function verifyTargetAccess(
|
||||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
const userId = req.user!.userId;
|
||||||
const targetId = parseInt(req.params.targetId);
|
const targetId = parseInt(req.params.targetId);
|
||||||
|
let userOrg = req.userOrg;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNaN(targetId)) {
|
if (isNaN(targetId)) {
|
||||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid organization ID'));
|
return next(
|
||||||
|
createHttpError(HttpCode.BAD_REQUEST, "Invalid organization ID")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = await db.select()
|
const target = await db
|
||||||
|
.select()
|
||||||
.from(targets)
|
.from(targets)
|
||||||
.where(eq(targets.targetId, targetId))
|
.where(eq(targets.targetId, targetId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
@ -42,7 +52,9 @@ export async function verifyTargetAccess(req: Request, res: Response, next: Next
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const resource = await db.select()
|
try {
|
||||||
|
const resource = await db
|
||||||
|
.select()
|
||||||
.from(resources)
|
.from(resources)
|
||||||
.where(eq(resources.resourceId, resourceId!))
|
.where(eq(resources.resourceId, resourceId!))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
@ -51,7 +63,7 @@ export async function verifyTargetAccess(req: Request, res: Response, next: Next
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.NOT_FOUND,
|
HttpCode.NOT_FOUND,
|
||||||
`resource with ID ${resourceId} not found`
|
`Resource with ID ${resourceId} not found`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -65,20 +77,37 @@ export async function verifyTargetAccess(req: Request, res: Response, next: Next
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.select()
|
if (!userOrg) {
|
||||||
|
const res = await db
|
||||||
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, resource[0].orgId)))
|
.where(
|
||||||
.then((result) => {
|
and(
|
||||||
if (result.length === 0) {
|
eq(userOrgs.userId, userId),
|
||||||
next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
eq(userOrgs.orgId, resource[0].orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
userOrg = res[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userOrg) {
|
||||||
|
next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// User has access, attach the user's role to the request for potential future use
|
req.userOrgRoleId = userOrg.roleId;
|
||||||
req.userOrgRoleId = result[0].roleId;
|
|
||||||
req.userOrgId = resource[0].orgId!;
|
req.userOrgId = resource[0].orgId!;
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
})
|
} catch (e) {
|
||||||
.catch((error) => {
|
return next(
|
||||||
next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying organization access'));
|
createHttpError(
|
||||||
});
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"Error verifying organization access"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ export type VerifyTotpResponse = {
|
||||||
export async function verifyTotp(
|
export async function verifyTotp(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction,
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const parsedBody = verifyTotpBody.safeParse(req.body);
|
const parsedBody = verifyTotpBody.safeParse(req.body);
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ export async function verifyTotp(
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.BAD_REQUEST,
|
HttpCode.BAD_REQUEST,
|
||||||
fromError(parsedBody.error).toString(),
|
fromError(parsedBody.error).toString()
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ export async function verifyTotp(
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.BAD_REQUEST,
|
HttpCode.BAD_REQUEST,
|
||||||
"Two-factor authentication is already enabled",
|
"Two-factor authentication is already enabled"
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,13 +55,17 @@ export async function verifyTotp(
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.BAD_REQUEST,
|
HttpCode.BAD_REQUEST,
|
||||||
"User has not requested two-factor authentication",
|
"User has not requested two-factor authentication"
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const valid = await verifyTotpCode(code, user.twoFactorSecret, user.userId);
|
const valid = await verifyTotpCode(
|
||||||
|
code,
|
||||||
|
user.twoFactorSecret,
|
||||||
|
user.userId
|
||||||
|
);
|
||||||
|
|
||||||
let codes;
|
let codes;
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
@ -101,8 +105,8 @@ export async function verifyTotp(
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
"Failed to verify two-factor authentication code",
|
"Failed to verify two-factor authentication code"
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import {
|
import { userOrgs } from "@server/db/schema";
|
||||||
sites,
|
|
||||||
userOrgs,
|
|
||||||
userSites,
|
|
||||||
roleSites,
|
|
||||||
roles,
|
|
||||||
} from "@server/db/schema";
|
|
||||||
import { and, eq, or } from "drizzle-orm";
|
import { and, eq, or } from "drizzle-orm";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
@ -16,9 +10,11 @@ export async function verifyUserAccess(
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) {
|
) {
|
||||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
const userId = req.user!.userId;
|
||||||
const reqUserId = req.params.userId || req.body.userId || req.query.userId;
|
const reqUserId = req.params.userId || req.body.userId || req.query.userId;
|
||||||
|
|
||||||
|
let userOrg = req.userOrg;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
@ -30,7 +26,8 @@ export async function verifyUserAccess(
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userOrg = await db
|
if (!userOrg) {
|
||||||
|
const res = await db
|
||||||
.select()
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(
|
.where(
|
||||||
|
@ -40,8 +37,10 @@ export async function verifyUserAccess(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
userOrg = res[0];
|
||||||
|
}
|
||||||
|
|
||||||
if (userOrg.length === 0) {
|
if (userOrg) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
|
|
|
@ -1,31 +1,51 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { db } from '@server/db';
|
import createHttpError from "http-errors";
|
||||||
import { roles, userOrgs } from '@server/db/schema';
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { and, eq } from 'drizzle-orm';
|
import logger from "@server/logger";
|
||||||
import createHttpError from 'http-errors';
|
|
||||||
import HttpCode from '@server/types/HttpCode';
|
|
||||||
import logger from '@server/logger';
|
|
||||||
|
|
||||||
export async function verifyUserInRole(req: Request, res: Response, next: NextFunction) {
|
export async function verifyUserInRole(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const roleId = parseInt(req.params.roleId || req.body.roleId || req.query.roleId);
|
const roleId = parseInt(
|
||||||
|
req.params.roleId || req.body.roleId || req.query.roleId
|
||||||
|
);
|
||||||
const userRoleId = req.userOrgRoleId;
|
const userRoleId = req.userOrgRoleId;
|
||||||
|
|
||||||
if (isNaN(roleId)) {
|
if (isNaN(roleId)) {
|
||||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid role ID'));
|
return next(
|
||||||
|
createHttpError(HttpCode.BAD_REQUEST, "Invalid role ID")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userRoleId) {
|
if (!userRoleId) {
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userRoleId !== roleId) {
|
if (userRoleId !== roleId) {
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this role'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have access to this role"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error verifying role access:', error);
|
logger.error("Error verifying role access:", error);
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"Error verifying role access"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ import {
|
||||||
verifyResourceAccess,
|
verifyResourceAccess,
|
||||||
verifyTargetAccess,
|
verifyTargetAccess,
|
||||||
verifyRoleAccess,
|
verifyRoleAccess,
|
||||||
verifySuperUser,
|
verifyAdmin,
|
||||||
verifyUserInRole,
|
verifyUserInRole,
|
||||||
verifyUserAccess,
|
verifyUserAccess,
|
||||||
} from "./auth";
|
} from "./auth";
|
||||||
|
@ -121,7 +121,7 @@ authenticated.delete(
|
||||||
// authenticated.put(
|
// authenticated.put(
|
||||||
// "/org/:orgId/role",
|
// "/org/:orgId/role",
|
||||||
// verifyOrgAccess,
|
// verifyOrgAccess,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.createRole
|
// role.createRole
|
||||||
// );
|
// );
|
||||||
// authenticated.get("/org/:orgId/roles", verifyOrgAccess, role.listRoles);
|
// authenticated.get("/org/:orgId/roles", verifyOrgAccess, role.listRoles);
|
||||||
|
@ -134,13 +134,13 @@ authenticated.delete(
|
||||||
// authenticated.post(
|
// authenticated.post(
|
||||||
// "/role/:roleId",
|
// "/role/:roleId",
|
||||||
// verifyRoleAccess,
|
// verifyRoleAccess,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.updateRole
|
// role.updateRole
|
||||||
// );
|
// );
|
||||||
// authenticated.delete(
|
// authenticated.delete(
|
||||||
// "/role/:roleId",
|
// "/role/:roleId",
|
||||||
// verifyRoleAccess,
|
// verifyRoleAccess,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.deleteRole
|
// role.deleteRole
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
@ -190,14 +190,14 @@ authenticated.delete(
|
||||||
// "/role/:roleId/action",
|
// "/role/:roleId/action",
|
||||||
// verifyRoleAccess,
|
// verifyRoleAccess,
|
||||||
// verifyUserInRole,
|
// verifyUserInRole,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.removeRoleAction
|
// role.removeRoleAction
|
||||||
// );
|
// );
|
||||||
// authenticated.get(
|
// authenticated.get(
|
||||||
// "/role/:roleId/actions",
|
// "/role/:roleId/actions",
|
||||||
// verifyRoleAccess,
|
// verifyRoleAccess,
|
||||||
// verifyUserInRole,
|
// verifyUserInRole,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.listRoleActions
|
// role.listRoleActions
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
@ -239,14 +239,14 @@ authenticated.delete(
|
||||||
// "/org/:orgId/user/:userId/action",
|
// "/org/:orgId/user/:userId/action",
|
||||||
// verifyOrgAccess,
|
// verifyOrgAccess,
|
||||||
// verifyUserAccess,
|
// verifyUserAccess,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.addRoleAction
|
// role.addRoleAction
|
||||||
// );
|
// );
|
||||||
// authenticated.delete(
|
// authenticated.delete(
|
||||||
// "/org/:orgId/user/:userId/action",
|
// "/org/:orgId/user/:userId/action",
|
||||||
// verifyOrgAccess,
|
// verifyOrgAccess,
|
||||||
// verifyUserAccess,
|
// verifyUserAccess,
|
||||||
// verifySuperUser,
|
// verifyAdmin,
|
||||||
// role.removeRoleAction
|
// role.removeRoleAction
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from "drizzle-orm";
|
||||||
import { orgs, userOrgs } from '@server/db/schema';
|
import { orgs, userOrgs } from "@server/db/schema";
|
||||||
import response from "@server/utils/response";
|
import response from "@server/utils/response";
|
||||||
import HttpCode from '@server/types/HttpCode';
|
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';
|
import { createAdminRole } from "@server/db/ensureActions";
|
||||||
import config, { APP_PATH } from "@server/config";
|
import config, { APP_PATH } from "@server/config";
|
||||||
import { fromError } from 'zod-validation-error';
|
import { fromError } from "zod-validation-error";
|
||||||
|
|
||||||
const createOrgSchema = z.object({
|
const createOrgSchema = z.object({
|
||||||
orgId: z.string(),
|
orgId: z.string(),
|
||||||
|
@ -20,7 +20,11 @@ const createOrgSchema = z.object({
|
||||||
|
|
||||||
const MAX_ORGS = 5;
|
const MAX_ORGS = 5;
|
||||||
|
|
||||||
export async function createOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function createOrg(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedBody = createOrgSchema.safeParse(req.body);
|
const parsedBody = createOrgSchema.safeParse(req.body);
|
||||||
if (!parsedBody.success) {
|
if (!parsedBody.success) {
|
||||||
|
@ -52,7 +56,8 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
||||||
const { orgId, name } = parsedBody.data;
|
const { orgId, name } = parsedBody.data;
|
||||||
|
|
||||||
// make sure the orgId is unique
|
// make sure the orgId is unique
|
||||||
const orgExists = await db.select()
|
const orgExists = await db
|
||||||
|
.select()
|
||||||
.from(orgs)
|
.from(orgs)
|
||||||
.where(eq(orgs.orgId, orgId))
|
.where(eq(orgs.orgId, orgId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
@ -69,29 +74,34 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
||||||
// create a url from config.app.base_url and get the hostname
|
// create a url from config.app.base_url and get the hostname
|
||||||
const domain = new URL(config.app.base_url).hostname;
|
const domain = new URL(config.app.base_url).hostname;
|
||||||
|
|
||||||
const newOrg = await db.insert(orgs).values({
|
const newOrg = await db
|
||||||
|
.insert(orgs)
|
||||||
|
.values({
|
||||||
orgId,
|
orgId,
|
||||||
name,
|
name,
|
||||||
domain
|
domain,
|
||||||
}).returning();
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
const roleId = await createSuperUserRole(newOrg[0].orgId);
|
const roleId = await createAdminRole(newOrg[0].orgId);
|
||||||
|
|
||||||
if (!roleId) {
|
if (!roleId) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
`Error creating Super User role`
|
`Error creating Admin role`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// put the user in the super user role
|
await db
|
||||||
await db.insert(userOrgs).values({
|
.insert(userOrgs)
|
||||||
|
.values({
|
||||||
userId: req.user!.userId,
|
userId: req.user!.userId,
|
||||||
orgId: newOrg[0].orgId,
|
orgId: newOrg[0].orgId,
|
||||||
roleId: roleId,
|
roleId: roleId,
|
||||||
}).execute();
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: newOrg[0],
|
data: newOrg[0],
|
||||||
|
@ -102,6 +112,11 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"An error occurred..."
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { orgs } from '@server/db/schema';
|
import { orgs, userActions } from "@server/db/schema";
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/utils/response";
|
import response from "@server/utils/response";
|
||||||
import HttpCode from '@server/types/HttpCode';
|
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 { fromError } from 'zod-validation-error';
|
import { fromError } from "zod-validation-error";
|
||||||
|
|
||||||
const deleteOrgSchema = z.object({
|
const deleteOrgSchema = z.object({
|
||||||
orgId: z.string()
|
orgId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function deleteOrg(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = deleteOrgSchema.safeParse(req.params);
|
const parsedParams = deleteOrgSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -28,13 +32,22 @@ export async function deleteOrg(req: Request, res: Response, next: NextFunction)
|
||||||
|
|
||||||
const { orgId } = parsedParams.data;
|
const { orgId } = parsedParams.data;
|
||||||
|
|
||||||
// Check if the user has permission to list sites
|
// // Check if the user has permission to list sites
|
||||||
const hasPermission = await checkUserActionPermission(ActionsEnum.deleteOrg, req);
|
// const hasPermission = await checkUserActionPermission(
|
||||||
if (!hasPermission) {
|
// ActionsEnum.deleteOrg,
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
|
// req
|
||||||
}
|
// );
|
||||||
|
// if (!hasPermission) {
|
||||||
|
// return next(
|
||||||
|
// createHttpError(
|
||||||
|
// HttpCode.FORBIDDEN,
|
||||||
|
// "User does not have permission to perform this action"
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
const deletedOrg = await db.delete(orgs)
|
const deletedOrg = await db
|
||||||
|
.delete(orgs)
|
||||||
.where(eq(orgs.orgId, orgId))
|
.where(eq(orgs.orgId, orgId))
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
@ -56,6 +69,11 @@ export async function deleteOrg(req: Request, res: Response, next: NextFunction)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"An error occurred..."
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,29 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { db } from '@server/db';
|
import { db } from "@server/db";
|
||||||
import { orgs, resources, roleResources, roles, userResources } from '@server/db/schema';
|
import {
|
||||||
|
orgs,
|
||||||
|
resources,
|
||||||
|
roleResources,
|
||||||
|
roles,
|
||||||
|
userResources,
|
||||||
|
} from "@server/db/schema";
|
||||||
import response from "@server/utils/response";
|
import response from "@server/utils/response";
|
||||||
import HttpCode from '@server/types/HttpCode';
|
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 { eq, and } from 'drizzle-orm';
|
import { eq, and } from "drizzle-orm";
|
||||||
import stoi from '@server/utils/stoi';
|
import stoi from "@server/utils/stoi";
|
||||||
import { fromError } from 'zod-validation-error';
|
import { fromError } from "zod-validation-error";
|
||||||
|
|
||||||
const createResourceParamsSchema = z.object({
|
const createResourceParamsSchema = z.object({
|
||||||
siteId: z.string().optional().transform(stoi).pipe(z.number().int().positive().optional()),
|
siteId: z
|
||||||
orgId: z.string()
|
.string()
|
||||||
|
.optional()
|
||||||
|
.transform(stoi)
|
||||||
|
.pipe(z.number().int().positive().optional()),
|
||||||
|
orgId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define Zod schema for request body validation
|
// Define Zod schema for request body validation
|
||||||
|
@ -22,7 +32,11 @@ const createResourceSchema = z.object({
|
||||||
subdomain: z.string().min(1).max(255).optional(),
|
subdomain: z.string().min(1).max(255).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function createResource(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function createResource(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request body
|
// Validate request body
|
||||||
const parsedBody = createResourceSchema.safeParse(req.body);
|
const parsedBody = createResourceSchema.safeParse(req.body);
|
||||||
|
@ -51,17 +65,28 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
||||||
const { siteId, orgId } = parsedParams.data;
|
const { siteId, orgId } = parsedParams.data;
|
||||||
|
|
||||||
// Check if the user has permission to list sites
|
// Check if the user has permission to list sites
|
||||||
const hasPermission = await checkUserActionPermission(ActionsEnum.createResource, req);
|
const hasPermission = await checkUserActionPermission(
|
||||||
|
ActionsEnum.createResource,
|
||||||
|
req
|
||||||
|
);
|
||||||
if (!hasPermission) {
|
if (!hasPermission) {
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"User does not have permission to perform this action"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req.userOrgRoleId) {
|
if (!req.userOrgRoleId) {
|
||||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have a role'));
|
return next(
|
||||||
|
createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the org
|
// get the org
|
||||||
const org = await db.select()
|
const org = await db
|
||||||
|
.select()
|
||||||
.from(orgs)
|
.from(orgs)
|
||||||
.where(eq(orgs.orgId, orgId))
|
.where(eq(orgs.orgId, orgId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
@ -79,35 +104,35 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
||||||
const fullDomain = `${subdomain}.${org[0].domain}`;
|
const fullDomain = `${subdomain}.${org[0].domain}`;
|
||||||
|
|
||||||
// Create new resource in the database
|
// Create new resource in the database
|
||||||
const newResource = await db.insert(resources).values({
|
const newResource = await db
|
||||||
|
.insert(resources)
|
||||||
|
.values({
|
||||||
fullDomain,
|
fullDomain,
|
||||||
siteId,
|
siteId,
|
||||||
orgId,
|
orgId,
|
||||||
name,
|
name,
|
||||||
subdomain,
|
subdomain,
|
||||||
}).returning();
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
// find the Super User roleId and also add the resource to the Super User role
|
const adminRole = await db
|
||||||
const superUserRole = await db.select()
|
.select()
|
||||||
.from(roles)
|
.from(roles)
|
||||||
.where(and(eq(roles.isSuperUserRole, true), eq(roles.orgId, orgId)))
|
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (superUserRole.length === 0) {
|
if (adminRole.length === 0) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(HttpCode.NOT_FOUND, `Admin role not found`)
|
||||||
HttpCode.NOT_FOUND,
|
|
||||||
`Super User role not found`
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.insert(roleResources).values({
|
await db.insert(roleResources).values({
|
||||||
roleId: superUserRole[0].roleId,
|
roleId: adminRole[0].roleId,
|
||||||
resourceId: newResource[0].resourceId,
|
resourceId: newResource[0].resourceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (req.userOrgRoleId != superUserRole[0].roleId) {
|
if (req.userOrgRoleId != adminRole[0].roleId) {
|
||||||
// make sure the user can access the resource
|
// make sure the user can access the resource
|
||||||
await db.insert(userResources).values({
|
await db.insert(userResources).values({
|
||||||
userId: req.user?.userId!,
|
userId: req.user?.userId!,
|
||||||
|
@ -124,6 +149,11 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"An error occurred..."
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export async function listResourceRoles(
|
||||||
roleId: roles.roleId,
|
roleId: roles.roleId,
|
||||||
name: roles.name,
|
name: roles.name,
|
||||||
description: roles.description,
|
description: roles.description,
|
||||||
isSuperUserRole: roles.isSuperUserRole,
|
isAdmin: roles.isAdmin,
|
||||||
})
|
})
|
||||||
.from(roleResources)
|
.from(roleResources)
|
||||||
.innerJoin(roles, eq(roleResources.roleId, roles.roleId))
|
.innerJoin(roles, eq(roleResources.roleId, roles.roleId))
|
||||||
|
|
|
@ -61,11 +61,11 @@ export async function deleteRole(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role[0].isSuperUserRole) {
|
if (role[0].isAdmin) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
`Cannot delete a Super User role`
|
`Cannot delete a Admin role`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ export async function listRoles(
|
||||||
.select({
|
.select({
|
||||||
roleId: roles.roleId,
|
roleId: roles.roleId,
|
||||||
orgId: roles.orgId,
|
orgId: roles.orgId,
|
||||||
isSuperUserRole: roles.isSuperUserRole,
|
isAdmin: roles.isAdmin,
|
||||||
name: roles.name,
|
name: roles.name,
|
||||||
description: roles.description,
|
description: roles.description,
|
||||||
orgName: orgs.name,
|
orgName: orgs.name,
|
||||||
|
|
|
@ -81,11 +81,11 @@ export async function updateRole(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role[0].isSuperUserRole) {
|
if (role[0].isAdmin) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
`Cannot update a Super User role`
|
`Cannot update a Admin role`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,25 +107,24 @@ export async function createSite(
|
||||||
subnet,
|
subnet,
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
// find the Super User roleId and also add the resource to the Super User role
|
const adminRole = await db
|
||||||
const superUserRole = await db
|
|
||||||
.select()
|
.select()
|
||||||
.from(roles)
|
.from(roles)
|
||||||
.where(and(eq(roles.isSuperUserRole, true), eq(roles.orgId, orgId)))
|
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (superUserRole.length === 0) {
|
if (adminRole.length === 0) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(HttpCode.NOT_FOUND, `Super User role not found`)
|
createHttpError(HttpCode.NOT_FOUND, `Admin role not found`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.insert(roleSites).values({
|
await db.insert(roleSites).values({
|
||||||
roleId: superUserRole[0].roleId,
|
roleId: adminRole[0].roleId,
|
||||||
siteId: newSite.siteId,
|
siteId: newSite.siteId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (req.userOrgRoleId != superUserRole[0].roleId) {
|
if (req.userOrgRoleId != adminRole[0].roleId) {
|
||||||
// make sure the user can access the site
|
// make sure the user can access the site
|
||||||
db.insert(userSites).values({
|
db.insert(userSites).values({
|
||||||
userId: req.user?.userId!,
|
userId: req.user?.userId!,
|
||||||
|
|
|
@ -51,7 +51,7 @@ export async function listSiteRoles(
|
||||||
roleId: roles.roleId,
|
roleId: roles.roleId,
|
||||||
name: roles.name,
|
name: roles.name,
|
||||||
description: roles.description,
|
description: roles.description,
|
||||||
isSuperUserRole: roles.isSuperUserRole,
|
isAdmin: roles.isAdmin,
|
||||||
})
|
})
|
||||||
.from(roleSites)
|
.from(roleSites)
|
||||||
.innerJoin(roles, eq(roleSites.roleId, roles.roleId))
|
.innerJoin(roles, eq(roleSites.roleId, roles.roleId))
|
||||||
|
|
|
@ -57,13 +57,7 @@ export default function InviteUserForm({ open, setOpen }: InviteUserFormProps) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [expiresInDays, setExpiresInDays] = useState(1);
|
const [expiresInDays, setExpiresInDays] = useState(1);
|
||||||
|
|
||||||
const roles = [
|
const roles = [{ roleId: 1, name: "Admin" }];
|
||||||
{ roleId: 1, name: "Super User" },
|
|
||||||
{ roleId: 2, name: "Admin" },
|
|
||||||
{ roleId: 3, name: "Power User" },
|
|
||||||
{ roleId: 4, name: "User" },
|
|
||||||
{ roleId: 5, name: "Guest" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const validFor = [
|
const validFor = [
|
||||||
{ hours: 24, name: "1 day" },
|
{ hours: 24, name: "1 day" },
|
||||||
|
@ -122,13 +116,16 @@ export default function InviteUserForm({ open, setOpen }: InviteUserFormProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Credenza open={open} onOpenChange={(val) => {
|
<Credenza
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(val) => {
|
||||||
setOpen(val);
|
setOpen(val);
|
||||||
setInviteLink(null);
|
setInviteLink(null);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setExpiresInDays(1);
|
setExpiresInDays(1);
|
||||||
form.reset();
|
form.reset();
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<CredenzaContent>
|
<CredenzaContent>
|
||||||
<CredenzaHeader>
|
<CredenzaHeader>
|
||||||
<CredenzaTitle>Invite User</CredenzaTitle>
|
<CredenzaTitle>Invite User</CredenzaTitle>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue