- Клиентская часть Vue 3 + Vite - Серверная часть Node.js + WebSocket - Система авторизации и смен - Управление игровыми портами - Поддержка тем (светлая/темная) - Адаптивный дизайн 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
196 lines
9.3 KiB
JavaScript
196 lines
9.3 KiB
JavaScript
"use strict";
|
||
|
||
const fs = require('node:fs/promises');
|
||
const path = require('path');
|
||
const crypto = require('crypto');
|
||
|
||
// Функция генерации случайного хэша для сессии (как в старом коде)
|
||
const genHash = (length) => {
|
||
const chars = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890';
|
||
let result = '';
|
||
for (let i = 0; i < length; i++) {
|
||
result += chars[Math.floor(Math.random() * chars.length)];
|
||
}
|
||
return result;
|
||
};
|
||
|
||
// Функция генерации хэша пароля как в оригинальной системе
|
||
const generatePasswordHash = (password) => {
|
||
// Шаг 1: MD5 от пароля
|
||
const firstHash = crypto.createHash('md5').update(password).digest('hex');
|
||
// Шаг 2: MD5 от (первый_хэш + "pult2024")
|
||
const finalHash = crypto.createHash('md5').update(firstHash + "pult2024").digest('hex');
|
||
return finalHash;
|
||
};
|
||
|
||
exports.go = async (req, res, postData, urlParsed) => {
|
||
try {
|
||
console.log('[api/auth] Запрос авторизации пользователя:', {
|
||
phone: postData.phone,
|
||
hasPassword: !!postData.password,
|
||
hasHash: !!postData.hash
|
||
});
|
||
|
||
// Нормализуем номер телефона (убираем все кроме цифр)
|
||
const normalizedPhone = postData.phone ? postData.phone.replace(/\D/g, '') : null;
|
||
|
||
if (!normalizedPhone) {
|
||
return res.end(JSON.stringify({
|
||
success: false,
|
||
error: "Не указан номер телефона"
|
||
}));
|
||
}
|
||
|
||
// Читаем данные пользователей и сессионных хэшей
|
||
let avt = {};
|
||
let hash = {};
|
||
|
||
try {
|
||
const avtData = await fs.readFile(path.join(__dirname, '../data/avt.ini'), 'utf8');
|
||
avt = JSON.parse(avtData);
|
||
console.log('[api/auth] Загружены пользователи:', Object.keys(avt).length);
|
||
} catch (error) {
|
||
console.error('[api/auth] Ошибка чтения avt.ini:', error);
|
||
return res.end(JSON.stringify({
|
||
success: false,
|
||
error: "Ошибка загрузки данных пользователей"
|
||
}));
|
||
}
|
||
|
||
try {
|
||
const hashData = await fs.readFile(path.join(__dirname, '../data/hash.ini'), 'utf8');
|
||
hash = JSON.parse(hashData);
|
||
} catch (error) {
|
||
console.warn('[api/auth] Файл hash.ini не найден или пуст, создаем новый');
|
||
hash = {};
|
||
}
|
||
|
||
let user = false;
|
||
|
||
// АВТОРИЗАЦИЯ ПО ПАРОЛЮ (как в старом коде)
|
||
if (postData.password && normalizedPhone in avt) {
|
||
console.log('[api/auth] Попытка авторизации по паролю для:', normalizedPhone);
|
||
|
||
// Генерируем хэш пароля по оригинальной схеме: MD5(MD5(пароль) + "pult2024")
|
||
const inputPasswordHash = generatePasswordHash(postData.password);
|
||
console.log('[api/auth] Схема: MD5(MD5(пароль) + "pult2024")');
|
||
console.log('[api/auth] Хэш введенного пароля:', inputPasswordHash);
|
||
console.log('[api/auth] Хэш из базы:', avt[normalizedPhone].pass);
|
||
|
||
// Сравниваем хэши по правильной схеме
|
||
if (avt[normalizedPhone].pass === inputPasswordHash) {
|
||
console.log('[api/auth] ✅ Пароль верен!');
|
||
|
||
// Копируем данные пользователя без пароля
|
||
user = JSON.parse(JSON.stringify(avt[normalizedPhone]));
|
||
delete user.pass;
|
||
if (user.groupz && user.groupz.access) delete user.groupz.access;
|
||
|
||
// Генерируем сессионный хэш
|
||
hash[normalizedPhone] = genHash(15);
|
||
user.hash = hash[normalizedPhone];
|
||
|
||
// Сохраняем сессионный хэш
|
||
await fs.writeFile(path.join(__dirname, '../data/hash.ini'), JSON.stringify(hash));
|
||
|
||
console.log('[api/auth] Создан сессионный хэш:', user.hash);
|
||
} else {
|
||
console.log('[api/auth] ❌ Неверный пароль');
|
||
}
|
||
}
|
||
|
||
// АВТОРИЗАЦИЯ ПО СЕССИОННОМУ ХЭШУ (как в старом коде)
|
||
if (postData.hash && normalizedPhone in hash && normalizedPhone in avt && hash[normalizedPhone] === postData.hash) {
|
||
console.log('[api/auth] ✅ Авторизация по сессионному хэшу успешна');
|
||
|
||
user = JSON.parse(JSON.stringify(avt[normalizedPhone]));
|
||
user.hash = hash[normalizedPhone];
|
||
delete user.pass;
|
||
if (user.groupz && user.groupz.access) delete user.groupz.access;
|
||
}
|
||
|
||
// ФОРМИРУЕМ ОТВЕТ
|
||
if (user !== false) {
|
||
console.log('[api/auth] ✅ Авторизация успешна для:', user.fio || user._id);
|
||
|
||
// Определяем роль пользователя
|
||
let userRole = 'operator';
|
||
console.log('[api/auth] Данные пользователя для определения роли:', {
|
||
taccess: user.taccess,
|
||
access: user.access,
|
||
groupz: user.groupz
|
||
});
|
||
|
||
if (user.taccess) {
|
||
// Простая обработка строковой роли
|
||
if (user.taccess === 'technics') {
|
||
userRole = 'technic';
|
||
} else if (user.taccess === 'operators') {
|
||
userRole = 'operator';
|
||
} else {
|
||
userRole = user.taccess;
|
||
}
|
||
console.log('[api/auth] Роль установлена из taccess:', user.taccess, '-> преобразована в:', userRole);
|
||
} else if (user.access && user.access.fullaccess) {
|
||
userRole = 'admin';
|
||
console.log('[api/auth] Роль установлена как admin из access.fullaccess');
|
||
} else if (user.groupz && user.groupz.name) {
|
||
const groupName = user.groupz.name.toLowerCase();
|
||
console.log('[api/auth] Анализ группы:', groupName);
|
||
if (groupName.includes('программист') || groupName.includes('админ')) {
|
||
userRole = 'admin';
|
||
console.log('[api/auth] Роль установлена как admin из группы');
|
||
} else if (groupName.includes('оператор')) {
|
||
userRole = 'operator';
|
||
console.log('[api/auth] Роль установлена как operator из группы');
|
||
} else if (groupName.includes('техник')) {
|
||
userRole = 'technic';
|
||
console.log('[api/auth] Роль установлена как technic из группы');
|
||
}
|
||
}
|
||
|
||
console.log('[api/auth] Финальная роль пользователя:', userRole);
|
||
|
||
// Возвращаем данные в формате React
|
||
const response = {
|
||
success: true,
|
||
user: {
|
||
id: user._id || normalizedPhone,
|
||
name: user.fio || user.name || 'Пользователь',
|
||
phone: normalizedPhone,
|
||
role: userRole, // Возвращаем простую строковую роль
|
||
isAuthenticated: true,
|
||
hash: user.hash, // Сессионный хэш для последующих запросов
|
||
// Дополнительные данные
|
||
group: user.groupz ? user.groupz.name : null,
|
||
color: user.color || null,
|
||
balance: user.bal || null,
|
||
serverConnected: global.conn_to_server || false
|
||
}
|
||
};
|
||
|
||
// Логируем отправляемого пользователя в отдельный файл
|
||
const fsSync = require('fs');
|
||
try {
|
||
fsSync.appendFileSync('./avt-server.log', JSON.stringify(response, null, 2) + '\n');
|
||
} catch (e) {
|
||
console.error('[api/auth] Ошибка записи avt-server.log:', e);
|
||
}
|
||
|
||
res.end(JSON.stringify(response));
|
||
} else {
|
||
console.log('[api/auth] ❌ Авторизация не удалась');
|
||
res.end(JSON.stringify({
|
||
success: false,
|
||
error: "Неверный логин или пароль"
|
||
}));
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('[api/auth] Критическая ошибка:', error);
|
||
res.end(JSON.stringify({
|
||
success: false,
|
||
error: "Внутренняя ошибка сервера"
|
||
}));
|
||
}
|
||
};
|