UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

376 lines (375 loc) 18.3 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "AdminUsersManager", { enumerable: true, get: function() { return AdminUsersManager; } }); const _common = require("@nestjs/common"); const _authmanagerservice = require("../../../authentication/services/auth-manager.service"); const _functions = require("../../../common/functions"); const _files = require("../../files/utils/files"); const _group = require("../constants/group"); const _user = require("../constants/user"); const _usermodel = require("../models/user.model"); const _adminusersqueriesservice = require("./admin-users-queries.service"); function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function _ts_metadata(k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); } let AdminUsersManager = class AdminUsersManager { listUsers() { return this.adminQueries.listUsers(); } async getUser(userId) { const user = await this.adminQueries.listUsers(userId); this.checkUser(user, true); return user; } async getGuest(guestId) { const user = await this.adminQueries.usersQueries.listGuests(guestId, 0, true); this.checkUser(user, true); return user; } async createUserOrGuest(createUserDto, userRole = _user.USER_ROLE.USER, asAdmin = false) { await this.loginOrEmailAlreadyUsed(createUserDto.login, createUserDto.email); try { createUserDto.password = await (0, _functions.hashPassword)(createUserDto.password); const userId = await this.adminQueries.usersQueries.createUserOrGuest(createUserDto, userRole); const user = new _usermodel.UserModel({ ...createUserDto, id: userId, role: userRole }); this.logger.log(`${this.createUserOrGuest.name} - ${_user.USER_ROLE[userRole]} (${userId}) was created : ${JSON.stringify((0, _functions.anonymizePassword)(createUserDto))}`); this.adminQueries.usersQueries.clearWhiteListCaches('*'); await user.makePaths(); if (userRole <= _user.USER_ROLE.USER) { return asAdmin ? this.getUser(user.id) : user; } else { return asAdmin ? this.getGuest(user.id) : user; } } catch (e) { this.logger.error(`${this.createUserOrGuest.name} - unable to create user *${createUserDto.login}* : ${e}`); throw new _common.HttpException('Unable to create user', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } async updateUserOrGuest(userId, updateUserDto, userRole = _user.USER_ROLE.USER) { const user = userRole === _user.USER_ROLE.USER ? await this.getUser(userId) : await this.getGuest(userId); const updateUser = {}; const updateUserGroups = { add: [], delete: [] }; const updateGuestManagers = { add: [], delete: [] }; for (const [k, v] of Object.entries(updateUserDto)){ switch(k){ case 'login': if (user.login === v) { break; } if (await this.adminQueries.usersQueries.checkUserExists(v)) { throw new _common.HttpException('Login already used', _common.HttpStatus.FORBIDDEN); } if (!await this.renameUserSpace(user.login, v)) { throw new _common.HttpException('Unable to rename user space', _common.HttpStatus.INTERNAL_SERVER_ERROR); } updateUser.login = v; break; case 'email': if (user.email === v) { break; } if (await this.adminQueries.usersQueries.checkUserExists(null, v)) { throw new _common.HttpException('Email already used', _common.HttpStatus.FORBIDDEN); } updateUser.email = v; break; case 'isActive': updateUser.isActive = v; if (v) { updateUser.passwordAttempts = 0; } break; case 'password': updateUser.password = await (0, _functions.hashPassword)(updateUserDto.password); break; case 'groups': if (userRole === _user.USER_ROLE.USER) { const currentGroups = user.groups?.length ? user.groups.map((g)=>g.id) : []; updateUserGroups.add = v.filter((id)=>currentGroups.indexOf(id) === -1); updateUserGroups.delete = currentGroups.filter((id)=>v.indexOf(id) === -1); } break; case 'managers': if (userRole === _user.USER_ROLE.GUEST) { const currentManagers = user.managers?.length ? user.managers.map((m)=>m.id) : []; updateGuestManagers.add = v.filter((id)=>currentManagers.indexOf(id) === -1); updateGuestManagers.delete = currentManagers.filter((id)=>v.indexOf(id) === -1); } break; default: updateUser[k] = v; } } if (Object.keys(updateUser).length) { // force the type for security reason const forceRole = userRole === _user.USER_ROLE.GUEST ? _user.USER_ROLE.GUEST : undefined; if (!await this.adminQueries.usersQueries.updateUserOrGuest(user.id, updateUser, forceRole)) { throw new _common.HttpException('Unable to update user', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } if (userRole === _user.USER_ROLE.USER) { if (updateUserGroups.add.length || updateUserGroups.delete.length) { try { await this.adminQueries.updateUserGroups(user.id, updateUserGroups); } catch { throw new _common.HttpException('Unable to update user groups', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } return this.getUser(userId); } else { if (updateGuestManagers.add.length || updateGuestManagers.delete.length) { try { await this.adminQueries.updateGuestManagers(user.id, updateGuestManagers); } catch { throw new _common.HttpException('Unable to update guest managers', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } return this.getGuest(userId); } } async deleteUserOrGuest(userId, userLogin, deleteUserDto) { try { if (await this.adminQueries.deleteUser(userId, userLogin)) { this.logger.log(`${this.deleteUserOrGuest.name} - *${userLogin}* (${userId}) was deleted`); } else { this.logger.error(`${this.deleteUserOrGuest.name} - *${userLogin}* (${userId}) was not deleted : not found`); } if (deleteUserDto.deleteSpace) { await this.deleteUserSpace(userLogin, deleteUserDto.isGuest); } } catch (e) { this.logger.error(`${this.deleteUserOrGuest.name} - unable to delete *${userLogin}* (${userId}) : ${e}`); throw new _common.HttpException('Unable to delete user', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } async deleteUserOrGuestFromAdmin(userId, deleteUserDto) { const userToDelete = this.checkUser(await this.adminQueries.usersQueries.from(userId)); if (userToDelete.isGuest !== deleteUserDto.isGuest) { throw new _common.HttpException('User mismatch', _common.HttpStatus.BAD_REQUEST); } await this.deleteUserOrGuest(userToDelete.id, userToDelete.login, { deleteSpace: deleteUserDto.isGuest ? true : deleteUserDto.deleteSpace, isGuest: deleteUserDto.isGuest }); } listGuests() { return this.adminQueries.usersQueries.listGuests(null, null, true); } createGuest(user, createGuestDto) { if (!createGuestDto.managers.length) { createGuestDto.managers.push(user.id); } return this.createUserOrGuest(createGuestDto, _user.USER_ROLE.GUEST, true); } updateGuest(guestId, updateGuestDto) { if (!Object.keys(updateGuestDto).length) { throw new _common.HttpException('No changes to update', _common.HttpStatus.BAD_REQUEST); } if (updateGuestDto.managers && !updateGuestDto.managers.length) { throw new _common.HttpException('Guest must have at least one manager', _common.HttpStatus.BAD_REQUEST); } return this.updateUserOrGuest(guestId, updateGuestDto, _user.USER_ROLE.GUEST); } async browseGroups(name, type = _group.GROUP_TYPE.USER) { if (name) { const group = await this.adminQueries.groupFromName(name); if (!group) { throw new _common.HttpException('Group not found', _common.HttpStatus.NOT_FOUND); } return { parentGroup: group, members: await this.adminQueries.browseGroupMembers(group.id, type) }; } return { parentGroup: undefined, members: await this.adminQueries.browseRootGroupMembers(type) }; } async getGroup(groupId) { const group = await this.adminQueries.groupFromId(groupId); if (!group) { throw new _common.HttpException('Group not found', _common.HttpStatus.NOT_FOUND); } return group; } async createGroup(createGroupDto) { if (!createGroupDto.name) { this.logger.error(`${this.createGroup.name} - missing group name : ${JSON.stringify(createGroupDto)}`); throw new _common.HttpException('Group name is missing', _common.HttpStatus.BAD_REQUEST); } await this.checkGroupNameExists(createGroupDto.name); try { const groupId = await this.adminQueries.createGroup(createGroupDto); this.logger.log(`${this.createGroup.name} - group (${groupId}) was created : ${JSON.stringify(createGroupDto)}`); return this.adminQueries.groupFromId(groupId); } catch (e) { this.logger.error(`${this.createGroup.name} - group was not created : ${JSON.stringify(createGroupDto)} : ${e}`); throw new _common.HttpException('Unable to create group', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } async updateGroup(groupId, updateGroupDto) { if (updateGroupDto.name) { await this.checkGroupNameExists(updateGroupDto.name); } if (!await this.adminQueries.updateGroup(groupId, updateGroupDto)) { throw new _common.HttpException('Unable to update group', _common.HttpStatus.INTERNAL_SERVER_ERROR); } // Clear whitelist caches when the group’s visibility is changed if (updateGroupDto.visibility !== undefined) { this.adminQueries.usersQueries.clearWhiteListCaches('*'); } return this.adminQueries.groupFromId(groupId); } async deleteGroup(groupId) { if (await this.adminQueries.deleteGroup(groupId)) { this.logger.log(`${this.deleteGroup.name} - group (${groupId}) was deleted`); } else { this.logger.warn(`${this.deleteGroup.name} - group (${groupId}) does not exist`); throw new _common.HttpException('Unable to delete group', _common.HttpStatus.BAD_REQUEST); } } async addUsersToGroup(groupId, userIds) { const group = await this.adminQueries.groupFromId(groupId); if (!group) { throw new _common.HttpException('Group not found', _common.HttpStatus.NOT_FOUND); } try { await this.adminQueries.addUsersToGroup(groupId, userIds, group.type === _group.GROUP_TYPE.USER ? _user.USER_ROLE.USER : undefined); } catch (e) { throw new _common.HttpException(e.message, _common.HttpStatus.BAD_REQUEST); } } async updateUserFromGroup(groupId, userId, updateUserFromGroupDto) { try { await this.adminQueries.updateUserFromGroup(groupId, userId, updateUserFromGroupDto.role); } catch (e) { throw new _common.HttpException(e.message, _common.HttpStatus.BAD_REQUEST); } } async removeUserFromGroup(groupId, userId) { try { await this.adminQueries.removeUserFromGroup(groupId, userId); } catch (e) { throw new _common.HttpException(e.message, _common.HttpStatus.BAD_REQUEST); } } searchMembers(searchMembersDto) { return this.adminQueries.usersQueries.searchUsersOrGroups(searchMembersDto); } async impersonateUser(admin, userId, res) { if (admin.id === userId) { throw new _common.HttpException('You are already logged in', _common.HttpStatus.BAD_REQUEST); } const user = this.checkUser(await this.adminQueries.usersQueries.from(userId)); user.impersonatedFromId = admin.id; user.impersonatedClientId = admin.clientId; return this.authManager.setCookies(user, res); } async logoutImpersonateUser(user, res) { if (!user.impersonatedFromId) { throw new _common.HttpException('You are not allowed to do this action', _common.HttpStatus.FORBIDDEN); } const admin = this.checkUser(await this.adminQueries.usersQueries.from(user.impersonatedFromId)); if (!admin.isAdmin) { throw new _common.HttpException('You are not allowed to do this action', _common.HttpStatus.FORBIDDEN); } admin.clientId = user.impersonatedClientId; return this.authManager.setCookies(admin, res); } async deleteUserSpace(userLogin, isGuest = false) { const userSpace = _usermodel.UserModel.getHomePath(userLogin, isGuest); try { if (await (0, _files.isPathExists)(userSpace)) { await (0, _files.removeFiles)(userSpace); this.logger.log(`${this.deleteUserSpace.name} - user space *${userLogin}* was deleted`); } else { this.logger.warn(`${this.deleteUserSpace.name} - user space *${userLogin}* does not exist : ${userSpace}`); } } catch (e) { this.logger.warn(`${this.deleteUserSpace.name} - user space *${userLogin}* (${userSpace}) was not deleted : ${e}`); throw new _common.HttpException('Unable to delete user space', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } checkUser(user, checkOnly = false) { if (!user) { throw new _common.HttpException('User not found', _common.HttpStatus.NOT_FOUND); } if (!checkOnly) { return new _usermodel.UserModel(user, true); } } async renameUserSpace(oldLogin, newLogin) { const currentUserSpace = _usermodel.UserModel.getHomePath(oldLogin); if (!await (0, _files.isPathExists)(currentUserSpace)) { this.logger.warn(`${this.renameUserSpace.name} - user space *${oldLogin}* does not exist : ${currentUserSpace}`); return false; } const newUserSpace = _usermodel.UserModel.getHomePath(newLogin); if (await (0, _files.isPathExists)(newUserSpace)) { this.logger.warn(`${this.renameUserSpace.name} - user space *${newLogin}* already exists : ${newUserSpace}`); return false; } try { await (0, _files.moveFiles)(currentUserSpace, newUserSpace); return true; } catch (e) { // try to restore await (0, _files.moveFiles)(newUserSpace, currentUserSpace, true); this.logger.error(`${this.renameUserSpace.name} - unable to rename user space from *${currentUserSpace}* to *${newUserSpace}* : ${e}`); return false; } } async checkGroupNameExists(groupName) { if (await this.adminQueries.usersQueries.checkGroupNameExists(groupName)) { throw new _common.HttpException('Name already used', _common.HttpStatus.BAD_REQUEST); } } async loginOrEmailAlreadyUsed(login, email) { const exists = await this.adminQueries.usersQueries.checkUserExists(login, email); if (exists) { throw new _common.HttpException(`${exists.login === login ? 'Login' : 'Email'} already used`, _common.HttpStatus.BAD_REQUEST); } } constructor(authManager, adminQueries){ this.authManager = authManager; this.adminQueries = adminQueries; this.logger = new _common.Logger(AdminUsersManager.name); } }; AdminUsersManager = _ts_decorate([ (0, _common.Injectable)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _authmanagerservice.AuthManager === "undefined" ? Object : _authmanagerservice.AuthManager, typeof _adminusersqueriesservice.AdminUsersQueries === "undefined" ? Object : _adminusersqueriesservice.AdminUsersQueries ]) ], AdminUsersManager); //# sourceMappingURL=admin-users-manager.service.js.map