Описание изменений

This commit is contained in:
2025-03-06 21:31:29 +03:00
parent 3157ad0cd9
commit 765637f2d0
57 changed files with 6240 additions and 3695 deletions

View File

@@ -1,130 +1,132 @@
const { createError } = require('./errorHandler');
const authService = require('../services/auth-service');
const logger = require('../utils/logger');
const { getUserInfo } = require('../utils/access-check');
const { USER_ROLES } = require('../utils/constants');
const db = require('../db');
// Добавьте в начало файла
const isMiddleware = true;
// Middleware для проверки роли
const requireRole = (allowedRoles) => async (req, res, next) => {
if (!req.session || !req.session.authenticated || !req.session.userId) {
return res.status(401).json({ error: 'Требуется аутентификация' });
/**
* Middleware для проверки аутентификации
*/
function requireAuth(req, res, next) {
console.log('Session in requireAuth:', req.session);
if (!req.session || !req.session.authenticated) {
return next(createError(401, 'Требуется аутентификация'));
}
next();
}
/**
* Middleware для проверки прав администратора
*/
async function requireAdmin(req, res, next) {
try {
// Получение информации о пользователе
const userInfo = await getUserInfo(req.session.userId);
if (!userInfo) {
return res.status(401).json({ error: 'Пользователь не найден' });
}
// Проверка роли
if (!allowedRoles.includes(userInfo.role)) {
return res.status(403).json({ error: 'Недостаточно прав' });
}
next();
} catch (error) {
logger.error('Error checking user role:', error);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
}
};
// Проверка роли пользователя
const checkRole = async (req, res, next) => {
try {
// Если функция вызвана как middleware
const isMiddleware = typeof next === 'function';
if (!req.session.authenticated) {
return isMiddleware ? res.status(401).json({ error: 'Не авторизован' }) : false;
// Проверка аутентификации
if (!req.session || !req.session.authenticated) {
return next(createError('Требуется аутентификация', 401));
}
// Если роль администратора уже проверена в сессии
if (req.session.isAdmin === true) {
return isMiddleware ? next() : true;
// Проверка через сессию
if (req.session.isAdmin) {
return next();
}
const db = require('../db');
// Проверка наличия токенов доступа в смарт-контракте
// Проверка через кошелек
if (req.session.address) {
const address = req.session.address.toLowerCase();
// Проверка в базе данных
const userRole = await db.query(
'SELECT r.name FROM users u JOIN roles r ON u.role_id = r.id WHERE LOWER(u.address) = $1',
[address]
);
if (userRole.rows.length > 0 && userRole.rows[0].name === 'admin') {
const isAdmin = await authService.checkAdminToken(req.session.address);
if (isAdmin) {
// Обновляем сессию
req.session.isAdmin = true;
return isMiddleware ? next() : true;
}
// Проверка токенов в смарт-контракте через сервис
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider(process.env.PROVIDER_URL);
const accessTokenABI = require('../artifacts/contracts/AccessToken.sol/AccessToken.json').abi;
const accessTokenContract = new ethers.Contract(
process.env.ACCESS_TOKEN_ADDRESS,
accessTokenABI,
provider
);
try {
const hasAdminRole = await accessTokenContract.hasRole(
ethers.keccak256(ethers.toUtf8Bytes('ADMIN_ROLE')),
address
);
if (hasAdminRole) {
// Обновляем роль в базе данных
await db.query(
'UPDATE users SET role_id = (SELECT id FROM roles WHERE name = $1) WHERE LOWER(address) = $2',
['admin', address]
);
req.session.isAdmin = true;
return isMiddleware ? next() : true;
}
} catch (error) {
console.error('Ошибка при проверке роли в контракте:', error);
return next();
}
}
// Если пользователь не администратор
req.session.isAdmin = false;
return isMiddleware ? res.status(403).json({ error: 'Недостаточно прав' }) : false;
// Проверка через ID пользователя
if (req.session.userId) {
const userResult = await db.query('SELECT role FROM users WHERE id = $1', [req.session.userId]);
if (userResult.rows.length > 0 && userResult.rows[0].role === USER_ROLES.ADMIN) {
// Обновляем сессию
req.session.isAdmin = true;
return next();
}
}
// Если ни одна проверка не прошла
return next(createError('Доступ запрещен', 403));
} catch (error) {
console.error('Ошибка при проверке роли:', error);
return isMiddleware ? res.status(500).json({ error: 'Внутренняя ошибка сервера' }) : false;
logger.error(`Error in requireAdmin middleware: ${error.message}`);
return next(createError('Внутренняя ошибка сервера', 500));
}
};
}
// Middleware для проверки аутентификации
const requireAuth = (req, res, next) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
next();
};
/**
* Middleware для проверки определенной роли
* @param {string} role - Требуемая роль
*/
function requireRole(role) {
return async (req, res, next) => {
try {
// Проверка аутентификации
if (!req.session || !req.session.authenticated) {
return next(createError('Требуется аутентификация', 401));
}
// Middleware для проверки прав администратора
const requireAdmin = (req, res, next) => {
if (!req.session || !req.session.authenticated) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
if (!req.session.isAdmin) {
return res.status(403).json({ error: 'Требуются права администратора' });
}
next();
};
// Для администраторов разрешаем все
if (req.session.isAdmin) {
return next();
}
// Проверка через ID пользователя
if (req.session.userId) {
const userResult = await db.query('SELECT role FROM users WHERE id = $1', [req.session.userId]);
if (userResult.rows.length > 0 && userResult.rows[0].role === role) {
return next();
}
}
// Если проверка не прошла
return next(createError('Доступ запрещен', 403));
} catch (error) {
logger.error(`Error in requireRole middleware: ${error.message}`);
return next(createError('Внутренняя ошибка сервера', 500));
}
};
}
/**
* Проверяет роль пользователя
* @param {string} role - Роль для проверки
*/
function checkRole(role) {
return async (req, res, next) => {
try {
// Если пользователь не аутентифицирован, просто продолжаем
if (!req.session || !req.session.authenticated) {
req.hasRole = false;
return next();
}
// Проверка через ID пользователя
if (req.session.userId) {
const userResult = await db.query('SELECT role FROM users WHERE id = $1', [req.session.userId]);
if (userResult.rows.length > 0 && userResult.rows[0].role === role) {
req.hasRole = true;
return next();
}
}
req.hasRole = false;
next();
} catch (error) {
logger.error(`Error in checkRole middleware: ${error.message}`);
req.hasRole = false;
next();
}
};
}
module.exports = {
requireRole,
requireAuth,
requireAdmin,
checkRole,
requireRole,
checkRole
};

View File

@@ -0,0 +1,71 @@
const logger = require('../utils/logger');
const { ERROR_CODES } = require('../utils/constants');
/**
* Middleware для обработки ошибок
*/
function errorHandler(err, req, res, next) {
// Логируем ошибку
logger.error(`Error: ${err.message}`, {
stack: err.stack,
url: req.originalUrl,
method: req.method,
ip: req.ip,
userId: req.session?.userId
});
// Определяем тип ошибки
let statusCode = 500;
let errorCode = ERROR_CODES.INTERNAL_ERROR;
let errorMessage = 'Внутренняя ошибка сервера';
// Обрабатываем разные типы ошибок
if (err.name === 'UnauthorizedError' || err.status === 401) {
statusCode = 401;
errorCode = ERROR_CODES.UNAUTHORIZED;
errorMessage = 'Требуется аутентификация';
} else if (err.status === 403) {
statusCode = 403;
errorCode = ERROR_CODES.FORBIDDEN;
errorMessage = 'Доступ запрещен';
} else if (err.status === 404) {
statusCode = 404;
errorCode = ERROR_CODES.NOT_FOUND;
errorMessage = 'Ресурс не найден';
} else if (err.status === 400) {
statusCode = 400;
errorCode = ERROR_CODES.BAD_REQUEST;
errorMessage = err.message || 'Некорректный запрос';
}
// В режиме разработки возвращаем стек ошибки
const devError = process.env.NODE_ENV === 'development'
? { stack: err.stack }
: {};
// Отправляем ответ клиенту
res.status(statusCode).json({
error: {
code: errorCode,
message: errorMessage,
...devError
}
});
}
/**
* Функция для создания ошибок с определенным статусом
* @param {string} message - Сообщение об ошибке
* @param {number} status - HTTP-статус ошибки
* @returns {Error} - Объект ошибки
*/
function createError(message, status) {
const error = new Error(message);
error.status = status;
return error;
}
module.exports = {
errorHandler,
createError
};

View File

@@ -0,0 +1,56 @@
const logger = require('../utils/logger');
const { ERROR_CODES } = require('../utils/constants');
/**
* Middleware для обработки ошибок
*/
function errorMiddleware(err, req, res, next) {
// Логируем ошибку
logger.error(`Error: ${err.message}`, {
stack: err.stack,
url: req.originalUrl,
method: req.method,
ip: req.ip,
userId: req.session?.userId
});
// Определяем тип ошибки
let statusCode = 500;
let errorCode = ERROR_CODES.INTERNAL_ERROR;
let errorMessage = 'Внутренняя ошибка сервера';
// Обрабатываем разные типы ошибок
if (err.name === 'UnauthorizedError' || err.status === 401) {
statusCode = 401;
errorCode = ERROR_CODES.UNAUTHORIZED;
errorMessage = 'Требуется аутентификация';
} else if (err.status === 403) {
statusCode = 403;
errorCode = ERROR_CODES.FORBIDDEN;
errorMessage = 'Доступ запрещен';
} else if (err.status === 404) {
statusCode = 404;
errorCode = ERROR_CODES.NOT_FOUND;
errorMessage = 'Ресурс не найден';
} else if (err.status === 400) {
statusCode = 400;
errorCode = ERROR_CODES.BAD_REQUEST;
errorMessage = err.message || 'Некорректный запрос';
}
// В режиме разработки возвращаем стек ошибки
const devError = process.env.NODE_ENV === 'development'
? { stack: err.stack }
: {};
// Отправляем ответ клиенту
res.status(statusCode).json({
error: {
code: errorCode,
message: errorMessage,
...devError
}
});
}
module.exports = errorMiddleware;

View File

@@ -1,12 +1,14 @@
const logger = (req, res, next) => {
const logger = require('../utils/logger');
const requestLogger = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`);
logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`);
});
next();
};
module.exports = logger;
module.exports = requestLogger;

View File

@@ -4,18 +4,18 @@ const { pool } = require('../db');
const sessionMiddleware = session({
store: new pgSession({
pool: pool,
pool,
tableName: 'session',
createTableIfMissing: true,
}),
secret: process.env.SESSION_SECRET || 'your-secret-key',
resave: false,
saveUninitialized: false,
saveUninitialized: true,
cookie: {
secure: process.env.NODE_ENV === 'production', // В production должно быть true
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 дней
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000, // 24 часа
sameSite: 'none', // Для работы между разными доменами
secure: process.env.NODE_ENV === 'production', // В production должно быть true
sameSite: 'lax', // Попробуйте изменить на 'none' если используете разные домены
},
});