Тестовый коммит после удаления husky

This commit is contained in:
2025-03-05 01:02:09 +03:00
parent 97ca5e4b64
commit 3157ad0cd9
118 changed files with 8177 additions and 8530 deletions

View File

@@ -1,7 +1,7 @@
const express = require('express');
const cors = require('cors');
const session = require('express-session');
const { verifySignature } = require('./utils/auth');
const { verifySignature, findOrCreateUser } = require('./utils/auth');
const pgSession = require('connect-pg-simple')(session);
const { requireRole } = require('./middleware/auth');
const crypto = require('crypto');
@@ -9,6 +9,13 @@ const path = require('path');
const fs = require('fs');
const { router: authRouter } = require('./routes/auth');
const { pool } = require('./db');
const FileStore = require('session-file-store')(session);
const helmet = require('helmet');
const sessionMiddleware = require('./middleware/session');
const chatRouter = require('./routes/chat');
const usersRoutes = require('./routes/users');
const contractsRoutes = require('./routes/contracts');
const rolesRoutes = require('./routes/roles');
const app = express();
@@ -20,74 +27,88 @@ function generateNonce() {
// Парсинг JSON - должен быть до всех роутов
app.use(express.json());
// Настройка CORS - должна быть первой после парсинга JSON
app.use(cors({
origin: ['http://127.0.0.1:5173', 'http://localhost:5173'],
credentials: true,
methods: ['GET', 'POST', 'OPTIONS', 'DELETE', 'PUT', 'HEAD'],
allowedHeaders: [
'Content-Type',
'X-Wallet-Address',
'X-Wallet-Signature',
'Cookie',
'Authorization'
],
exposedHeaders: ['Set-Cookie']
}));
// Настройка CORS
app.use(
cors({
origin: function(origin, callback) {
// Разрешаем запросы с любого источника в режиме разработки
const allowedOrigins = ['http://localhost:3000', 'http://127.0.0.1:5173', 'http://localhost:5173'];
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Auth-Nonce'],
})
);
// Настройка сессий
app.use(session({
store: new pgSession({
pool: pool,
tableName: 'session',
createTableIfMissing: true
}),
secret: process.env.SESSION_SECRET || 'your-secret-key',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: false,
sameSite: 'lax',
maxAge: 24 * 60 * 60 * 1000 // 24 часа
}
}));
app.use(
session({
store: new pgSession({
pool: pool,
tableName: 'sessions',
createTableIfMissing: false,
}),
secret: process.env.SESSION_SECRET || 'your-secret-key',
resave: false,
saveUninitialized: true,
name: 'dapp.sid',
cookie: {
secure: false,
httpOnly: true,
maxAge: 30 * 24 * 60 * 60 * 1000,
sameSite: 'lax',
},
})
);
// Middleware для логирования сессий
app.use((req, res, next) => {
// Восстанавливаем сессию из store если есть sessionID
if (req.sessionID && !req.session.authenticated) {
req.sessionStore.get(req.sessionID, (err, session) => {
if (err) {
console.error('Session restore error:', err);
} else if (session) {
req.session.authenticated = session.authenticated;
req.session.address = session.address;
req.session.lastSignature = session.lastSignature;
}
next();
});
} else {
next();
}
});
// Middleware для безопасности
app.use(
helmet({
contentSecurityPolicy: false, // Отключаем CSP для разработки
})
);
// Middleware для логирования
app.use((req, res, next) => {
console.log(`${req.method} ${req.path}`, {
headers: req.headers,
body: req.body,
session: req.session
session: req.session,
});
next();
});
// Middleware для сохранения сессии после каждого запроса
app.use((req, res, next) => {
const originalEnd = res.end;
res.end = function () {
if (req.session && req.session.save) {
req.session.save((err) => {
if (err) {
console.error('Ошибка при сохранении сессии:', err);
}
originalEnd.apply(res, arguments);
});
} else {
originalEnd.apply(res, arguments);
}
};
next();
});
// Middleware для проверки авторизации
const requireAuth = (req, res, next) => {
console.log('Auth check:', {
session: req.session,
authenticated: req.session.authenticated,
address: req.session.address
address: req.session.address,
});
if (!req.session.authenticated || !req.session.address) {
@@ -96,9 +117,68 @@ const requireAuth = (req, res, next) => {
next();
};
// Миддлвар для обновления дополнительных полей в таблице sessions
app.use(async (req, res, next) => {
try {
// Если есть адрес, но нет userId, найдем или создадим пользователя
if (req.session && req.session.authenticated && req.session.address && !req.session.userId) {
try {
const user = await findOrCreateUser(req.session.address, 'wallet');
req.session.userId = user.id;
req.session.role = user.role;
req.session.isAdmin = user.is_admin;
// Стандартизируем данные сессии
standardizeSessionData(req);
// Сохраняем обновленную сессию
await new Promise((resolve, reject) => {
req.session.save(err => {
if (err) reject(err);
else resolve();
});
});
} catch (err) {
console.error('Ошибка при обновлении userId в сессии:', err);
}
}
// Обновляем поля в таблице sessions
if (req.session && (req.session.userId || req.session.address)) {
db.query(
'UPDATE sessions SET last_activity = NOW(), user_id = $1, auth_channel = $2, language = $3 WHERE sid = $4',
[
req.session.userId || null,
req.session.authChannel || 'web',
req.session.language || 'en',
req.sessionID
]
).catch(err => console.error('Error updating session data:', err));
}
} catch (err) {
console.error('Ошибка в middleware сессий:', err);
}
next();
});
// Функция для стандартизации данных сессии
function standardizeSessionData(req) {
if (req.session.authenticated) {
// Убедимся, что все необходимые поля присутствуют
req.session.authType = req.session.authType || 'wallet';
req.session.role = req.session.role || 'USER';
req.session.isAdmin = !!req.session.isAdmin;
req.session.authChannel = req.session.authChannel || 'web';
req.session.language = req.session.language || 'en';
}
}
// API роуты
const apiRouter = express.Router();
// Удалите или закомментируйте этот блок кода
/*
apiRouter.post('/refresh-session', async (req, res) => {
try {
const { address, signature } = req.body;
@@ -143,17 +223,18 @@ apiRouter.post('/refresh-session', async (req, res) => {
res.status(500).json({ error: 'Internal server error' });
}
});
*/
apiRouter.get('/session', (req, res) => {
console.log('Session check:', {
session: req.session,
authenticated: req.session.authenticated,
address: req.session.address
address: req.session.address,
});
res.json({
authenticated: !!req.session.authenticated,
address: req.session.address || null
address: req.session.address || null,
});
});
@@ -180,12 +261,8 @@ apiRouter.get('/admin/check', async (req, res) => {
const ethers = require('ethers');
const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_NETWORK_URL);
const contractABI = require('./artifacts/contracts/MyContract.sol/MyContract.json').abi;
const contract = new ethers.Contract(
process.env.CONTRACT_ADDRESS,
contractABI,
provider
);
const contract = new ethers.Contract(process.env.CONTRACT_ADDRESS, contractABI, provider);
const contractOwner = await contract.owner();
const isAdmin = req.session.address.toLowerCase() === contractOwner.toLowerCase();
@@ -216,48 +293,51 @@ apiRouter.post('/verify', async (req, res) => {
try {
console.log('Получен запрос на верификацию в app.js:', req.body);
const { message, signature } = req.body;
if (!message || !signature) {
console.error('Отсутствуют необходимые поля:', { message: !!message, signature: !!signature });
console.error('Отсутствуют необходимые поля:', {
message: !!message,
signature: !!signature,
});
return res.status(400).json({ success: false, error: 'Missing required fields' });
}
// Проверяем, что message содержит адрес
if (!message.address) {
console.error('Отсутствует адрес в сообщении');
return res.status(400).json({ success: false, error: 'Missing address in message' });
}
// Получаем адрес из сообщения напрямую
const address = message.address;
console.log('Адрес из сообщения:', address);
// Устанавливаем сессию без проверки подписи
req.session.authenticated = true;
req.session.address = address;
req.session.lastSignature = signature;
// Сохраняем сессию
req.session.save((err) => {
if (err) {
console.error('Ошибка при сохранении сессии:', err);
return res.status(500).json({
success: false,
error: 'Session save failed',
message: err.message
return res.status(500).json({
success: false,
error: 'Session save failed',
message: err.message,
});
}
console.log('Сессия сохранена успешно:', req.sessionID);
return res.json({ success: true, address, isAdmin: true });
});
} catch (error) {
console.error('Подробная ошибка при верификации:', error.stack);
console.error('Verification error:', error);
res.status(500).json({
success: false,
error: 'Verification failed',
message: error.message || 'Unknown error'
res.status(500).json({
success: false,
error: 'Verification failed',
message: error.message || 'Unknown error',
});
}
});
@@ -267,27 +347,34 @@ app.use('/api', apiRouter);
// Подключаем маршруты аутентификации
app.use('/api/auth', authRouter);
app.use('/api/users', usersRoutes);
app.use('/api/contracts', contractsRoutes);
app.use('/api/chat', chatRouter);
app.use('/api/roles', rolesRoutes);
apiRouter.get('/nonce', (req, res) => {
const nonce = generateNonce();
console.log('Generated new nonce:', nonce);
// Сохраняем nonce в сессии
if (!req.session.nonces) {
req.session.nonces = [];
}
req.session.nonces.push(nonce);
// Ограничиваем количество nonce в сессии
if (req.session.nonces.length > 5) {
req.session.nonces.shift();
}
console.log('Nonces in session:', req.session.nonces);
res.json({ nonce });
});
// Добавьте после настройки сессий
app.use(sessionMiddleware);
// Обработка ошибок сессий
app.use((err, req, res, next) => {
if (err.code === 'ENOENT' && err.message.includes('sessions')) {
@@ -311,4 +398,8 @@ app.use((err, req, res, next) => {
res.status(500).json({ error: 'Something broke!' });
});
module.exports = { app };
// Подключаем маршруты для отладки
const debugRouter = require('./routes/debug');
app.use('/api/debug', debugRouter);
module.exports = { app };