361 lines
12 KiB
JavaScript
361 lines
12 KiB
JavaScript
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
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Вычисляет уровень риска на основе подозрительной активности
|
||
*/
|
||
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
|
||
}; |