172 lines
4.9 KiB
JavaScript
172 lines
4.9 KiB
JavaScript
const express = require('express');
|
||
const cors = require('cors');
|
||
const session = require('express-session');
|
||
const { SiweMessage, generateNonce } = require('siwe');
|
||
const path = require('path');
|
||
|
||
const app = express();
|
||
|
||
// Конфигурация CORS для работы с frontend
|
||
app.use(cors({
|
||
origin: ['http://localhost:5174', 'http://127.0.0.1:5173', 'http://localhost:5173'],
|
||
credentials: true,
|
||
methods: ['GET', 'POST'],
|
||
allowedHeaders: ['Content-Type', 'Accept']
|
||
}));
|
||
|
||
app.use(express.json());
|
||
app.use(express.urlencoded({ extended: true }));
|
||
|
||
// Настройка сессий
|
||
app.use(session({
|
||
name: 'siwe-dapp',
|
||
secret: "siwe-dapp-secret",
|
||
resave: true,
|
||
saveUninitialized: true,
|
||
cookie: {
|
||
secure: false,
|
||
sameSite: 'lax',
|
||
maxAge: 24 * 60 * 60 * 1000 // 24 часа
|
||
}
|
||
}));
|
||
|
||
// Логирование запросов
|
||
app.use((req, res, next) => {
|
||
console.log(`${req.method} ${req.url}`);
|
||
next();
|
||
});
|
||
|
||
// Генерация nonce
|
||
app.get('/nonce', (req, res) => {
|
||
try {
|
||
req.session.nonce = generateNonce();
|
||
console.log('Сгенерирован новый nonce:', req.session.nonce);
|
||
res.setHeader('Content-Type', 'application/json');
|
||
res.status(200).json({ nonce: req.session.nonce });
|
||
} catch (error) {
|
||
console.error('Ошибка генерации nonce:', error);
|
||
res.status(500).json({ error: 'Internal Server Error' });
|
||
}
|
||
});
|
||
|
||
// Верификация сообщения
|
||
app.post('/verify', async (req, res) => {
|
||
try {
|
||
const { signature, message } = req.body;
|
||
|
||
console.log('Получен запрос на верификацию:', {
|
||
signature: signature?.slice(0, 20) + '...',
|
||
message,
|
||
sessionNonce: req.session.nonce
|
||
});
|
||
|
||
if (!req.session.nonce) {
|
||
console.error('Сессия не содержит nonce');
|
||
throw new Error('Invalid session');
|
||
}
|
||
|
||
let siweMessage;
|
||
try {
|
||
siweMessage = new SiweMessage(message);
|
||
const fields = await siweMessage.validate(signature);
|
||
|
||
if (fields.nonce !== req.session.nonce) {
|
||
console.error('Nonce не совпадает');
|
||
throw new Error('Invalid nonce');
|
||
}
|
||
|
||
console.log('Сообщение успешно верифицировано');
|
||
req.session.siwe = fields;
|
||
req.session.authenticated = true;
|
||
req.session.nonce = null;
|
||
|
||
res.json({
|
||
success: true,
|
||
address: fields.address
|
||
});
|
||
} catch (error) {
|
||
console.error('Ошибка валидации сообщения:', error);
|
||
req.session.authenticated = false;
|
||
req.session.siwe = null;
|
||
req.session.nonce = null;
|
||
throw error;
|
||
}
|
||
} catch (error) {
|
||
console.error('Ошибка верификации:', error);
|
||
res.status(400).json({
|
||
success: false,
|
||
error: error.message
|
||
});
|
||
}
|
||
});
|
||
|
||
// Получение сессии
|
||
app.get('/session', (req, res) => {
|
||
try {
|
||
res.json({
|
||
authenticated: !!req.session.authenticated,
|
||
address: req.session.siwe?.address
|
||
});
|
||
} catch (error) {
|
||
console.error('Ошибка получения сессии:', error);
|
||
res.status(500).json({ error: 'Internal Server Error' });
|
||
}
|
||
});
|
||
|
||
// Выход
|
||
app.get('/signout', (req, res) => {
|
||
try {
|
||
req.session.destroy((err) => {
|
||
if (err) {
|
||
console.error('Ошибка при удалении сессии:', err);
|
||
return res.status(500).json({ error: 'Failed to destroy session' });
|
||
}
|
||
res.status(200).json({ success: true });
|
||
});
|
||
} catch (error) {
|
||
console.error('Ошибка выхода:', error);
|
||
res.status(500).json({ error: 'Internal Server Error' });
|
||
}
|
||
});
|
||
|
||
// Базовый маршрут
|
||
app.get('/', (req, res) => {
|
||
res.json({
|
||
status: 'ok',
|
||
endpoints: {
|
||
nonce: 'GET /nonce',
|
||
verify: 'POST /verify',
|
||
session: 'GET /session',
|
||
signout: 'GET /signout'
|
||
}
|
||
});
|
||
});
|
||
|
||
// Обработка 404
|
||
app.use((req, res) => {
|
||
console.log(`404: ${req.method} ${req.url}`);
|
||
res.status(404).json({
|
||
error: 'Not Found',
|
||
message: `Endpoint ${req.method} ${req.url} не существует`
|
||
});
|
||
});
|
||
|
||
// Обработка ошибок
|
||
app.use((err, req, res, next) => {
|
||
console.error('Ошибка сервера:', err);
|
||
res.status(500).json({
|
||
error: 'Internal Server Error',
|
||
message: err.message
|
||
});
|
||
});
|
||
|
||
const PORT = process.env.PORT || 3000;
|
||
app.listen(PORT, () => {
|
||
console.log(`SIWE сервер запущен на порту ${PORT}`);
|
||
console.log('Доступные эндпоинты:');
|
||
console.log(' GET / - Информация о сервере');
|
||
console.log(' GET /nonce - Получить nonce');
|
||
console.log(' POST /verify - Верифицировать сообщение');
|
||
console.log(' GET /session - Получить текущую сессию');
|
||
console.log(' GET /signout - Выйти из системы');
|
||
});
|