From 96cf4cb0dbe87a482b3365f31857e18a6e7297e6 Mon Sep 17 00:00:00 2001 From: Professional Date: Mon, 26 May 2025 18:42:01 +0700 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/deviceSecurityController.js | 97 ++++- backend/models/User.js | 60 +++ backend/routes/adminRoutes.js | 8 +- src/services/api.js | 8 + src/views/admin/AdminUserDetail.vue | 352 +++++++++++++++++- 5 files changed, 507 insertions(+), 18 deletions(-) diff --git a/backend/controllers/deviceSecurityController.js b/backend/controllers/deviceSecurityController.js index 8af2cc0..5583c10 100644 --- a/backend/controllers/deviceSecurityController.js +++ b/backend/controllers/deviceSecurityController.js @@ -317,6 +317,99 @@ const getBlockedDeviceDetails = async (req, res) => { } }; +// @desc Получение устройств пользователя +// @route GET /api/admin/user/:userId/devices +// @access Private/Admin +const getUserDevices = async (req, res) => { + try { + const { userId } = req.params; + + // Проверяем, существует ли пользователь + const user = await User.findById(userId); + if (!user) { + return res.status(404).json({ + message: 'Пользователь не найден' + }); + } + + // Получаем список устройств пользователя по его ID + const devices = await User.findUserDevices(userId); + + console.log(`[ADMIN] Запрос устройств пользователя ${userId}, найдено: ${devices.length}`); + + res.json({ + success: true, + data: devices + }); + + } catch (error) { + console.error('[ADMIN] Ошибка при получении устройств пользователя:', error); + res.status(500).json({ + message: 'Ошибка при получении устройств пользователя', + error: error.message + }); + } +}; + +// @desc Блокировка всех устройств пользователя +// @route POST /api/admin/user/:userId/block-devices +// @access Private/Admin +const blockUserDevices = async (req, res) => { + try { + const { userId } = req.params; + const { reason = 'Блокировка администратором', duration = 'permanent' } = req.body; + + // Проверяем, существует ли пользователь + const user = await User.findById(userId); + if (!user) { + return res.status(404).json({ + message: 'Пользователь не найден' + }); + } + + // Получаем все устройства пользователя + const devices = await User.findUserDevices(userId); + + if (!devices.length) { + return res.status(404).json({ + message: 'У пользователя не найдено устройств для блокировки' + }); + } + + // Блокируем каждое устройство + const blockedDevices = []; + for (const device of devices) { + try { + const blockedDevice = await blockUserDevice( + userId, + req.user._id, + reason, + device.fingerprint, + duration + ); + blockedDevices.push(blockedDevice); + } catch (err) { + console.error(`[ADMIN] Ошибка при блокировке устройства ${device.fingerprint}:`, err); + } + } + + console.log(`[ADMIN] Заблокированы устройства пользователя ${userId}, количество: ${blockedDevices.length}`); + + res.json({ + success: true, + message: `Заблокировано ${blockedDevices.length} из ${devices.length} устройств пользователя`, + blockedDevices + }); + + } catch (error) { + console.error('[ADMIN] Ошибка при блокировке устройств пользователя:', error); + res.status(500).json({ + message: 'Ошибка при блокировке устройств пользователя', + error: error.message + }); + } +}; + /** * Вычисляет уровень риска на основе подозрительной активности */ @@ -357,5 +450,7 @@ module.exports = { blockDevice, unblockDeviceAdmin, getBlockedDevicesList, - getBlockedDeviceDetails + getBlockedDeviceDetails, + getUserDevices, + blockUserDevices }; \ No newline at end of file diff --git a/backend/models/User.js b/backend/models/User.js index a1f3913..a4f8bb3 100644 --- a/backend/models/User.js +++ b/backend/models/User.js @@ -113,6 +113,66 @@ userSchema.methods.matchPassword = async function (enteredPassword) { return await bcrypt.compare(enteredPassword, this.password); }; +// Статический метод для получения устройств пользователя +userSchema.statics.findUserDevices = async function(userId) { + try { + // Получаем сессии и авторизации пользователя + const user = await this.findById(userId).select('authHistory devices sessions'); + + if (!user) return []; + + // Объединяем все возможные источники устройств + let devices = []; + + // Из истории авторизаций + if (user.authHistory && user.authHistory.length > 0) { + devices = devices.concat(user.authHistory.map(auth => ({ + fingerprint: auth.deviceFingerprint, + userAgent: auth.userAgent, + ipAddress: auth.ipAddress, + lastUsed: auth.timestamp, + type: 'auth' + }))); + } + + // Из списка устройств + if (user.devices && user.devices.length > 0) { + devices = devices.concat(user.devices.map(device => ({ + fingerprint: device.fingerprint, + userAgent: device.userAgent, + platform: device.platform, + lastUsed: device.lastActive, + type: 'device' + }))); + } + + // Из активных сессий + if (user.sessions && user.sessions.length > 0) { + devices = devices.concat(user.sessions.map(session => ({ + fingerprint: session.deviceFingerprint, + userAgent: session.userAgent, + ipAddress: session.ipAddress, + lastUsed: session.lastActive, + type: 'session' + }))); + } + + // Удаляем дубликаты по fingerprint + const uniqueDevices = Array.from( + devices.reduce((map, device) => { + if (device.fingerprint && !map.has(device.fingerprint)) { + map.set(device.fingerprint, device); + } + return map; + }, new Map()).values() + ); + + return uniqueDevices; + } catch (error) { + console.error('Ошибка при поиске устройств пользователя:', error); + return []; + } +}; const User = mongoose.model('User', userSchema); diff --git a/backend/routes/adminRoutes.js b/backend/routes/adminRoutes.js index ce40333..f72b517 100644 --- a/backend/routes/adminRoutes.js +++ b/backend/routes/adminRoutes.js @@ -13,7 +13,9 @@ const { blockDevice, unblockDeviceAdmin, getBlockedDevicesList, - getBlockedDeviceDetails + getBlockedDeviceDetails, + getUserDevices, + blockUserDevices } = require('../controllers/deviceSecurityController'); // Все маршруты защищены middleware для проверки авторизации и прав администратора @@ -44,4 +46,8 @@ router.get('/blocked-devices/:id', getBlockedDeviceDetails); router.post('/block-device', blockDevice); router.post('/unblock-device', unblockDeviceAdmin); +// Новые маршруты для управления устройствами пользователя +router.get('/user/:userId/devices', getUserDevices); +router.post('/user/:userId/block-devices', blockUserDevices); + module.exports = router; \ No newline at end of file diff --git a/src/services/api.js b/src/services/api.js index 6b90848..743c636 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -318,5 +318,13 @@ export default { }, unblockDevice(deviceFingerprint, reason) { return apiClient.post('/admin/unblock-device', { deviceFingerprint, reason }); + }, + + // Новые методы для управления устройствами пользователей + getUserDevices(userId) { + return apiClient.get(`/admin/user/${userId}/devices`); + }, + blockUserDevices(userId, data = {}) { + return apiClient.post(`/admin/user/${userId}/block-devices`, data); } }; \ No newline at end of file diff --git a/src/views/admin/AdminUserDetail.vue b/src/views/admin/AdminUserDetail.vue index 45d8679..34b5cd1 100644 --- a/src/views/admin/AdminUserDetail.vue +++ b/src/views/admin/AdminUserDetail.vue @@ -5,14 +5,26 @@ « Назад к списку пользователей - +
+ + + +
@@ -135,14 +147,80 @@
+ + +