231 lines
8.6 KiB
JavaScript
231 lines
8.6 KiB
JavaScript
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
|
||
}; |