mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-04 01:55:10 +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
|
@ -7,15 +7,19 @@ import logger from "@server/logger";
|
|||
export async function ensureActions() {
|
||||
const actionIds = Object.values(ActionsEnum);
|
||||
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 actionsToRemove = existingActionIds.filter(id => !actionIds.includes(id as ActionsEnum));
|
||||
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))
|
||||
.where(eq(roles.isAdmin, true))
|
||||
.execute();
|
||||
|
||||
// Add new actions
|
||||
|
@ -24,29 +28,42 @@ export async function ensureActions() {
|
|||
await db.insert(actions).values({ actionId }).execute();
|
||||
// Add new actions to the Default role
|
||||
if (defaultRoles.length != 0) {
|
||||
await db.insert(roleActions)
|
||||
.values(defaultRoles.map(role => ({ roleId: role.roleId!, actionId, orgId: role.orgId! })))
|
||||
await db
|
||||
.insert(roleActions)
|
||||
.values(
|
||||
defaultRoles.map((role) => ({
|
||||
roleId: role.roleId!,
|
||||
actionId,
|
||||
orgId: role.orgId!,
|
||||
}))
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deprecated actions
|
||||
if (actionsToRemove.length > 0) {
|
||||
logger.debug(`Removing actions: ${actionsToRemove.join(', ')}`);
|
||||
await db.delete(actions).where(inArray(actions.actionId, actionsToRemove)).execute();
|
||||
await db.delete(roleActions).where(inArray(roleActions.actionId, actionsToRemove)).execute();
|
||||
logger.debug(`Removing actions: ${actionsToRemove.join(", ")}`);
|
||||
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: string) {
|
||||
export async function createAdminRole(orgId: string) {
|
||||
// Create the Default role if it doesn't exist
|
||||
const [insertedRole] = await db
|
||||
.insert(roles)
|
||||
.values({
|
||||
orgId,
|
||||
isSuperUserRole: true,
|
||||
name: 'Super User',
|
||||
description: 'Super User role with all actions'
|
||||
isAdmin: true,
|
||||
name: "Admin",
|
||||
description: "Admin role most permissions",
|
||||
})
|
||||
.returning({ roleId: roles.roleId })
|
||||
.execute();
|
||||
|
@ -56,13 +73,20 @@ export async function createSuperUserRole(orgId: string) {
|
|||
const actionIds = await db.select().from(actions).execute();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
await db.insert(roleActions)
|
||||
.values(actionIds.map(action => ({ roleId, actionId: action.actionId, orgId })))
|
||||
await db
|
||||
.insert(roleActions)
|
||||
.values(
|
||||
actionIds.map((action) => ({
|
||||
roleId,
|
||||
actionId: action.actionId,
|
||||
orgId,
|
||||
}))
|
||||
)
|
||||
.execute();
|
||||
|
||||
return roleId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ export const userOrgs = sqliteTable("userOrgs", {
|
|||
roleId: integer("roleId")
|
||||
.notNull()
|
||||
.references(() => roles.roleId),
|
||||
isOwner: integer("isOwner", { mode: "boolean" }).notNull().default(false),
|
||||
});
|
||||
|
||||
export const emailVerificationCodes = sqliteTable("emailVerificationCodes", {
|
||||
|
@ -131,7 +132,7 @@ export const roles = sqliteTable("roles", {
|
|||
orgId: text("orgId").references(() => orgs.orgId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
isSuperUserRole: integer("isSuperUserRole", { mode: "boolean" }),
|
||||
isAdmin: integer("isAdmin", { mode: "boolean" }),
|
||||
name: text("name").notNull(),
|
||||
description: text("description"),
|
||||
});
|
||||
|
@ -241,3 +242,4 @@ export type RoleResource = InferSelectModel<typeof roleResources>;
|
|||
export type UserResource = InferSelectModel<typeof userResources>;
|
||||
export type Limit = InferSelectModel<typeof limitsTable>;
|
||||
export type UserInvite = InferSelectModel<typeof userInvites>;
|
||||
export type UserOrg = InferSelectModel<typeof userOrgs>;
|
||||
|
|
|
@ -12,9 +12,9 @@ import {
|
|||
} from "@server/middlewares";
|
||||
import internal from "@server/routers/internal";
|
||||
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 { User } from "@server/db/schema";
|
||||
import { User, UserOrg } from "@server/db/schema";
|
||||
import { ensureActions } from "./db/ensureActions";
|
||||
import { logIncomingMiddleware } from "./middlewares/logIncoming";
|
||||
|
||||
|
@ -52,15 +52,15 @@ app.prepare().then(() => {
|
|||
externalServer.use(prefix, unauthenticated);
|
||||
externalServer.use(prefix, authenticated);
|
||||
externalServer.use(`${prefix}/ws`, wsRouter);
|
||||
|
||||
|
||||
externalServer.use(notFoundMiddleware);
|
||||
|
||||
|
||||
// We are using NEXT from here on
|
||||
externalServer.all("*", (req: Request, res: Response) => {
|
||||
const parsedUrl = parse(req.url!, true);
|
||||
handle(req, res, parsedUrl);
|
||||
});
|
||||
|
||||
|
||||
const httpServer = externalServer.listen(externalPort, (err?: any) => {
|
||||
if (err) throw err;
|
||||
logger.info(
|
||||
|
@ -98,6 +98,7 @@ declare global {
|
|||
namespace Express {
|
||||
interface Request {
|
||||
user?: User;
|
||||
userOrg?: UserOrg;
|
||||
userOrgRoleId?: number;
|
||||
userOrgId?: string;
|
||||
userOrgIds?: string[];
|
||||
|
|
|
@ -11,7 +11,7 @@ export * from "./verifyResourceAccess";
|
|||
export * from "./verifyTargetAccess";
|
||||
export * from "./verifyRoleAccess";
|
||||
export * from "./verifyUserAccess";
|
||||
export * from "./verifySuperUser";
|
||||
export * from "./verifyAdmin";
|
||||
export * from "./verifyEmail";
|
||||
export * from "./requestEmailVerificationCode";
|
||||
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 createHttpError from "http-errors";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { AuthenticatedRequest } from "@server/types/Auth";
|
||||
|
||||
export function verifyOrgAccess(
|
||||
export async function verifyOrgAccess(
|
||||
req: Request,
|
||||
res: Response,
|
||||
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;
|
||||
let userOrg = req.userOrg;
|
||||
|
||||
if (!userId) {
|
||||
return next(
|
||||
|
@ -26,30 +26,36 @@ export function verifyOrgAccess(
|
|||
);
|
||||
}
|
||||
|
||||
db.select()
|
||||
.from(userOrgs)
|
||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
|
||||
.then((result) => {
|
||||
if (result.length === 0) {
|
||||
next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
"User does not have access to this organization"
|
||||
)
|
||||
try {
|
||||
if (!userOrg) {
|
||||
const userOrgRes = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId))
|
||||
);
|
||||
} else {
|
||||
// User has access, attach the user's role to the request for potential future use
|
||||
req.userOrgRoleId = result[0].roleId;
|
||||
req.userOrgId = orgId;
|
||||
next();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
userOrg = userOrgRes[0];
|
||||
}
|
||||
|
||||
if (!userOrg) {
|
||||
next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
"Error verifying organization access"
|
||||
HttpCode.FORBIDDEN,
|
||||
"User does not have access to this organization"
|
||||
)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// User has access, attach the user's role to the request for potential future use
|
||||
req.userOrgRoleId = userOrg.roleId;
|
||||
req.userOrgId = orgId;
|
||||
return next();
|
||||
}
|
||||
} catch (e) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
"Error verifying organization access"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,85 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import { db } from '@server/db';
|
||||
import { resources, userOrgs, userResources, roleResources } from '@server/db/schema';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import createHttpError from 'http-errors';
|
||||
import HttpCode from '@server/types/HttpCode';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { db } from "@server/db";
|
||||
import {
|
||||
resources,
|
||||
userOrgs,
|
||||
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) {
|
||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
||||
const resourceId = req.params.resourceId || req.body.resourceId || req.query.resourceId;
|
||||
export async function verifyResourceAccess(
|
||||
req: Request,
|
||||
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) {
|
||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
||||
return next(
|
||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the resource
|
||||
const resource = await db.select()
|
||||
const resource = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.where(eq(resources.resourceId, resourceId))
|
||||
.limit(1);
|
||||
|
||||
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) {
|
||||
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
|
||||
const userOrgRole = await db.select()
|
||||
.from(userOrgs)
|
||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, resource[0].orgId)))
|
||||
.limit(1);
|
||||
|
||||
if (userOrgRole.length === 0) {
|
||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
||||
if (!userOrg) {
|
||||
const userOrgRole = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, userId),
|
||||
eq(userOrgs.orgId, resource[0].orgId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
userOrg = userOrgRole[0];
|
||||
}
|
||||
|
||||
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.userOrgId = resource[0].orgId;
|
||||
|
||||
// Check role-based resource access first
|
||||
const roleResourceAccess = await db.select()
|
||||
const roleResourceAccess = await db
|
||||
.select()
|
||||
.from(roleResources)
|
||||
.where(
|
||||
and(
|
||||
|
@ -54,25 +90,36 @@ export async function verifyResourceAccess(req: Request, res: Response, next: Ne
|
|||
.limit(1);
|
||||
|
||||
if (roleResourceAccess.length > 0) {
|
||||
// User's role has access to the resource
|
||||
return next();
|
||||
}
|
||||
|
||||
// If role doesn't have access, check user-specific resource access
|
||||
const userResourceAccess = await db.select()
|
||||
const userResourceAccess = await db
|
||||
.select()
|
||||
.from(userResources)
|
||||
.where(and(eq(userResources.userId, userId), eq(userResources.resourceId, resourceId)))
|
||||
.where(
|
||||
and(
|
||||
eq(userResources.userId, userId),
|
||||
eq(userResources.resourceId, resourceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (userResourceAccess.length > 0) {
|
||||
// User has direct access to the resource
|
||||
return next();
|
||||
}
|
||||
|
||||
// If we reach here, the user doesn't have access to the resource
|
||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this resource'));
|
||||
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
"User does not have access to this resource"
|
||||
)
|
||||
);
|
||||
} 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 { 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';
|
||||
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 verifyRoleAccess(req: Request, res: Response, next: NextFunction) {
|
||||
const userId = req.user?.userId; // Assuming you have user information in the request
|
||||
const roleId = parseInt(req.params.roleId || req.body.roleId || req.query.roleId);
|
||||
export async function verifyRoleAccess(
|
||||
req: Request,
|
||||
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) {
|
||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
||||
return next(
|
||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||
);
|
||||
}
|
||||
|
||||
if (isNaN(roleId)) {
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid role ID'));
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid role ID"));
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if the role exists and belongs to the specified organization
|
||||
const role = await db.select()
|
||||
const role = await db
|
||||
.select()
|
||||
.from(roles)
|
||||
.where(eq(roles.roleId, roleId))
|
||||
.limit(1);
|
||||
|
||||
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
|
||||
const userOrgRole = await db.select()
|
||||
.from(userOrgs)
|
||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, role[0].orgId!)))
|
||||
.limit(1);
|
||||
|
||||
if (userOrgRole.length === 0) {
|
||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
||||
if (!userOrg) {
|
||||
const userOrgRole = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, userId),
|
||||
eq(userOrgs.orgId, role[0].orgId!)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
userOrg = userOrgRole[0];
|
||||
}
|
||||
|
||||
req.userOrgRoleId = userOrgRole[0].roleId;
|
||||
req.userOrgId = userOrgRole[0].orgId;
|
||||
if (!userOrg) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
"User does not have access to this organization"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
req.userOrgRoleId = userOrg.roleId;
|
||||
req.userOrgId = userOrg.orgId;
|
||||
|
||||
return next();
|
||||
} catch (error) {
|
||||
logger.error('Error verifying role access:', error);
|
||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
|
||||
logger.error("Error verifying role access:", error);
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
"Error verifying role access"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,81 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import { db } from '@server/db';
|
||||
import { sites, userOrgs, 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';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { db } from "@server/db";
|
||||
import {
|
||||
sites,
|
||||
userOrgs,
|
||||
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 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) {
|
||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
||||
return next(
|
||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||
);
|
||||
}
|
||||
|
||||
if (isNaN(siteId)) {
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid site ID'));
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid site ID"));
|
||||
}
|
||||
|
||||
try {
|
||||
// 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) {
|
||||
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) {
|
||||
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
|
||||
const userOrgRole = await db.select()
|
||||
const userOrgRole = await db
|
||||
.select()
|
||||
.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);
|
||||
|
||||
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;
|
||||
|
@ -44,7 +83,8 @@ export async function verifySiteAccess(req: Request, res: Response, next: NextFu
|
|||
req.userOrgId = site[0].orgId;
|
||||
|
||||
// Check role-based site access first
|
||||
const roleSiteAccess = await db.select()
|
||||
const roleSiteAccess = await db
|
||||
.select()
|
||||
.from(roleSites)
|
||||
.where(
|
||||
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
|
||||
const userSiteAccess = await db.select()
|
||||
const userSiteAccess = await db
|
||||
.select()
|
||||
.from(userSites)
|
||||
.where(and(eq(userSites.userId, userId), eq(userSites.siteId, siteId)))
|
||||
.where(
|
||||
and(eq(userSites.userId, userId), eq(userSites.siteId, siteId))
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
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
|
||||
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) {
|
||||
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 { db } from '@server/db';
|
||||
import { resources, targets, userOrgs } from '@server/db/schema';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import createHttpError from 'http-errors';
|
||||
import HttpCode from '@server/types/HttpCode';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { db } from "@server/db";
|
||||
import { resources, targets, 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 verifyTargetAccess(req: Request, res: Response, next: NextFunction) {
|
||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
||||
export async function verifyTargetAccess(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
const userId = req.user!.userId;
|
||||
const targetId = parseInt(req.params.targetId);
|
||||
let userOrg = req.userOrg;
|
||||
|
||||
if (!userId) {
|
||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
||||
return next(
|
||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||
);
|
||||
}
|
||||
|
||||
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)
|
||||
.where(eq(targets.targetId, targetId))
|
||||
.limit(1);
|
||||
|
@ -42,43 +52,62 @@ export async function verifyTargetAccess(req: Request, res: Response, next: Next
|
|||
);
|
||||
}
|
||||
|
||||
const resource = await db.select()
|
||||
.from(resources)
|
||||
.where(eq(resources.resourceId, resourceId!))
|
||||
.limit(1);
|
||||
try {
|
||||
const resource = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.where(eq(resources.resourceId, resourceId!))
|
||||
.limit(1);
|
||||
|
||||
if (resource.length === 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.NOT_FOUND,
|
||||
`resource with ID ${resourceId} not found`
|
||||
)
|
||||
);
|
||||
}
|
||||
if (resource.length === 0) {
|
||||
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`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!userOrg) {
|
||||
const res = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, userId),
|
||||
eq(userOrgs.orgId, resource[0].orgId)
|
||||
)
|
||||
);
|
||||
userOrg = res[0];
|
||||
}
|
||||
|
||||
if (!userOrg) {
|
||||
next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
"User does not have access to this organization"
|
||||
)
|
||||
);
|
||||
} else {
|
||||
req.userOrgRoleId = userOrg.roleId;
|
||||
req.userOrgId = resource[0].orgId!;
|
||||
next();
|
||||
}
|
||||
} catch (e) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
`resource with ID ${resourceId} does not have an organization ID`
|
||||
"Error verifying organization access"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
db.select()
|
||||
.from(userOrgs)
|
||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, resource[0].orgId)))
|
||||
.then((result) => {
|
||||
if (result.length === 0) {
|
||||
next(createHttpError(HttpCode.FORBIDDEN, 'User does not have access to this organization'));
|
||||
} else {
|
||||
// User has access, attach the user's role to the request for potential future use
|
||||
req.userOrgRoleId = result[0].roleId;
|
||||
req.userOrgId = resource[0].orgId!;
|
||||
next();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying organization access'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ export type VerifyTotpResponse = {
|
|||
export async function verifyTotp(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
const parsedBody = verifyTotpBody.safeParse(req.body);
|
||||
|
||||
|
@ -33,8 +33,8 @@ export async function verifyTotp(
|
|||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedBody.error).toString(),
|
||||
),
|
||||
fromError(parsedBody.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,8 @@ export async function verifyTotp(
|
|||
return next(
|
||||
createHttpError(
|
||||
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(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"User has not requested two-factor authentication",
|
||||
),
|
||||
"User has not requested two-factor authentication"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const valid = await verifyTotpCode(code, user.twoFactorSecret, user.userId);
|
||||
const valid = await verifyTotpCode(
|
||||
code,
|
||||
user.twoFactorSecret,
|
||||
user.userId
|
||||
);
|
||||
|
||||
let codes;
|
||||
if (valid) {
|
||||
|
@ -101,8 +105,8 @@ export async function verifyTotp(
|
|||
return next(
|
||||
createHttpError(
|
||||
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 { db } from "@server/db";
|
||||
import {
|
||||
sites,
|
||||
userOrgs,
|
||||
userSites,
|
||||
roleSites,
|
||||
roles,
|
||||
} from "@server/db/schema";
|
||||
import { userOrgs } from "@server/db/schema";
|
||||
import { and, eq, or } from "drizzle-orm";
|
||||
import createHttpError from "http-errors";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
|
@ -16,9 +10,11 @@ export async function verifyUserAccess(
|
|||
res: Response,
|
||||
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;
|
||||
|
||||
let userOrg = req.userOrg;
|
||||
|
||||
if (!userId) {
|
||||
return next(
|
||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||
|
@ -30,18 +26,21 @@ export async function verifyUserAccess(
|
|||
}
|
||||
|
||||
try {
|
||||
const userOrg = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, reqUserId),
|
||||
eq(userOrgs.orgId, req.userOrgId!)
|
||||
if (!userOrg) {
|
||||
const res = await db
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, reqUserId),
|
||||
eq(userOrgs.orgId, req.userOrgId!)
|
||||
)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
.limit(1);
|
||||
userOrg = res[0];
|
||||
}
|
||||
|
||||
if (userOrg.length === 0) {
|
||||
if (userOrg) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
|
|
|
@ -1,31 +1,51 @@
|
|||
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';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
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 {
|
||||
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;
|
||||
|
||||
if (isNaN(roleId)) {
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid role ID'));
|
||||
return next(
|
||||
createHttpError(HttpCode.BAD_REQUEST, "Invalid role ID")
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
} catch (error) {
|
||||
logger.error('Error verifying role access:', error);
|
||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Error verifying role access'));
|
||||
logger.error("Error verifying role access:", error);
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
"Error verifying role access"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
verifyResourceAccess,
|
||||
verifyTargetAccess,
|
||||
verifyRoleAccess,
|
||||
verifySuperUser,
|
||||
verifyAdmin,
|
||||
verifyUserInRole,
|
||||
verifyUserAccess,
|
||||
} from "./auth";
|
||||
|
@ -121,7 +121,7 @@ authenticated.delete(
|
|||
// authenticated.put(
|
||||
// "/org/:orgId/role",
|
||||
// verifyOrgAccess,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.createRole
|
||||
// );
|
||||
// authenticated.get("/org/:orgId/roles", verifyOrgAccess, role.listRoles);
|
||||
|
@ -134,13 +134,13 @@ authenticated.delete(
|
|||
// authenticated.post(
|
||||
// "/role/:roleId",
|
||||
// verifyRoleAccess,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.updateRole
|
||||
// );
|
||||
// authenticated.delete(
|
||||
// "/role/:roleId",
|
||||
// verifyRoleAccess,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.deleteRole
|
||||
// );
|
||||
|
||||
|
@ -190,14 +190,14 @@ authenticated.delete(
|
|||
// "/role/:roleId/action",
|
||||
// verifyRoleAccess,
|
||||
// verifyUserInRole,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.removeRoleAction
|
||||
// );
|
||||
// authenticated.get(
|
||||
// "/role/:roleId/actions",
|
||||
// verifyRoleAccess,
|
||||
// verifyUserInRole,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.listRoleActions
|
||||
// );
|
||||
|
||||
|
@ -239,14 +239,14 @@ authenticated.delete(
|
|||
// "/org/:orgId/user/:userId/action",
|
||||
// verifyOrgAccess,
|
||||
// verifyUserAccess,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.addRoleAction
|
||||
// );
|
||||
// authenticated.delete(
|
||||
// "/org/:orgId/user/:userId/action",
|
||||
// verifyOrgAccess,
|
||||
// verifyUserAccess,
|
||||
// verifySuperUser,
|
||||
// verifyAdmin,
|
||||
// role.removeRoleAction
|
||||
// );
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { db } from '@server/db';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { orgs, userOrgs } from '@server/db/schema';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { orgs, userOrgs } from "@server/db/schema";
|
||||
import response from "@server/utils/response";
|
||||
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';
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||
import logger from "@server/logger";
|
||||
import { createAdminRole } from "@server/db/ensureActions";
|
||||
import config, { APP_PATH } from "@server/config";
|
||||
import { fromError } from 'zod-validation-error';
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const createOrgSchema = z.object({
|
||||
orgId: z.string(),
|
||||
|
@ -20,7 +20,11 @@ const createOrgSchema = z.object({
|
|||
|
||||
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 {
|
||||
const parsedBody = createOrgSchema.safeParse(req.body);
|
||||
if (!parsedBody.success) {
|
||||
|
@ -43,7 +47,7 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
|||
}
|
||||
|
||||
// TODO: we cant do this when they create an org because they are not in an org yet... maybe we need to make the org id optional on the userActions table
|
||||
// Check if the user has permission
|
||||
// Check if the user has permission
|
||||
// const hasPermission = await checkUserActionPermission(ActionsEnum.createOrg, req);
|
||||
// if (!hasPermission) {
|
||||
// return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
|
||||
|
@ -52,11 +56,12 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
|||
const { orgId, name } = parsedBody.data;
|
||||
|
||||
// make sure the orgId is unique
|
||||
const orgExists = await db.select()
|
||||
const orgExists = await db
|
||||
.select()
|
||||
.from(orgs)
|
||||
.where(eq(orgs.orgId, orgId))
|
||||
.limit(1);
|
||||
|
||||
|
||||
if (orgExists.length > 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
|
@ -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
|
||||
const domain = new URL(config.app.base_url).hostname;
|
||||
|
||||
const newOrg = await db.insert(orgs).values({
|
||||
orgId,
|
||||
name,
|
||||
domain
|
||||
}).returning();
|
||||
const newOrg = await db
|
||||
.insert(orgs)
|
||||
.values({
|
||||
orgId,
|
||||
name,
|
||||
domain,
|
||||
})
|
||||
.returning();
|
||||
|
||||
const roleId = await createSuperUserRole(newOrg[0].orgId);
|
||||
const roleId = await createAdminRole(newOrg[0].orgId);
|
||||
|
||||
if (!roleId) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
`Error creating Super User role`
|
||||
`Error creating Admin role`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// put the user in the super user role
|
||||
await db.insert(userOrgs).values({
|
||||
userId: req.user!.userId,
|
||||
orgId: newOrg[0].orgId,
|
||||
roleId: roleId,
|
||||
}).execute();
|
||||
await db
|
||||
.insert(userOrgs)
|
||||
.values({
|
||||
userId: req.user!.userId,
|
||||
orgId: newOrg[0].orgId,
|
||||
roleId: roleId,
|
||||
})
|
||||
.execute();
|
||||
|
||||
return response(res, {
|
||||
data: newOrg[0],
|
||||
|
@ -102,6 +112,11 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
|||
});
|
||||
} catch (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 { z } from 'zod';
|
||||
import { db } from '@server/db';
|
||||
import { orgs } from '@server/db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import { orgs, userActions } from "@server/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import response from "@server/utils/response";
|
||||
import HttpCode from '@server/types/HttpCode';
|
||||
import createHttpError from 'http-errors';
|
||||
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
|
||||
import logger from '@server/logger';
|
||||
import { fromError } from 'zod-validation-error';
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
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 {
|
||||
const parsedParams = deleteOrgSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
|
@ -28,13 +32,22 @@ export async function deleteOrg(req: Request, res: Response, next: NextFunction)
|
|||
|
||||
const { orgId } = parsedParams.data;
|
||||
|
||||
// Check if the user has permission to list sites
|
||||
const hasPermission = await checkUserActionPermission(ActionsEnum.deleteOrg, req);
|
||||
if (!hasPermission) {
|
||||
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
|
||||
}
|
||||
// // Check if the user has permission to list sites
|
||||
// const hasPermission = await checkUserActionPermission(
|
||||
// ActionsEnum.deleteOrg,
|
||||
// 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))
|
||||
.returning();
|
||||
|
||||
|
@ -56,6 +69,11 @@ export async function deleteOrg(req: Request, res: Response, next: NextFunction)
|
|||
});
|
||||
} catch (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 { z } from 'zod';
|
||||
import { db } from '@server/db';
|
||||
import { orgs, resources, roleResources, roles, userResources } from '@server/db/schema';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import {
|
||||
orgs,
|
||||
resources,
|
||||
roleResources,
|
||||
roles,
|
||||
userResources,
|
||||
} from "@server/db/schema";
|
||||
import response from "@server/utils/response";
|
||||
import HttpCode from '@server/types/HttpCode';
|
||||
import createHttpError from 'http-errors';
|
||||
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
|
||||
import logger from '@server/logger';
|
||||
import { eq, and } from 'drizzle-orm';
|
||||
import stoi from '@server/utils/stoi';
|
||||
import { fromError } from 'zod-validation-error';
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||
import logger from "@server/logger";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import stoi from "@server/utils/stoi";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const createResourceParamsSchema = z.object({
|
||||
siteId: z.string().optional().transform(stoi).pipe(z.number().int().positive().optional()),
|
||||
orgId: z.string()
|
||||
siteId: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform(stoi)
|
||||
.pipe(z.number().int().positive().optional()),
|
||||
orgId: z.string(),
|
||||
});
|
||||
|
||||
// Define Zod schema for request body validation
|
||||
|
@ -22,7 +32,11 @@ const createResourceSchema = z.object({
|
|||
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 {
|
||||
// Validate request 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;
|
||||
|
||||
// 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) {
|
||||
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) {
|
||||
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
|
||||
const org = await db.select()
|
||||
const org = await db
|
||||
.select()
|
||||
.from(orgs)
|
||||
.where(eq(orgs.orgId, orgId))
|
||||
.limit(1);
|
||||
|
@ -79,35 +104,35 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
|||
const fullDomain = `${subdomain}.${org[0].domain}`;
|
||||
|
||||
// Create new resource in the database
|
||||
const newResource = await db.insert(resources).values({
|
||||
fullDomain,
|
||||
siteId,
|
||||
orgId,
|
||||
name,
|
||||
subdomain,
|
||||
}).returning();
|
||||
const newResource = await db
|
||||
.insert(resources)
|
||||
.values({
|
||||
fullDomain,
|
||||
siteId,
|
||||
orgId,
|
||||
name,
|
||||
subdomain,
|
||||
})
|
||||
.returning();
|
||||
|
||||
// find the Super User roleId and also add the resource to the Super User role
|
||||
const superUserRole = await db.select()
|
||||
const adminRole = await db
|
||||
.select()
|
||||
.from(roles)
|
||||
.where(and(eq(roles.isSuperUserRole, true), eq(roles.orgId, orgId)))
|
||||
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
|
||||
.limit(1);
|
||||
|
||||
if (superUserRole.length === 0) {
|
||||
if (adminRole.length === 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.NOT_FOUND,
|
||||
`Super User role not found`
|
||||
)
|
||||
createHttpError(HttpCode.NOT_FOUND, `Admin role not found`)
|
||||
);
|
||||
}
|
||||
|
||||
await db.insert(roleResources).values({
|
||||
roleId: superUserRole[0].roleId,
|
||||
roleId: adminRole[0].roleId,
|
||||
resourceId: newResource[0].resourceId,
|
||||
});
|
||||
|
||||
if (req.userOrgRoleId != superUserRole[0].roleId) {
|
||||
if (req.userOrgRoleId != adminRole[0].roleId) {
|
||||
// make sure the user can access the resource
|
||||
await db.insert(userResources).values({
|
||||
userId: req.user?.userId!,
|
||||
|
@ -124,6 +149,11 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
|||
});
|
||||
} catch (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,
|
||||
name: roles.name,
|
||||
description: roles.description,
|
||||
isSuperUserRole: roles.isSuperUserRole,
|
||||
isAdmin: roles.isAdmin,
|
||||
})
|
||||
.from(roleResources)
|
||||
.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(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
`Cannot delete a Super User role`
|
||||
`Cannot delete a Admin role`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ export async function listRoles(
|
|||
.select({
|
||||
roleId: roles.roleId,
|
||||
orgId: roles.orgId,
|
||||
isSuperUserRole: roles.isSuperUserRole,
|
||||
isAdmin: roles.isAdmin,
|
||||
name: roles.name,
|
||||
description: roles.description,
|
||||
orgName: orgs.name,
|
||||
|
|
|
@ -81,11 +81,11 @@ export async function updateRole(
|
|||
);
|
||||
}
|
||||
|
||||
if (role[0].isSuperUserRole) {
|
||||
if (role[0].isAdmin) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
`Cannot update a Super User role`
|
||||
`Cannot update a Admin role`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -107,25 +107,24 @@ export async function createSite(
|
|||
subnet,
|
||||
})
|
||||
.returning();
|
||||
// find the Super User roleId and also add the resource to the Super User role
|
||||
const superUserRole = await db
|
||||
const adminRole = await db
|
||||
.select()
|
||||
.from(roles)
|
||||
.where(and(eq(roles.isSuperUserRole, true), eq(roles.orgId, orgId)))
|
||||
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
|
||||
.limit(1);
|
||||
|
||||
if (superUserRole.length === 0) {
|
||||
if (adminRole.length === 0) {
|
||||
return next(
|
||||
createHttpError(HttpCode.NOT_FOUND, `Super User role not found`)
|
||||
createHttpError(HttpCode.NOT_FOUND, `Admin role not found`)
|
||||
);
|
||||
}
|
||||
|
||||
await db.insert(roleSites).values({
|
||||
roleId: superUserRole[0].roleId,
|
||||
roleId: adminRole[0].roleId,
|
||||
siteId: newSite.siteId,
|
||||
});
|
||||
|
||||
if (req.userOrgRoleId != superUserRole[0].roleId) {
|
||||
if (req.userOrgRoleId != adminRole[0].roleId) {
|
||||
// make sure the user can access the site
|
||||
db.insert(userSites).values({
|
||||
userId: req.user?.userId!,
|
||||
|
|
|
@ -51,7 +51,7 @@ export async function listSiteRoles(
|
|||
roleId: roles.roleId,
|
||||
name: roles.name,
|
||||
description: roles.description,
|
||||
isSuperUserRole: roles.isSuperUserRole,
|
||||
isAdmin: roles.isAdmin,
|
||||
})
|
||||
.from(roleSites)
|
||||
.innerJoin(roles, eq(roleSites.roleId, roles.roleId))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue