move action permission check to middleware

This commit is contained in:
Milo Schwartz
2024-11-05 23:55:46 -05:00
parent 03051878ef
commit 372e51c0a5
48 changed files with 266 additions and 936 deletions

View File

@@ -11,13 +11,16 @@ import response from "@server/utils/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { sql, eq, or, inArray, and, count } from "drizzle-orm";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import stoi from "@server/utils/stoi";
const listResourcesParamsSchema = z
.object({
siteId: z.string().optional().transform(stoi).pipe(z.number().int().positive().optional()),
siteId: z
.string()
.optional()
.transform(stoi)
.pipe(z.number().int().positive().optional()),
orgId: z.string().optional(),
})
.refine((data) => !!data.siteId !== !!data.orgId, {
@@ -43,7 +46,7 @@ const listResourcesSchema = z.object({
function queryResources(
accessibleResourceIds: number[],
siteId?: number,
orgId?: string,
orgId?: string
) {
if (siteId) {
return db
@@ -58,8 +61,8 @@ function queryResources(
.where(
and(
inArray(resources.resourceId, accessibleResourceIds),
eq(resources.siteId, siteId),
),
eq(resources.siteId, siteId)
)
);
} else if (orgId) {
return db
@@ -74,8 +77,8 @@ function queryResources(
.where(
and(
inArray(resources.resourceId, accessibleResourceIds),
eq(resources.orgId, orgId),
),
eq(resources.orgId, orgId)
)
);
}
}
@@ -88,7 +91,7 @@ export type ListResourcesResponse = {
export async function listResources(
req: Request,
res: Response,
next: NextFunction,
next: NextFunction
): Promise<any> {
try {
const parsedQuery = listResourcesSchema.safeParse(req.query);
@@ -96,8 +99,8 @@ export async function listResources(
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedQuery.error.errors.map((e) => e.message).join(", "),
),
parsedQuery.error.errors.map((e) => e.message).join(", ")
)
);
}
const { limit, offset } = parsedQuery.data;
@@ -107,36 +110,21 @@ export async function listResources(
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map((e) => e.message).join(", "),
),
parsedParams.error.errors.map((e) => e.message).join(", ")
)
);
}
const { siteId, orgId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(
ActionsEnum.listResources,
req,
);
if (!hasPermission) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action",
),
);
}
if (orgId && orgId !== req.userOrgId) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have access to this organization",
),
"User does not have access to this organization"
)
);
}
// Get the list of resources the user has access to
const accessibleResources = await db
.select({
resourceId: sql<number>`COALESCE(${userResources.resourceId}, ${roleResources.resourceId})`,
@@ -144,17 +132,17 @@ export async function listResources(
.from(userResources)
.fullJoin(
roleResources,
eq(userResources.resourceId, roleResources.resourceId),
eq(userResources.resourceId, roleResources.resourceId)
)
.where(
or(
eq(userResources.userId, req.user!.userId),
eq(roleResources.roleId, req.userOrgRoleId!),
),
eq(roleResources.roleId, req.userOrgRoleId!)
)
);
const accessibleResourceIds = accessibleResources.map(
(resource) => resource.resourceId,
(resource) => resource.resourceId
);
let countQuery: any = db
@@ -185,10 +173,7 @@ export async function listResources(
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred...",
),
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}