Reflex/backend/middleware/deviceBlockMiddleware.js

231 lines
8.6 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');
/**
* 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
};