Skip to content

Commit

Permalink
fixed bugs with updating permission
Browse files Browse the repository at this point in the history
  • Loading branch information
SupertigerDev committed Jan 16, 2025
1 parent 2c3254b commit 524b0ee
Showing 1 changed file with 75 additions and 47 deletions.
122 changes: 75 additions & 47 deletions src/routes/servers/serverRoleUpdate.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Request, Response, Router } from 'express';
import { body, matchedData } from 'express-validator';
import { prisma } from '../../common/database';
import {
customExpressValidatorResult,
generateError,
} from '../../common/errorHandler';
import { ROLE_PERMISSIONS } from '../../common/Bitwise';
import { customExpressValidatorResult, generateError } from '../../common/errorHandler';
import { hasBit, ROLE_PERMISSIONS } from '../../common/Bitwise';
import { authenticate } from '../../middleware/authenticate';
import { memberHasRolePermissionMiddleware } from '../../middleware/memberHasRolePermission';
import { rateLimit } from '../../middleware/rateLimit';
Expand All @@ -15,40 +12,15 @@ import { updateServerRole } from '../../services/ServerRole';
export function serverRoleUpdate(Router: Router) {
Router.post(
'/servers/:serverId/roles/:roleId',
authenticate({allowBot: true}),
authenticate({ allowBot: true }),
serverMemberVerification(),
memberHasRolePermissionMiddleware(ROLE_PERMISSIONS.MANAGE_ROLES),
body('name')
.isString()
.withMessage('Name must be a string.')
.isLength({ min: 4, max: 100 })
.withMessage('Name must be between 4 and 100 characters long.')
.optional({ nullable: true }),
body('hexColor')
.isString()
.withMessage('hexColor must be a string.')
.isLength({ min: 4, max: 100 })
.withMessage('Name must be between 4 and 100 characters long.')
.optional({ nullable: true }),
body('hideRole')
.isBoolean()
.withMessage('hideRole must be a boolean.')
.optional({ nullable: true }),
body('permissions')
.isNumeric()
.withMessage('Permissions must be a number.')
.isInt({ min: 0, max: 900 })
.withMessage('Permissions must be between 0 and 900.')
.isLength({ min: 0, max: 100 })
.withMessage('Permissions must be between 0 and 100 characters long.')
.optional({ nullable: true }),

body('icon')
.isString()
.withMessage('Icon must be a string.')
.isLength({ min: 0, max: 100 })
.withMessage('Icon must be between 0 and 100 characters long.')
.optional({ nullable: true }),
body('name').isString().withMessage('Name must be a string.').isLength({ min: 4, max: 100 }).withMessage('Name must be between 4 and 100 characters long.').optional({ nullable: true }),
body('hexColor').isString().withMessage('hexColor must be a string.').isLength({ min: 4, max: 100 }).withMessage('Name must be between 4 and 100 characters long.').optional({ nullable: true }),
body('hideRole').isBoolean().withMessage('hideRole must be a boolean.').optional({ nullable: true }),
body('permissions').isNumeric().withMessage('Permissions must be a number.').isInt({ min: 0, max: 900 }).withMessage('Permissions must be between 0 and 900.').isLength({ min: 0, max: 100 }).withMessage('Permissions must be between 0 and 100 characters long.').optional({ nullable: true }),

body('icon').isString().withMessage('Icon must be a string.').isLength({ min: 0, max: 100 }).withMessage('Icon must be between 0 and 100 characters long.').optional({ nullable: true }),

rateLimit({
name: 'server_role_update',
Expand All @@ -65,7 +37,6 @@ interface Body {
hexColor?: string;
hideRoles?: boolean;
icon?: string | null;

}

async function route(req: Request, res: Response) {
Expand All @@ -76,30 +47,87 @@ async function route(req: Request, res: Response) {

const matchedBody: Body = matchedData(req);

const role = await prisma.serverRole.findFirst({
const role = await prisma.serverRole.findUnique({
where: { id: req.params.roleId },
});
if (!role) {
return res.status(400).json(generateError('Role does not exist.'));
}
const isCreator = req.serverCache.createdById === req.userCache.id;
if (!isCreator && role.order >= req.serverMemberCache.topRoleOrder) {
return res
.status(400)
.json(generateError('You do not have priority to modify this role.'));
return res.status(400).json(generateError('You do not have priority to modify this role.'));
}

if (req.body.icon === null) {
matchedBody.icon = null;
}

const [updated, error] = await updateServerRole(
req.serverCache.id,
req.params.roleId,
matchedBody
);
if (!isCreator && matchedBody.permissions !== undefined) {
const diff = matchedBody.permissions ^ role.permissions;
if (!hasBit(req.serverMemberCache.permissions, diff)) {
return res.status(400).json(generateError('You must have this permission to modify this role.'));
}
const [highestOrderPerms, highestOrderPermsError] = await getHighestPermission(req.userCache.id, req.serverCache.id);

if (highestOrderPermsError) {
return res.status(400).json(highestOrderPermsError);
}

for (const key in ROLE_PERMISSIONS) {
const permission = ROLE_PERMISSIONS[key as keyof typeof ROLE_PERMISSIONS];
if (!hasBit(diff, permission.bit)) continue;
const highestOrder = highestOrderPerms.get(permission.bit);
if (highestOrder === undefined) continue;
if (role.order >= highestOrder) {
return res.status(400).json(generateError(`You cannot modify this permission for this role.`));
}
}
}

const [updated, error] = await updateServerRole(req.serverCache.id, role.id, matchedBody);
if (error) {
return res.status(400).json(error);
}
res.json(updated);
}

async function getHighestPermission(userId: string, serverId: string) {
const [member, roles] = await prisma.$transaction([
prisma.serverMember.findUnique({
include: {
server: {
select: {
defaultRoleId: true,
},
},
},
where: { userId_serverId: { userId, serverId } },
}),
prisma.serverRole.findMany({
where: { serverId },
select: { permissions: true, order: true, id: true },
orderBy: { order: 'desc' },
}),
]);
if (!member) return [null, generateError('Member not found.')] as const;

const roleIds = [...member.roleIds, member.server.defaultRoleId];

// permissions[bit] = order
const permissions = new Map<number, number>();

for (let i = 0; i < roles.length; i++) {
const role = roles[i]!;
if (!roleIds.includes(role.id)) continue;

for (const key in ROLE_PERMISSIONS) {
const permission = ROLE_PERMISSIONS[key as keyof typeof ROLE_PERMISSIONS];
if (permissions.get(permission.bit) !== undefined) continue;
const hasPerm = hasBit(role.permissions, permission.bit);
if (hasPerm) {
permissions.set(permission.bit, role.order);
}
}
}
return [permissions, null] as const;
}

0 comments on commit 524b0ee

Please sign in to comment.