Reflex/backend/middleware/deviceBlockMiddleware.js

231 lines
8.6 KiB
JavaScript
Raw Normal View History

const BlockedDevice = require('../models/BlockedDevice');
/**
* Middleware для проверки блокировки устройства
* Должен использоваться перед аутентификацией
*/
const checkDeviceBlock = async (req, res, next) => {
try {
console.log('[DEVICE_CHECK] Проверка блокировки устройства');
// Получаем fingerprint устройства из заголовков запроса
const deviceFingerprint = req.headers['x-device-fingerprint'];
if (!deviceFingerprint) {
console.log('[DEVICE_CHECK] Device fingerprint не предоставлен');
return res.status(400).json({
message: 'Требуется идентификация устройства для обеспечения безопасности',
code: 'DEVICE_FINGERPRINT_REQUIRED'
});
}
console.log('[DEVICE_CHECK] Проверяем fingerprint:', deviceFingerprint.substring(0, 16) + '...');
// Проверяем, заблокировано ли устройство
const blockedDevice = await BlockedDevice.isDeviceBlocked(deviceFingerprint);
if (blockedDevice) {
console.log('[DEVICE_CHECK] Устройство заблокировано:', {
deviceId: blockedDevice._id,
blockedAt: blockedDevice.blockedAt,
reason: blockedDevice.reason
});
// Записываем попытку обхода блокировки
await blockedDevice.addBypassAttempt({
type: req.route?.path?.includes('/login') ? 'login' :
req.route?.path?.includes('/register') ? 'register' : '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'
});
}
// Проверяем похожие заблокированные устройства
const similarDevices = await BlockedDevice.findSimilarDevices(deviceFingerprint, 0.85);
if (similarDevices.length > 0) {
console.log('[DEVICE_CHECK] Найдены похожие заблокированные устройства:', similarDevices.length);
// Повышаем уровень безопасности для похожих устройств
req.securityRisk = 'HIGH';
req.similarBlockedDevices = similarDevices;
// Можно добавить дополнительные проверки для подозрительных устройств
// Например, CAPTCHA или дополнительную верификацию
}
// Сохраняем fingerprint в запросе для дальнейшего использования
req.deviceFingerprint = deviceFingerprint;
req.deviceInfo = {
userAgent: req.headers['user-agent'],
ipAddress: req.ip || req.connection.remoteAddress,
screenResolution: req.headers['x-screen-resolution'],
platform: req.headers['x-platform'],
language: req.headers['x-language'],
timezone: req.headers['x-timezone']
};
console.log('[DEVICE_CHECK] Устройство не заблокировано, продолжаем');
next();
} catch (error) {
console.error('[DEVICE_CHECK] Ошибка при проверке блокировки устройства:', error);
// В случае ошибки системы безопасности, блокируем доступ
return res.status(500).json({
message: 'Ошибка системы безопасности. Попробуйте позже.',
code: 'SECURITY_CHECK_ERROR'
});
}
};
/**
* Middleware для записи информации об устройстве при успешной аутентификации
*/
const recordDeviceActivity = async (req, res, next) => {
try {
if (req.deviceFingerprint && req.user) {
console.log('[DEVICE_RECORD] Записываем активность устройства для пользователя:', req.user._id);
// Можно сохранить информацию об устройстве пользователя для анализа
// Например, в отдельной коллекции UserDevices
// Пока просто логируем
console.log('[DEVICE_RECORD] Device fingerprint:', req.deviceFingerprint.substring(0, 16) + '...');
console.log('[DEVICE_RECORD] Device info:', req.deviceInfo);
}
next();
} catch (error) {
console.error('[DEVICE_RECORD] Ошибка при записи активности устройства:', error);
// Не блокируем запрос из-за ошибки записи
next();
}
};
/**
* Функция для блокировки устройства пользователя
*/
const blockUserDevice = async (userId, adminId, reason, deviceFingerprint = null) => {
try {
console.log('[BLOCK_DEVICE] Блокировка устройства пользователя:', userId);
if (!deviceFingerprint) {
// Если fingerprint не предоставлен, нужно найти его в активных сессиях
// Это более сложная задача, требующая отслеживания активных сессий
throw new Error('Device fingerprint не предоставлен для блокировки');
}
const deviceInfo = {
// Получаем дополнительную информацию об устройстве из базы данных или сессии
// Это может быть реализовано через отслеживание активных подключений
};
const blockedDevice = await BlockedDevice.blockDevice({
deviceFingerprint,
blockedBy: adminId,
blockedUserId: userId,
reason,
deviceInfo
});
console.log('[BLOCK_DEVICE] Устройство заблокировано:', blockedDevice._id);
return blockedDevice;
} catch (error) {
console.error('[BLOCK_DEVICE] Ошибка при блокировке устройства:', error);
throw error;
}
};
/**
* Функция для разблокировки устройства
*/
const unblockDevice = async (deviceFingerprint, adminId, reason) => {
try {
console.log('[UNBLOCK_DEVICE] Разблокировка устройства:', deviceFingerprint.substring(0, 16) + '...');
const blockedDevice = await BlockedDevice.findOne({
deviceFingerprint,
isActive: true
});
if (!blockedDevice) {
throw new Error('Заблокированное устройство не найдено');
}
await blockedDevice.unblock(adminId, reason);
console.log('[UNBLOCK_DEVICE] Устройство разблокировано');
return blockedDevice;
} catch (error) {
console.error('[UNBLOCK_DEVICE] Ошибка при разблокировке устройства:', error);
throw error;
}
};
/**
* Функция для получения информации о заблокированных устройствах
*/
const getBlockedDevices = async (filters = {}) => {
try {
const {
page = 1,
limit = 20,
sortBy = 'blockedAt',
sortOrder = 'desc',
isActive = true,
userId
} = filters;
const query = { isActive };
if (userId) {
query.blockedUserId = userId;
}
const skip = (page - 1) * limit;
const sort = { [sortBy]: sortOrder === 'desc' ? -1 : 1 };
const devices = await BlockedDevice.find(query)
.populate('blockedBy', 'name email')
.populate('blockedUserId', 'name email')
.sort(sort)
.skip(skip)
.limit(limit);
const total = await BlockedDevice.countDocuments(query);
return {
devices,
pagination: {
currentPage: page,
totalPages: Math.ceil(total / limit),
totalItems: total,
itemsPerPage: limit
}
};
} catch (error) {
console.error('[GET_BLOCKED_DEVICES] Ошибка при получении заблокированных устройств:', error);
throw error;
}
};
module.exports = {
checkDeviceBlock,
recordDeviceActivity,
blockUserDevice,
unblockDevice,
getBlockedDevices
};