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
|
|||
|
};
|