backend: prevent admins to delete their own account or root admin user account
This commit is contained in:
parent
8ab8007c1d
commit
7d7f66edf3
@ -217,6 +217,38 @@ export const errorUserAlreadyExists = (userId: string): OpenViduMeetError => {
|
||||
return new OpenViduMeetError('User Error', `User '${userId}' already exists`, 409);
|
||||
};
|
||||
|
||||
export const errorCannotResetRootAdminPassword = (): OpenViduMeetError => {
|
||||
return new OpenViduMeetError(
|
||||
'User Error',
|
||||
'Cannot reset password for the root admin user. The root admin must change their own password.',
|
||||
403
|
||||
);
|
||||
};
|
||||
|
||||
export const errorCannotResetOwnPassword = (): OpenViduMeetError => {
|
||||
return new OpenViduMeetError(
|
||||
'User Error',
|
||||
'Cannot reset your own password. Please use the change-password endpoint to change your password.',
|
||||
403
|
||||
);
|
||||
};
|
||||
|
||||
export const errorCannotDeleteRootAdmin = (): OpenViduMeetError => {
|
||||
return new OpenViduMeetError(
|
||||
'User Error',
|
||||
'Cannot delete the root admin user. This account is required for system administration.',
|
||||
403
|
||||
);
|
||||
};
|
||||
|
||||
export const errorCannotDeleteOwnAccount = (): OpenViduMeetError => {
|
||||
return new OpenViduMeetError(
|
||||
'User Error',
|
||||
'Cannot delete your own account. Please have another administrator delete your account if needed.',
|
||||
403
|
||||
);
|
||||
};
|
||||
|
||||
// Room errors
|
||||
|
||||
export const errorRoomNotFound = (roomId: string): OpenViduMeetError => {
|
||||
|
||||
@ -2,11 +2,20 @@ import { MeetUser, MeetUserDTO, MeetUserFilters, MeetUserOptions, MeetUserRole }
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { MEET_ENV } from '../environment.js';
|
||||
import { PasswordHelper } from '../helpers/password.helper.js';
|
||||
import { errorInvalidPassword, errorUserAlreadyExists, errorUserNotFound } from '../models/error.model.js';
|
||||
import {
|
||||
errorCannotDeleteOwnAccount,
|
||||
errorCannotDeleteRootAdmin,
|
||||
errorCannotResetOwnPassword,
|
||||
errorCannotResetRootAdminPassword,
|
||||
errorInvalidPassword,
|
||||
errorUserAlreadyExists,
|
||||
errorUserNotFound
|
||||
} from '../models/error.model.js';
|
||||
import { RoomMemberRepository } from '../repositories/room-member.repository.js';
|
||||
import { RoomRepository } from '../repositories/room.repository.js';
|
||||
import { UserRepository } from '../repositories/user.repository.js';
|
||||
import { LoggerService } from './logger.service.js';
|
||||
import { RequestSessionService } from './request-session.service.js';
|
||||
|
||||
@injectable()
|
||||
export class UserService {
|
||||
@ -14,7 +23,8 @@ export class UserService {
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(UserRepository) protected userRepository: UserRepository,
|
||||
@inject(RoomRepository) protected roomRepository: RoomRepository,
|
||||
@inject(RoomMemberRepository) protected roomMemberRepository: RoomMemberRepository
|
||||
@inject(RoomMemberRepository) protected roomMemberRepository: RoomMemberRepository,
|
||||
@inject(RequestSessionService) protected requestSessionService: RequestSessionService
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -116,6 +126,18 @@ export class UserService {
|
||||
* @param newPassword - The new temporary password set by admin
|
||||
*/
|
||||
async resetUserPassword(userId: string, newPassword: string): Promise<void> {
|
||||
// Prevent resetting own password (use change-password endpoint instead)
|
||||
const authenticatedUser = this.requestSessionService.getAuthenticatedUser();
|
||||
|
||||
if (authenticatedUser && authenticatedUser.userId === userId) {
|
||||
throw errorCannotResetOwnPassword();
|
||||
}
|
||||
|
||||
// Prevent resetting password for the root admin user
|
||||
if (userId === MEET_ENV.INITIAL_ADMIN_USER) {
|
||||
throw errorCannotResetRootAdminPassword();
|
||||
}
|
||||
|
||||
const user = await this.userRepository.findByUserId(userId);
|
||||
|
||||
if (!user) {
|
||||
@ -130,6 +152,18 @@ export class UserService {
|
||||
}
|
||||
|
||||
async deleteUser(userId: string): Promise<void> {
|
||||
// Prevent deleting the root admin user
|
||||
if (userId === MEET_ENV.INITIAL_ADMIN_USER) {
|
||||
throw errorCannotDeleteRootAdmin();
|
||||
}
|
||||
|
||||
// Prevent self-deletion
|
||||
const authenticatedUser = this.requestSessionService.getAuthenticatedUser();
|
||||
|
||||
if (authenticatedUser && authenticatedUser.userId === userId) {
|
||||
throw errorCannotDeleteOwnAccount();
|
||||
}
|
||||
|
||||
const user = await this.userRepository.findByUserId(userId);
|
||||
|
||||
if (!user) {
|
||||
@ -147,12 +181,35 @@ export class UserService {
|
||||
async bulkDeleteUsers(
|
||||
userIds: string[]
|
||||
): Promise<{ deleted: string[]; failed: { userId: string; error: string }[] }> {
|
||||
const usersToDelete = await this.userRepository.findByUserIds(userIds);
|
||||
const rootAdminUserId = MEET_ENV.INITIAL_ADMIN_USER;
|
||||
const authenticatedUser = this.requestSessionService.getAuthenticatedUser();
|
||||
|
||||
// Filter out the root admin user and authenticated user from the deletion list
|
||||
const failed: { userId: string; error: string }[] = [];
|
||||
let filteredUserIds = [...userIds];
|
||||
|
||||
if (userIds.includes(rootAdminUserId)) {
|
||||
failed.push({ userId: rootAdminUserId, error: 'Cannot delete the root admin user' });
|
||||
filteredUserIds = filteredUserIds.filter((id) => id !== rootAdminUserId);
|
||||
}
|
||||
|
||||
if (
|
||||
authenticatedUser &&
|
||||
authenticatedUser?.userId !== rootAdminUserId &&
|
||||
userIds.includes(authenticatedUser.userId)
|
||||
) {
|
||||
failed.push({ userId: authenticatedUser.userId, error: 'Cannot delete your own account' });
|
||||
filteredUserIds = filteredUserIds.filter((id) => id !== authenticatedUser.userId);
|
||||
}
|
||||
|
||||
const usersToDelete = await this.userRepository.findByUserIds(filteredUserIds);
|
||||
const foundUserIds = usersToDelete.map((u) => u.userId);
|
||||
|
||||
const failed = userIds
|
||||
.filter((id) => !foundUserIds.includes(id))
|
||||
.map((id) => ({ userId: id, error: 'User not found' }));
|
||||
failed.push(
|
||||
...filteredUserIds
|
||||
.filter((id) => !foundUserIds.includes(id))
|
||||
.map((id) => ({ userId: id, error: 'User not found' }))
|
||||
);
|
||||
|
||||
if (foundUserIds.length > 0) {
|
||||
// Clean up resources for all users in batches
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user