mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-03 22:37:20 +02:00
feat: prevent removing the last admin user
Add guard in removeRoleMember that checks countUsersByRole before demoting an ADMIN user, returning 400 if they are the last one.
This commit is contained in:
parent
b9e0fa48c6
commit
e9572854ef
2 changed files with 43 additions and 0 deletions
|
|
@ -1086,6 +1086,42 @@ describe('createAdminRolesHandlers', () => {
|
|||
expect(deps.updateUser).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns 400 when removing the last admin user', async () => {
|
||||
const deps = createDeps({
|
||||
getRoleByName: jest.fn().mockResolvedValue(mockRole({ name: SystemRoles.ADMIN })),
|
||||
findUser: jest.fn().mockResolvedValue(mockUser({ role: SystemRoles.ADMIN })),
|
||||
countUsersByRole: jest.fn().mockResolvedValue(1),
|
||||
});
|
||||
const handlers = createAdminRolesHandlers(deps);
|
||||
const { req, res, status, json } = createReqRes({
|
||||
params: { name: SystemRoles.ADMIN, userId: validUserId },
|
||||
});
|
||||
|
||||
await handlers.removeRoleMember(req, res);
|
||||
|
||||
expect(status).toHaveBeenCalledWith(400);
|
||||
expect(json).toHaveBeenCalledWith({ error: 'Cannot remove the last admin user' });
|
||||
expect(deps.updateUser).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('allows removing an admin when multiple admins exist', async () => {
|
||||
const deps = createDeps({
|
||||
getRoleByName: jest.fn().mockResolvedValue(mockRole({ name: SystemRoles.ADMIN })),
|
||||
findUser: jest.fn().mockResolvedValue(mockUser({ role: SystemRoles.ADMIN })),
|
||||
countUsersByRole: jest.fn().mockResolvedValue(3),
|
||||
});
|
||||
const handlers = createAdminRolesHandlers(deps);
|
||||
const { req, res, status, json } = createReqRes({
|
||||
params: { name: SystemRoles.ADMIN, userId: validUserId },
|
||||
});
|
||||
|
||||
await handlers.removeRoleMember(req, res);
|
||||
|
||||
expect(status).toHaveBeenCalledWith(200);
|
||||
expect(json).toHaveBeenCalledWith({ success: true });
|
||||
expect(deps.updateUser).toHaveBeenCalledWith(validUserId, { role: SystemRoles.USER });
|
||||
});
|
||||
|
||||
it('returns 500 on unexpected error', async () => {
|
||||
const deps = createDeps({
|
||||
getRoleByName: jest.fn().mockResolvedValue(mockRole()),
|
||||
|
|
|
|||
|
|
@ -337,6 +337,13 @@ export function createAdminRolesHandlers(deps: AdminRolesDeps) {
|
|||
return res.status(400).json({ error: 'User is not a member of this role' });
|
||||
}
|
||||
|
||||
if (name === SystemRoles.ADMIN) {
|
||||
const adminCount = await countUsersByRole(SystemRoles.ADMIN);
|
||||
if (adminCount <= 1) {
|
||||
return res.status(400).json({ error: 'Cannot remove the last admin user' });
|
||||
}
|
||||
}
|
||||
|
||||
await updateUser(userId, { role: SystemRoles.USER });
|
||||
return res.status(200).json({ success: true });
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue