Reflex/backend/controllers/deviceSecurityController.js

456 lines
15 KiB
JavaScript
Raw Normal View History

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
});
}
};
2025-05-26 18:42:01 +07:00
// @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,
2025-05-26 18:42:01 +07:00
getBlockedDeviceDetails,
getUserDevices,
blockUserDevices
};