Reflex/backend/controllers/deviceSecurityController.js
Professional 96cf4cb0db фикс
2025-05-26 18:42:01 +07:00

456 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const BlockedDevice = require('../models/BlockedDevice');
const User = require('../models/User');
const { blockUserDevice, unblockDevice, getBlockedDevices } = require('../middleware/deviceBlockMiddleware');
/**
* Контроллер для управления блокировками устройств
*/
// @desc Проверка блокировки устройства
// @route POST /api/security/check-device
// @access Public
const checkDeviceBlockStatus = async (req, res) => {
try {
const { fingerprint, deviceInfo } = req.body;
const deviceFingerprint = fingerprint || req.deviceFingerprint;
if (!deviceFingerprint) {
return res.status(400).json({
message: 'Device fingerprint требуется для проверки безопасности',
code: 'DEVICE_FINGERPRINT_REQUIRED'
});
}
console.log('[SECURITY] Проверка блокировки устройства:', deviceFingerprint.substring(0, 16) + '...');
// Проверяем, заблокировано ли устройство
const blockedDevice = await BlockedDevice.isDeviceBlocked(deviceFingerprint);
if (blockedDevice) {
console.log('[SECURITY] Устройство заблокировано:', blockedDevice._id);
// Записываем попытку доступа
await blockedDevice.addBypassAttempt({
type: 'api_request',
ipAddress: req.ip || req.connection.remoteAddress,
userAgent: req.headers['user-agent']
});
return res.status(403).json({
blocked: true,
message: 'Доступ с данного устройства заблокирован',
reason: blockedDevice.reason,
blockedAt: blockedDevice.blockedAt,
code: 'DEVICE_BLOCKED'
});
}
// Обновляем информацию об устройстве
if (deviceInfo) {
// Можно сохранить информацию об активном устройстве для мониторинга
console.log('[SECURITY] Активное устройство:', {
fingerprint: deviceFingerprint.substring(0, 16) + '...',
userAgent: deviceInfo.userAgent,
platform: deviceInfo.platform
});
}
res.json({
blocked: false,
message: 'Устройство не заблокировано'
});
} catch (error) {
console.error('[SECURITY] Ошибка при проверке блокировки устройства:', error);
res.status(500).json({
message: 'Ошибка системы безопасности',
code: 'SECURITY_CHECK_ERROR'
});
}
};
// @desc Отчет о подозрительной активности
// @route POST /api/security/report-suspicious
// @access Private
const reportSuspiciousActivity = async (req, res) => {
try {
const { activities, deviceInfo } = req.body;
const deviceFingerprint = req.deviceFingerprint;
if (!deviceFingerprint) {
return res.status(400).json({
message: 'Device fingerprint требуется для отчета',
code: 'DEVICE_FINGERPRINT_REQUIRED'
});
}
console.log('[SECURITY] Получен отчет о подозрительной активности:', {
fingerprint: deviceFingerprint.substring(0, 16) + '...',
activitiesCount: activities?.length || 0,
userId: req.user?._id
});
// Анализируем активность на предмет угроз
const riskScore = calculateRiskScore(activities, deviceInfo);
if (riskScore > 80) {
console.warn('[SECURITY] Высокий уровень риска обнаружен:', riskScore);
// Автоматическая блокировка при высоком риске
if (req.user) {
await blockUserDevice(
req.user._id,
req.user._id, // Автоматическая блокировка
`Автоматическая блокировка: высокий уровень риска (${riskScore})`,
deviceFingerprint
);
console.log('[SECURITY] Устройство автоматически заблокировано из-за высокого риска');
return res.status(403).json({
blocked: true,
message: 'Устройство заблокировано из-за подозрительной активности',
reason: 'Автоматическая блокировка системы безопасности',
code: 'DEVICE_BLOCKED'
});
}
}
// Сохраняем отчет для анализа администраторами
// Можно создать отдельную модель SuspiciousActivity или логировать
console.log('[SECURITY] Отчет о подозрительной активности сохранен');
res.json({
message: 'Отчет получен и обработан',
riskScore,
action: riskScore > 80 ? 'blocked' : 'monitored'
});
} catch (error) {
console.error('[SECURITY] Ошибка при обработке отчета о подозрительной активности:', error);
res.status(500).json({
message: 'Ошибка обработки отчета безопасности'
});
}
};
// @desc Блокировка устройства (админ)
// @route POST /api/admin/block-device
// @access Private/Admin
const blockDevice = async (req, res) => {
try {
const { userId, deviceFingerprint, reason } = req.body;
if (!userId || !deviceFingerprint || !reason) {
return res.status(400).json({
message: 'ID пользователя, device fingerprint и причина обязательны'
});
}
// Проверяем, существует ли пользователь
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({
message: 'Пользователь не найден'
});
}
// Блокируем устройство
const blockedDevice = await blockUserDevice(
userId,
req.user._id,
reason,
deviceFingerprint
);
console.log('[ADMIN] Устройство заблокировано администратором:', {
deviceId: blockedDevice._id,
userId,
adminId: req.user._id,
reason
});
res.status(201).json({
message: 'Устройство успешно заблокировано',
blockedDevice: {
id: blockedDevice._id,
deviceFingerprint: blockedDevice.deviceFingerprint,
reason: blockedDevice.reason,
blockedAt: blockedDevice.blockedAt
}
});
} catch (error) {
console.error('[ADMIN] Ошибка при блокировке устройства:', error);
res.status(500).json({
message: 'Ошибка при блокировке устройства',
error: error.message
});
}
};
// @desc Разблокировка устройства (админ)
// @route POST /api/admin/unblock-device
// @access Private/Admin
const unblockDeviceAdmin = async (req, res) => {
try {
const { deviceFingerprint, reason } = req.body;
if (!deviceFingerprint) {
return res.status(400).json({
message: 'Device fingerprint обязателен'
});
}
// Разблокируем устройство
const device = await unblockDevice(
deviceFingerprint,
req.user._id,
reason || 'Разблокировано администратором'
);
console.log('[ADMIN] Устройство разблокировано администратором:', {
deviceId: device._id,
adminId: req.user._id,
reason
});
res.json({
message: 'Устройство успешно разблокировано',
device: {
id: device._id,
deviceFingerprint: device.deviceFingerprint,
unblockedAt: new Date()
}
});
} catch (error) {
console.error('[ADMIN] Ошибка при разблокировке устройства:', error);
res.status(500).json({
message: 'Ошибка при разблокировке устройства',
error: error.message
});
}
};
// @desc Получение списка заблокированных устройств
// @route GET /api/admin/blocked-devices
// @access Private/Admin
const getBlockedDevicesList = async (req, res) => {
try {
const {
page = 1,
limit = 20,
sortBy = 'blockedAt',
sortOrder = 'desc',
isActive = 'true',
userId
} = req.query;
const filters = {
page: parseInt(page),
limit: parseInt(limit),
sortBy,
sortOrder,
isActive: isActive === 'true',
userId
};
const result = await getBlockedDevices(filters);
console.log('[ADMIN] Запрос списка заблокированных устройств:', {
adminId: req.user._id,
filters,
totalItems: result.pagination.totalItems
});
res.json({
success: true,
data: result.devices,
pagination: result.pagination
});
} catch (error) {
console.error('[ADMIN] Ошибка при получении списка заблокированных устройств:', error);
res.status(500).json({
message: 'Ошибка при получении списка заблокированных устройств',
error: error.message
});
}
};
// @desc Получение детальной информации о заблокированном устройстве
// @route GET /api/admin/blocked-devices/:id
// @access Private/Admin
const getBlockedDeviceDetails = async (req, res) => {
try {
const { id } = req.params;
const device = await BlockedDevice.findById(id)
.populate('blockedBy', 'name email')
.populate('blockedUserId', 'name email')
.populate('unblockRequests.requestedBy', 'name email')
.populate('unblockRequests.reviewedBy', 'name email');
if (!device) {
return res.status(404).json({
message: 'Заблокированное устройство не найдено'
});
}
console.log('[ADMIN] Запрос деталей заблокированного устройства:', {
deviceId: id,
adminId: req.user._id
});
res.json({
success: true,
data: device
});
} catch (error) {
console.error('[ADMIN] Ошибка при получении деталей заблокированного устройства:', error);
res.status(500).json({
message: 'Ошибка при получении информации об устройстве',
error: error.message
});
}
};
// @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
});
}
};
/**
* Вычисляет уровень риска на основе подозрительной активности
*/
function calculateRiskScore(activities, deviceInfo) {
let score = 0;
if (!activities || activities.length === 0) return 0;
activities.forEach(activity => {
switch (activity.type) {
case 'fingerprint_change':
score += 30; // Изменение fingerprint - высокий риск
break;
case 'multiple_login_attempts':
score += 20;
break;
case 'suspicious_user_agent':
score += 15;
break;
case 'rapid_requests':
score += 10;
break;
default:
score += 5;
}
});
// Дополнительные факторы риска
if (activities.length > 5) score += 10; // Много событий
if (deviceInfo?.visitCount === 1) score += 15; // Новое устройство
return Math.min(score, 100); // Максимум 100
}
module.exports = {
checkDeviceBlockStatus,
reportSuspiciousActivity,
blockDevice,
unblockDeviceAdmin,
getBlockedDevicesList,
getBlockedDeviceDetails,
getUserDevices,
blockUserDevices
};