Files
DLE/backend/app.js

163 lines
4.6 KiB
JavaScript

const express = require('express');
const cors = require('cors');
const session = require('express-session');
const pgSession = require('connect-pg-simple')(session);
const { pool } = require('./db');
const helmet = require('helmet');
const path = require('path');
const logger = require('./utils/logger');
const authService = require('./services/auth-service');
const { errorHandler, AppError, ErrorTypes } = require('./middleware/errorHandler');
const aiAssistant = require('./services/ai-assistant');
const crypto = require('crypto');
// Импорт маршрутов
const authRoutes = require('./routes/auth');
const usersRoutes = require('./routes/users');
const identitiesRoutes = require('./routes/identities');
const chatRoutes = require('./routes/chat');
const adminRoutes = require('./routes/admin');
const app = express();
// Настройка CORS
app.use(cors({
origin: 'http://localhost:5173',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Cookie']
}));
// Настройка сессии
app.use(session({
store: new pgSession({
pool,
tableName: 'session',
}),
secret: process.env.SESSION_SECRET || 'hb3atoken',
name: 'sessionId',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 30 * 24 * 60 * 60 * 1000,
httpOnly: true,
secure: false,
sameSite: 'lax',
path: '/'
}
}));
// Добавим middleware для проверки сессии
app.use(async (req, res, next) => {
console.log('Request cookies:', req.headers.cookie);
console.log('Session ID:', req.sessionID);
// Проверяем сессию в базе данных
if (req.sessionID) {
const result = await pool.query(
'SELECT sess FROM session WHERE sid = $1',
[req.sessionID]
);
console.log('Session from DB:', result.rows[0]?.sess);
}
// Если сессия уже есть, используем её
if (req.session.authenticated) {
return next();
}
// Проверяем заголовок авторизации
const authHeader = req.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.split(' ')[1];
try {
// Находим пользователя по токену
const { rows } = await pool.query(`
SELECT u.id,
(u.role = 'admin') as is_admin,
u.address
FROM users u
WHERE u.id = $1
`, [token]);
if (rows.length > 0) {
const user = rows[0];
req.session.userId = user.id;
req.session.address = user.address;
req.session.isAdmin = user.is_admin;
req.session.authenticated = true;
await new Promise(resolve => req.session.save(resolve));
}
} catch (error) {
console.error('Error checking auth header:', error);
}
}
next();
});
// Настройка парсеров
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Настройка безопасности
app.use(helmet({
contentSecurityPolicy: false // Отключаем CSP для разработки
}));
// Логирование запросов
app.use((req, res, next) => {
logger.info(`${req.method} ${req.url}`);
next();
});
// Маршруты API
app.use('/api/auth', authRoutes);
app.use('/api/users', usersRoutes);
app.use('/api/identities', identitiesRoutes);
app.use('/api/chat', chatRoutes);
app.use('/api/admin', adminRoutes);
const nonceStore = new Map(); // или любая другая реализация хранилища nonce
console.log('SESSION_SECRET:', process.env.SESSION_SECRET);
// Добавляем обработчик ошибок последним
app.use(errorHandler);
// Эндпоинт для проверки состояния
app.get('/api/health', async (req, res) => {
try {
// Проверяем подключение к БД
await pool.query('SELECT NOW()');
// Проверяем AI сервис
const aiStatus = await aiAssistant.checkHealth();
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
database: 'connected',
ai: aiStatus
});
} catch (error) {
logger.error('Health check failed:', error);
res.status(500).json({
status: 'error',
error: error.message
});
}
});
// Очистка старых сессий
setInterval(async () => {
try {
await pool.query('DELETE FROM session WHERE expire < NOW()');
} catch (error) {
console.error('Error cleaning old sessions:', error);
}
}, 15 * 60 * 1000); // Каждые 15 минут
module.exports = { app, nonceStore };