ваше сообщение коммита
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../db');
|
||||
const { requireAdmin } = require('../middleware/auth');
|
||||
const authService = require('../services/auth-service');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
@@ -35,29 +35,28 @@ router.get('/nonce', async (req, res) => {
|
||||
|
||||
// Генерируем случайный nonce
|
||||
const nonce = crypto.randomBytes(16).toString('hex');
|
||||
|
||||
|
||||
// Проверяем, существует ли уже nonce для этого адреса
|
||||
const existingNonce = await db.query(
|
||||
'SELECT id FROM nonces WHERE identity_value = $1',
|
||||
[address.toLowerCase()]
|
||||
);
|
||||
|
||||
const existingNonce = await db.query('SELECT id FROM nonces WHERE identity_value = $1', [
|
||||
address.toLowerCase(),
|
||||
]);
|
||||
|
||||
if (existingNonce.rows.length > 0) {
|
||||
// Обновляем существующий nonce
|
||||
await db.query(
|
||||
'UPDATE nonces SET nonce = $1, expires_at = NOW() + INTERVAL \'15 minutes\' WHERE identity_value = $2',
|
||||
"UPDATE nonces SET nonce = $1, expires_at = NOW() + INTERVAL '15 minutes' WHERE identity_value = $2",
|
||||
[nonce, address.toLowerCase()]
|
||||
);
|
||||
} else {
|
||||
// Создаем новый nonce
|
||||
await db.query(
|
||||
'INSERT INTO nonces (identity_value, nonce, expires_at) VALUES ($1, $2, NOW() + INTERVAL \'15 minutes\')',
|
||||
"INSERT INTO nonces (identity_value, nonce, expires_at) VALUES ($1, $2, NOW() + INTERVAL '15 minutes')",
|
||||
[address.toLowerCase(), nonce]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
logger.info(`Nonce ${nonce} сохранен для адреса ${address}`);
|
||||
|
||||
|
||||
res.json({ nonce });
|
||||
} catch (error) {
|
||||
logger.error('Error generating nonce:', error);
|
||||
@@ -69,53 +68,58 @@ router.get('/nonce', async (req, res) => {
|
||||
router.post('/verify', async (req, res) => {
|
||||
try {
|
||||
const { address, message, signature } = req.body;
|
||||
|
||||
|
||||
logger.info(`[verify] Verifying signature for address: ${address}`);
|
||||
|
||||
|
||||
// Сохраняем гостевые ID до проверки
|
||||
const guestId = req.session.guestId;
|
||||
const previousGuestId = req.session.previousGuestId;
|
||||
|
||||
|
||||
// Проверяем подпись
|
||||
const isValid = await authService.verifySignature(message, signature, address);
|
||||
if (!isValid) {
|
||||
return res.status(401).json({ success: false, error: 'Invalid signature' });
|
||||
}
|
||||
|
||||
|
||||
// Нормализуем адрес для использования в запросах
|
||||
const normalizedAddress = ethers.getAddress(address).toLowerCase();
|
||||
|
||||
|
||||
// Проверяем nonce
|
||||
const nonceResult = await db.query('SELECT nonce FROM nonces WHERE identity_value = $1', [normalizedAddress]);
|
||||
if (nonceResult.rows.length === 0 || nonceResult.rows[0].nonce !== message.match(/Nonce: ([^\n]+)/)[1]) {
|
||||
const nonceResult = await db.query('SELECT nonce FROM nonces WHERE identity_value = $1', [
|
||||
normalizedAddress,
|
||||
]);
|
||||
if (
|
||||
nonceResult.rows.length === 0 ||
|
||||
nonceResult.rows[0].nonce !== message.match(/Nonce: ([^\n]+)/)[1]
|
||||
) {
|
||||
return res.status(401).json({ success: false, error: 'Invalid nonce' });
|
||||
}
|
||||
|
||||
|
||||
let userId;
|
||||
let isAdmin = false;
|
||||
|
||||
|
||||
// Проверяем, авторизован ли пользователь уже
|
||||
if (req.session.authenticated && req.session.userId) {
|
||||
// Если пользователь уже авторизован, привязываем кошелек к существующему пользователю
|
||||
userId = req.session.userId;
|
||||
logger.info(`[verify] Using existing authenticated user ${userId} for wallet ${normalizedAddress}`);
|
||||
|
||||
// Связываем кошелек с пользователем через identity-service для предотвращения дубликатов
|
||||
const linkResult = await authService.linkIdentity(
|
||||
userId,
|
||||
'wallet',
|
||||
address
|
||||
logger.info(
|
||||
`[verify] Using existing authenticated user ${userId} for wallet ${normalizedAddress}`
|
||||
);
|
||||
|
||||
|
||||
// Связываем кошелек с пользователем через identity-service для предотвращения дубликатов
|
||||
const linkResult = await authService.linkIdentity(userId, 'wallet', address);
|
||||
|
||||
if (!linkResult.success && linkResult.error) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: linkResult.error
|
||||
error: linkResult.error,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Если linkResult.message содержит 'already exists', значит кошелек уже привязан
|
||||
logger.info(`[verify] Wallet ${normalizedAddress} linked to user ${userId}: ${linkResult.message || 'success'}`);
|
||||
logger.info(
|
||||
`[verify] Wallet ${normalizedAddress} linked to user ${userId}: ${linkResult.message || 'success'}`
|
||||
);
|
||||
} else {
|
||||
// Находим или создаем пользователя, если не авторизован
|
||||
const result = await authService.findOrCreateUser(address);
|
||||
@@ -123,49 +127,48 @@ router.post('/verify', async (req, res) => {
|
||||
isAdmin = result.isAdmin;
|
||||
logger.info(`[verify] Found or created user ${userId} for wallet ${normalizedAddress}`);
|
||||
}
|
||||
|
||||
|
||||
// Сохраняем идентификаторы гостевой сессии
|
||||
if (guestId) {
|
||||
await identityService.saveIdentity(userId, 'guest', guestId, true);
|
||||
}
|
||||
|
||||
|
||||
if (previousGuestId && previousGuestId !== guestId) {
|
||||
await identityService.saveIdentity(userId, 'guest', previousGuestId, true);
|
||||
}
|
||||
|
||||
|
||||
// Проверяем наличие админских токенов
|
||||
const adminStatus = await authService.checkAdminTokens(normalizedAddress);
|
||||
|
||||
|
||||
if (adminStatus) {
|
||||
await db.query('UPDATE users SET role = $1 WHERE id = $2', ['admin', userId]);
|
||||
isAdmin = true;
|
||||
}
|
||||
|
||||
|
||||
// Обновляем сессию
|
||||
req.session.userId = userId;
|
||||
req.session.authenticated = true;
|
||||
req.session.authType = 'wallet';
|
||||
req.session.isAdmin = adminStatus || isAdmin;
|
||||
req.session.address = normalizedAddress; // Всегда сохраняем нормализованный адрес
|
||||
|
||||
|
||||
// Удаляем временный ID
|
||||
delete req.session.tempUserId;
|
||||
|
||||
|
||||
// Сохраняем сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
// Связываем гостевые сообщения с пользователем
|
||||
await sessionService.linkGuestMessages(req.session, userId);
|
||||
|
||||
|
||||
// Возвращаем успешный ответ
|
||||
return res.json({
|
||||
success: true,
|
||||
userId,
|
||||
address: normalizedAddress, // Возвращаем нормализованный адрес
|
||||
isAdmin: adminStatus || isAdmin,
|
||||
authenticated: true
|
||||
authenticated: true,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('[verify] Error:', error);
|
||||
res.status(500).json({ success: false, error: 'Server error' });
|
||||
@@ -176,17 +179,17 @@ router.post('/verify', async (req, res) => {
|
||||
router.post('/telegram/verify', async (req, res) => {
|
||||
try {
|
||||
const { telegramId, verificationCode } = req.body;
|
||||
|
||||
|
||||
if (!telegramId || !verificationCode) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields'
|
||||
error: 'Missing required fields',
|
||||
});
|
||||
}
|
||||
|
||||
// Сохраняем гостевой ID из текущей сессии
|
||||
const guestId = req.session.guestId;
|
||||
|
||||
|
||||
// Передаем сессию в метод верификации
|
||||
const verificationResult = await authService.verifyTelegramAuth(
|
||||
telegramId,
|
||||
@@ -197,7 +200,7 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
if (!verificationResult.success) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: verificationResult.error || 'Verification failed'
|
||||
error: verificationResult.error || 'Verification failed',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -205,9 +208,9 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
req.session.regenerate(async (err) => {
|
||||
if (err) {
|
||||
logger.error('[telegram/verify] Error regenerating session:', err);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Session error'
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Session error',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -217,7 +220,7 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
req.session.authType = 'telegram';
|
||||
req.session.authenticated = true;
|
||||
req.session.role = verificationResult.role;
|
||||
|
||||
|
||||
// Восстанавливаем гостевой ID, если он был
|
||||
if (guestId) {
|
||||
req.session.guestId = guestId;
|
||||
@@ -236,14 +239,14 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
userId: verificationResult.userId,
|
||||
role: verificationResult.role,
|
||||
telegramId,
|
||||
isNewUser: verificationResult.isNewUser
|
||||
isNewUser: verificationResult.isNewUser,
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[telegram/verify] Error:', error);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
error: 'Internal server error',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -252,26 +255,26 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
router.post('/email/request', authLimiter, async (req, res) => {
|
||||
try {
|
||||
const { email } = req.body;
|
||||
|
||||
|
||||
if (!email || !email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
|
||||
return res.status(400).json({ error: 'Invalid email format' });
|
||||
}
|
||||
|
||||
|
||||
// Инициализация email аутентификации
|
||||
const result = await emailAuth.initEmailAuth(req.session, email);
|
||||
|
||||
|
||||
// Сохраняем сессию после установки pendingEmail
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
if (result.success) {
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Код подтверждения отправлен на email'
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Код подтверждения отправлен на email',
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: result.error || 'Ошибка отправки кода'
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: result.error || 'Ошибка отправки кода',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -284,150 +287,155 @@ router.post('/email/request', authLimiter, async (req, res) => {
|
||||
router.post('/email/verify-code', async (req, res) => {
|
||||
try {
|
||||
const { code, email } = req.body;
|
||||
|
||||
|
||||
if (!code) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Код подтверждения обязателен'
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Код подтверждения обязателен',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Если email передан в запросе, сохраняем его в сессии
|
||||
if (email && !req.session.pendingEmail) {
|
||||
req.session.pendingEmail = email.toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
if (!req.session.pendingEmail) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Email не найден в сессии. Пожалуйста, запросите код подтверждения снова.'
|
||||
error: 'Email не найден в сессии. Пожалуйста, запросите код подтверждения снова.',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Сохраняем гостевой ID до проверки
|
||||
const guestId = req.session.guestId;
|
||||
const previousGuestId = req.session.previousGuestId;
|
||||
|
||||
|
||||
// Проверяем код через сервис верификации
|
||||
const verificationResult = await verificationService.verifyCode(
|
||||
code,
|
||||
'email',
|
||||
code,
|
||||
'email',
|
||||
req.session.pendingEmail
|
||||
);
|
||||
|
||||
|
||||
if (!verificationResult.success) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: verificationResult.error || 'Неверный код подтверждения'
|
||||
error: verificationResult.error || 'Неверный код подтверждения',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Получаем или создаем пользователя
|
||||
let userId;
|
||||
let isNewAuth = false;
|
||||
|
||||
|
||||
// Проверяем, авторизован ли пользователь
|
||||
if (req.session.authenticated && req.session.userId) {
|
||||
// Связываем email с существующим пользователем
|
||||
userId = req.session.userId;
|
||||
logger.info(`[email/verify-code] Linking email ${req.session.pendingEmail} to existing authenticated user ${userId}`);
|
||||
|
||||
// Связываем email с текущим аккаунтом
|
||||
const linkResult = await authService.linkIdentity(
|
||||
userId,
|
||||
'email',
|
||||
req.session.pendingEmail
|
||||
logger.info(
|
||||
`[email/verify-code] Linking email ${req.session.pendingEmail} to existing authenticated user ${userId}`
|
||||
);
|
||||
|
||||
|
||||
// Связываем email с текущим аккаунтом
|
||||
const linkResult = await authService.linkIdentity(userId, 'email', req.session.pendingEmail);
|
||||
|
||||
// Сохраняем email в сессии
|
||||
req.session.email = req.session.pendingEmail;
|
||||
|
||||
|
||||
// Удаляем временные данные
|
||||
delete req.session.pendingEmail;
|
||||
|
||||
|
||||
// Сохраняем сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
return res.json({
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
userId,
|
||||
email: req.session.email,
|
||||
authenticated: true,
|
||||
linked: true
|
||||
linked: true,
|
||||
});
|
||||
} else {
|
||||
// Если пользователь не авторизован, ищем существующего пользователя или создаем нового
|
||||
|
||||
|
||||
// Ищем существующего пользователя по email
|
||||
const existingUser = await identityService.findUserByIdentity(
|
||||
'email',
|
||||
'email',
|
||||
req.session.pendingEmail
|
||||
);
|
||||
|
||||
|
||||
if (existingUser) {
|
||||
// Используем существующего пользователя
|
||||
userId = existingUser.id;
|
||||
logger.info(`[email/verify-code] Using existing user ${userId} with email ${req.session.pendingEmail}`);
|
||||
logger.info(
|
||||
`[email/verify-code] Using existing user ${userId} with email ${req.session.pendingEmail}`
|
||||
);
|
||||
} else if (req.session.userId) {
|
||||
// Используем текущего пользователя
|
||||
userId = req.session.userId;
|
||||
logger.info(`[email/verify-code] Using current user ${userId} for email ${req.session.pendingEmail}`);
|
||||
logger.info(
|
||||
`[email/verify-code] Using current user ${userId} for email ${req.session.pendingEmail}`
|
||||
);
|
||||
} else if (req.session.tempUserId) {
|
||||
// Используем временного пользователя
|
||||
userId = req.session.tempUserId;
|
||||
logger.info(`[email/verify-code] Using temporary user ${userId} for email ${req.session.pendingEmail}`);
|
||||
logger.info(
|
||||
`[email/verify-code] Using temporary user ${userId} for email ${req.session.pendingEmail}`
|
||||
);
|
||||
} else {
|
||||
// Создаем нового пользователя
|
||||
const newUser = await db.query(
|
||||
'INSERT INTO users (role) VALUES ($1) RETURNING id',
|
||||
['user']
|
||||
);
|
||||
const newUser = await db.query('INSERT INTO users (role) VALUES ($1) RETURNING id', [
|
||||
'user',
|
||||
]);
|
||||
userId = newUser.rows[0].id;
|
||||
isNewAuth = true;
|
||||
logger.info(`[email/verify-code] Created new user ${userId} for email ${req.session.pendingEmail}`);
|
||||
logger.info(
|
||||
`[email/verify-code] Created new user ${userId} for email ${req.session.pendingEmail}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Сохраняем email как идентификатор
|
||||
await identityService.saveIdentity(userId, 'email', req.session.pendingEmail, true);
|
||||
|
||||
|
||||
// Сохраняем гостевые идентификаторы
|
||||
if (guestId) {
|
||||
await identityService.saveIdentity(userId, 'guest', guestId, true);
|
||||
}
|
||||
|
||||
|
||||
if (previousGuestId && previousGuestId !== guestId) {
|
||||
await identityService.saveIdentity(userId, 'guest', previousGuestId, true);
|
||||
}
|
||||
|
||||
|
||||
// Устанавливаем сессию
|
||||
req.session.userId = userId;
|
||||
req.session.authenticated = true;
|
||||
req.session.authType = 'email';
|
||||
req.session.email = req.session.pendingEmail;
|
||||
|
||||
|
||||
// Удаляем временные данные
|
||||
delete req.session.tempUserId;
|
||||
delete req.session.pendingEmail;
|
||||
|
||||
|
||||
// Сохраняем сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
// Связываем гостевые сообщения
|
||||
await sessionService.linkGuestMessages(req.session, userId);
|
||||
|
||||
return res.json({
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
userId,
|
||||
email: req.session.email,
|
||||
authenticated: true,
|
||||
isNewAuth
|
||||
isNewAuth,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[email/verify-code] Error:', error);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка сервера'
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка сервера',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -436,29 +444,29 @@ router.post('/email/verify-code', async (req, res) => {
|
||||
router.post('/telegram/init', async (req, res) => {
|
||||
try {
|
||||
const { verificationCode, botLink } = await initTelegramAuth(req.session);
|
||||
|
||||
|
||||
if (!verificationCode || !botLink) {
|
||||
throw new Error('Failed to generate verification code');
|
||||
}
|
||||
|
||||
res.json({
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
verificationCode,
|
||||
botLink
|
||||
verificationCode,
|
||||
botLink,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error initializing Telegram auth:', error);
|
||||
|
||||
|
||||
if (error.message === 'Telegram уже привязан к этому аккаунту') {
|
||||
return res.status(400).json({
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: error.message
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to initialize Telegram auth'
|
||||
error: 'Failed to initialize Telegram auth',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -467,29 +475,29 @@ router.post('/telegram/init', async (req, res) => {
|
||||
router.post('/email/init', async (req, res) => {
|
||||
try {
|
||||
const { email } = req.body;
|
||||
|
||||
|
||||
if (!email || !email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Некорректный формат email'
|
||||
error: 'Некорректный формат email',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Инициализация email аутентификации
|
||||
const result = await emailAuth.initEmailAuth(req.session, email);
|
||||
|
||||
|
||||
// Сохраняем сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: 'Код верификации отправлен на email'
|
||||
message: 'Код верификации отправлен на email',
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error in email auth initialization:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Внутренняя ошибка сервера'
|
||||
error: 'Внутренняя ошибка сервера',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -499,21 +507,20 @@ router.get('/check', async (req, res) => {
|
||||
try {
|
||||
const authenticated = req.session.authenticated || false;
|
||||
const authType = req.session.authType || null;
|
||||
|
||||
|
||||
let identities = [];
|
||||
let isAdmin = false;
|
||||
|
||||
|
||||
if (authenticated && req.session.userId) {
|
||||
// Если пользователь аутентифицирован, получаем его идентификаторы из БД
|
||||
try {
|
||||
identities = await identityService.getUserIdentities(req.session.userId);
|
||||
|
||||
|
||||
// Проверяем роль пользователя
|
||||
const roleResult = await db.query(
|
||||
'SELECT role FROM users WHERE id = $1',
|
||||
[req.session.userId]
|
||||
);
|
||||
|
||||
const roleResult = await db.query('SELECT role FROM users WHERE id = $1', [
|
||||
req.session.userId,
|
||||
]);
|
||||
|
||||
if (roleResult.rows.length > 0) {
|
||||
isAdmin = roleResult.rows[0].role === 'admin';
|
||||
req.session.isAdmin = isAdmin;
|
||||
@@ -522,15 +529,15 @@ router.get('/check', async (req, res) => {
|
||||
logger.error(`[session/check] Error fetching identities: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Проверяем, нужно ли создать новый гостевой ID
|
||||
if (!authenticated && !req.session.guestId) {
|
||||
req.session.guestId = crypto.randomBytes(16).toString('hex');
|
||||
|
||||
|
||||
// Сохраняем сессию с новым гостевым ID
|
||||
await sessionService.saveSession(req.session);
|
||||
}
|
||||
|
||||
|
||||
// Формируем ответ
|
||||
const response = {
|
||||
success: true,
|
||||
@@ -539,9 +546,9 @@ router.get('/check', async (req, res) => {
|
||||
guestId: req.session.guestId || null,
|
||||
authType,
|
||||
identitiesCount: identities.length,
|
||||
isAdmin: isAdmin || false
|
||||
isAdmin: isAdmin || false,
|
||||
};
|
||||
|
||||
|
||||
// Добавляем специфические поля в зависимости от типа аутентификации
|
||||
if (authType === 'wallet') {
|
||||
response.address = req.session.address || null;
|
||||
@@ -556,13 +563,13 @@ router.get('/check', async (req, res) => {
|
||||
response.telegramFirstName = req.session.telegramFirstName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return res.json(response);
|
||||
} catch (error) {
|
||||
logger.error('[session/check] Error:', error);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
error: 'Internal server error',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -609,7 +616,7 @@ router.get('/check-access', requireAuth, async (req, res) => {
|
||||
|
||||
if (address) {
|
||||
const isAdmin = await authService.checkAdminTokens(address);
|
||||
|
||||
|
||||
// Обновляем сессию
|
||||
req.session.isAdmin = isAdmin;
|
||||
await sessionService.saveSession(req.session);
|
||||
@@ -618,7 +625,7 @@ router.get('/check-access', requireAuth, async (req, res) => {
|
||||
success: true,
|
||||
isAdmin,
|
||||
userId,
|
||||
address
|
||||
address,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -626,9 +633,8 @@ router.get('/check-access', requireAuth, async (req, res) => {
|
||||
success: true,
|
||||
isAdmin: false,
|
||||
userId,
|
||||
address: null
|
||||
address: null,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Error checking access:', error);
|
||||
return res.status(500).json({ error: 'Internal server error' });
|
||||
@@ -639,22 +645,22 @@ router.get('/check-access', requireAuth, async (req, res) => {
|
||||
router.post('/refresh-session', async (req, res) => {
|
||||
try {
|
||||
const { address } = req.body;
|
||||
|
||||
|
||||
if (req.session && req.session.authenticated) {
|
||||
logger.info('Обновление сессии для пользователя:', req.session.userId);
|
||||
|
||||
|
||||
// Обновляем время жизни сессии
|
||||
req.session.cookie.maxAge = 30 * 24 * 60 * 60 * 1000; // 30 дней
|
||||
|
||||
|
||||
// Сохраняем обновленную сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
return res.json({ success: true });
|
||||
} else if (address) {
|
||||
// Если сессия не аутентифицирована, но есть адрес
|
||||
try {
|
||||
const user = await identityService.findUserByIdentity('wallet', address.toLowerCase());
|
||||
|
||||
|
||||
if (user) {
|
||||
// Обновляем сессию
|
||||
req.session.authenticated = true;
|
||||
@@ -662,17 +668,17 @@ router.post('/refresh-session', async (req, res) => {
|
||||
req.session.address = address.toLowerCase();
|
||||
req.session.isAdmin = user.role === 'admin';
|
||||
req.session.authType = 'wallet';
|
||||
|
||||
|
||||
// Сохраняем обновленную сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
return res.json({ success: true });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при проверке пользователя:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Если не удалось обновить сессию, возвращаем успех=false, но не ошибку
|
||||
return res.json({ success: false });
|
||||
} catch (error) {
|
||||
@@ -685,82 +691,78 @@ router.post('/refresh-session', async (req, res) => {
|
||||
router.post('/wallet', async (req, res) => {
|
||||
try {
|
||||
const { address, nonce, signature } = req.body;
|
||||
|
||||
|
||||
if (!address || !nonce || !signature) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields'
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Missing required fields',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Сохраняем гостевые ID до аутентификации
|
||||
const guestId = req.session.guestId;
|
||||
const previousGuestId = req.session.previousGuestId;
|
||||
|
||||
// Формируем сообщение для проверки
|
||||
const message = `Sign this message to authenticate with HB3 DApp: ${nonce}`;
|
||||
|
||||
|
||||
// Проверяем подпись
|
||||
const validSignature = await authService.verifySignature(message, signature, address);
|
||||
if (!validSignature) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid signature'
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid signature',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Получаем или создаем пользователя
|
||||
const { userId } = await authService.findOrCreateUser(address);
|
||||
|
||||
|
||||
// Проверяем наличие админских токенов
|
||||
const isAdmin = await authService.checkAdminTokens(address);
|
||||
|
||||
|
||||
// Обновляем роль пользователя в базе данных, если нужно
|
||||
if (isAdmin) {
|
||||
await db.query(
|
||||
'UPDATE users SET role = $1 WHERE id = $2',
|
||||
['admin', userId]
|
||||
);
|
||||
await db.query('UPDATE users SET role = $1 WHERE id = $2', ['admin', userId]);
|
||||
}
|
||||
|
||||
|
||||
// Сохраняем идентификаторы
|
||||
await identityService.saveIdentity(userId, 'wallet', address.toLowerCase(), true);
|
||||
|
||||
|
||||
if (guestId) {
|
||||
await identityService.saveIdentity(userId, 'guest', guestId, true);
|
||||
}
|
||||
|
||||
|
||||
if (previousGuestId && previousGuestId !== guestId) {
|
||||
await identityService.saveIdentity(userId, 'guest', previousGuestId, true);
|
||||
}
|
||||
|
||||
|
||||
// Устанавливаем сессию
|
||||
req.session.userId = userId;
|
||||
req.session.address = address.toLowerCase();
|
||||
req.session.authType = 'wallet';
|
||||
req.session.authenticated = true;
|
||||
req.session.isAdmin = isAdmin;
|
||||
|
||||
|
||||
// Сохраняем сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
|
||||
// Связываем гостевые сообщения с пользователем
|
||||
await sessionService.linkGuestMessages(req.session, userId);
|
||||
|
||||
|
||||
// Возвращаем успешный ответ
|
||||
return res.json({
|
||||
success: true,
|
||||
userId,
|
||||
address,
|
||||
isAdmin,
|
||||
authenticated: true
|
||||
authenticated: true,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('[wallet] Error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Server error during wallet authentication'
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Server error during wallet authentication',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -769,19 +771,19 @@ router.post('/wallet', async (req, res) => {
|
||||
router.get('/identities', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { userId } = req.session;
|
||||
|
||||
|
||||
// Получаем все идентификаторы пользователя
|
||||
const identities = await identityService.getUserIdentities(userId);
|
||||
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
identities
|
||||
identities,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error getting user identities:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
error: 'Internal server error',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -794,17 +796,17 @@ router.get('/check-session', async (req, res) => {
|
||||
req.session.guestId = crypto.randomBytes(16).toString('hex');
|
||||
await sessionService.saveSession(req.session);
|
||||
}
|
||||
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
guestId: req.session.guestId,
|
||||
isAuthenticated: req.session.authenticated || false
|
||||
isAuthenticated: req.session.authenticated || false,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error checking session:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
error: 'Internal server error',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -813,21 +815,21 @@ router.get('/check-session', async (req, res) => {
|
||||
router.get('/check-tokens/:address', async (req, res) => {
|
||||
try {
|
||||
const { address } = req.params;
|
||||
|
||||
|
||||
// Получаем балансы токенов на всех сетях
|
||||
const balances = await authService.getTokenBalances(address);
|
||||
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
balances
|
||||
balances,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error checking token balances:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error'
|
||||
error: 'Internal server error',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
|
||||
@@ -12,19 +12,19 @@ const { v4: uuidv4 } = require('uuid');
|
||||
async function processGuestMessages(userId, guestId) {
|
||||
try {
|
||||
console.log(`Processing guest messages for user ${userId} with guest ID ${guestId}`);
|
||||
|
||||
|
||||
// Проверяем, обрабатывались ли уже эти сообщения
|
||||
const mappingCheck = await db.query(
|
||||
'SELECT processed FROM guest_user_mapping WHERE guest_id = $1',
|
||||
[guestId]
|
||||
);
|
||||
|
||||
|
||||
// Если сообщения уже обработаны, пропускаем
|
||||
if (mappingCheck.rows.length > 0 && mappingCheck.rows[0].processed) {
|
||||
console.log(`Guest messages for guest ID ${guestId} were already processed.`);
|
||||
return { success: true, message: 'Guest messages already processed' };
|
||||
}
|
||||
|
||||
|
||||
// Проверяем наличие mapping записи и создаем если нет
|
||||
if (mappingCheck.rows.length === 0) {
|
||||
await db.query(
|
||||
@@ -33,49 +33,49 @@ async function processGuestMessages(userId, guestId) {
|
||||
);
|
||||
console.log(`Created mapping for guest ID ${guestId} to user ${userId}`);
|
||||
}
|
||||
|
||||
|
||||
// Получаем все гостевые сообщения
|
||||
const guestMessagesResult = await db.query(
|
||||
'SELECT * FROM guest_messages WHERE guest_id = $1 ORDER BY created_at ASC',
|
||||
[guestId]
|
||||
);
|
||||
|
||||
|
||||
if (guestMessagesResult.rows.length === 0) {
|
||||
console.log('No guest messages found');
|
||||
|
||||
|
||||
// Помечаем как обработанные, даже если сообщений нет
|
||||
await db.query(
|
||||
'UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1',
|
||||
[guestId]
|
||||
);
|
||||
|
||||
await db.query('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [
|
||||
guestId,
|
||||
]);
|
||||
|
||||
return { success: true, message: 'No guest messages found' };
|
||||
}
|
||||
|
||||
|
||||
const guestMessages = guestMessagesResult.rows;
|
||||
console.log(`Found ${guestMessages.length} guest messages`);
|
||||
|
||||
|
||||
// Создаем новый диалог для этих сообщений
|
||||
const firstMessage = guestMessages[0];
|
||||
const title = firstMessage.content.length > 30
|
||||
? `${firstMessage.content.substring(0, 30)}...`
|
||||
: firstMessage.content;
|
||||
|
||||
const title =
|
||||
firstMessage.content.length > 30
|
||||
? `${firstMessage.content.substring(0, 30)}...`
|
||||
: firstMessage.content;
|
||||
|
||||
const newConversationResult = await db.query(
|
||||
'INSERT INTO conversations (user_id, title) VALUES ($1, $2) RETURNING *',
|
||||
[userId, title]
|
||||
);
|
||||
|
||||
|
||||
const conversation = newConversationResult.rows[0];
|
||||
console.log('Created new conversation for guest messages:', conversation);
|
||||
|
||||
|
||||
// Отслеживаем успешные сохранения сообщений
|
||||
const savedMessageIds = [];
|
||||
|
||||
|
||||
// Обрабатываем каждое гостевое сообщение
|
||||
for (const guestMessage of guestMessages) {
|
||||
console.log(`Processing guest message ID ${guestMessage.id}: ${guestMessage.content}`);
|
||||
|
||||
|
||||
try {
|
||||
// Сохраняем сообщение пользователя
|
||||
const userMessageResult = await db.query(
|
||||
@@ -85,26 +85,26 @@ async function processGuestMessages(userId, guestId) {
|
||||
($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *`,
|
||||
[
|
||||
conversation.id,
|
||||
guestMessage.content,
|
||||
'user',
|
||||
'user',
|
||||
conversation.id,
|
||||
guestMessage.content,
|
||||
'user',
|
||||
'user',
|
||||
'web',
|
||||
guestMessage.created_at,
|
||||
userId // Добавляем userId в сообщение для прямой связи
|
||||
userId, // Добавляем userId в сообщение для прямой связи
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
console.log(`Saved user message with ID ${userMessageResult.rows[0].id}`);
|
||||
savedMessageIds.push(guestMessage.id);
|
||||
|
||||
|
||||
// Получаем ответ от ИИ только для сообщений пользователя (не AI)
|
||||
if (!guestMessage.is_ai) {
|
||||
console.log('Getting AI response for:', guestMessage.content);
|
||||
const language = guestMessage.language || 'auto';
|
||||
const aiResponse = await aiAssistant.getResponse(guestMessage.content, language);
|
||||
console.log('AI response received:', aiResponse);
|
||||
|
||||
|
||||
// Сохраняем ответ от ИИ
|
||||
const aiMessageResult = await db.query(
|
||||
`INSERT INTO messages
|
||||
@@ -113,16 +113,16 @@ async function processGuestMessages(userId, guestId) {
|
||||
($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *`,
|
||||
[
|
||||
conversation.id,
|
||||
aiResponse,
|
||||
'assistant',
|
||||
'assistant',
|
||||
conversation.id,
|
||||
aiResponse,
|
||||
'assistant',
|
||||
'assistant',
|
||||
'web',
|
||||
new Date(),
|
||||
userId // Добавляем userId в сообщение для прямой связи
|
||||
userId, // Добавляем userId в сообщение для прямой связи
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
console.log(`Saved AI response with ID ${aiMessageResult.rows[0].id}`);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -130,25 +130,26 @@ async function processGuestMessages(userId, guestId) {
|
||||
// Продолжаем с другими сообщениями в случае ошибки
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Удаляем только успешно обработанные гостевые сообщения
|
||||
if (savedMessageIds.length > 0) {
|
||||
await db.query('DELETE FROM guest_messages WHERE id = ANY($1)', [savedMessageIds]);
|
||||
console.log(`Deleted ${savedMessageIds.length} processed guest messages for guest ID ${guestId}`);
|
||||
|
||||
// Помечаем гостевой ID как обработанный
|
||||
await db.query(
|
||||
'UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1',
|
||||
[guestId]
|
||||
console.log(
|
||||
`Deleted ${savedMessageIds.length} processed guest messages for guest ID ${guestId}`
|
||||
);
|
||||
|
||||
// Помечаем гостевой ID как обработанный
|
||||
await db.query('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [
|
||||
guestId,
|
||||
]);
|
||||
} else {
|
||||
console.log('No guest messages were successfully processed, skipping deletion');
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Processed ${savedMessageIds.length} of ${guestMessages.length} guest messages`,
|
||||
conversationId: conversation.id
|
||||
conversationId: conversation.id,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error processing guest messages:', error);
|
||||
@@ -160,11 +161,11 @@ async function processGuestMessages(userId, guestId) {
|
||||
router.post('/guest-message', async (req, res) => {
|
||||
try {
|
||||
const { content, language, guestId: requestGuestId } = req.body;
|
||||
|
||||
|
||||
if (!content) {
|
||||
return res.status(400).json({ success: false, error: 'Content is required' });
|
||||
}
|
||||
|
||||
|
||||
// Используем гостевой ID из запроса или из сессии, или генерируем новый
|
||||
const guestId = requestGuestId || req.session.guestId || crypto.randomBytes(16).toString('hex');
|
||||
|
||||
@@ -182,9 +183,9 @@ router.post('/guest-message', async (req, res) => {
|
||||
|
||||
console.log('Guest message saved:', result.rows[0]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
messageId: result.rows[0].id
|
||||
res.json({
|
||||
success: true,
|
||||
messageId: result.rows[0].id,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving guest message:', error);
|
||||
@@ -195,43 +196,48 @@ router.post('/guest-message', async (req, res) => {
|
||||
// Маршрут для обычных сообщений (для аутентифицированных пользователей)
|
||||
router.post('/message', requireAuth, async (req, res) => {
|
||||
const { message, conversationId, language = 'auto' } = req.body;
|
||||
|
||||
|
||||
if (!message) {
|
||||
return res.status(400).json({ error: 'Message is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('Processing message:', { message, conversationId, language, userId: req.session.userId });
|
||||
console.log('Processing message:', {
|
||||
message,
|
||||
conversationId,
|
||||
language,
|
||||
userId: req.session.userId,
|
||||
});
|
||||
const userId = req.session.userId;
|
||||
|
||||
|
||||
let conversation;
|
||||
|
||||
|
||||
// Если указан ID диалога, проверяем его существование и принадлежность пользователю
|
||||
if (conversationId) {
|
||||
const conversationResult = await db.query(
|
||||
'SELECT * FROM conversations WHERE id = $1 AND user_id = $2',
|
||||
[conversationId, userId]
|
||||
);
|
||||
|
||||
|
||||
if (conversationResult.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Conversation not found or access denied' });
|
||||
}
|
||||
|
||||
|
||||
conversation = conversationResult.rows[0];
|
||||
console.log('Using existing conversation:', conversation);
|
||||
} else {
|
||||
// Создаем новый диалог
|
||||
const title = message.length > 30 ? `${message.substring(0, 30)}...` : message;
|
||||
|
||||
|
||||
const newConversationResult = await db.query(
|
||||
'INSERT INTO conversations (user_id, title) VALUES ($1, $2) RETURNING *',
|
||||
[userId, title]
|
||||
);
|
||||
|
||||
|
||||
conversation = newConversationResult.rows[0];
|
||||
console.log('Created new conversation:', conversation);
|
||||
}
|
||||
|
||||
|
||||
// Сохраняем сообщение пользователя
|
||||
console.log('Saving user message');
|
||||
const userMessageResult = await db.query(
|
||||
@@ -242,12 +248,12 @@ router.post('/message', requireAuth, async (req, res) => {
|
||||
RETURNING *`,
|
||||
[conversation.id, message, 'user', 'user', 0, 'web', new Date()]
|
||||
);
|
||||
|
||||
|
||||
// Получаем ответ от ИИ
|
||||
console.log('Getting AI response');
|
||||
const aiResponse = await aiAssistant.getResponse(message, language);
|
||||
console.log('AI response received:', aiResponse);
|
||||
|
||||
|
||||
// Сохраняем ответ от ИИ
|
||||
console.log('Saving AI response');
|
||||
const aiMessageResult = await db.query(
|
||||
@@ -258,14 +264,14 @@ router.post('/message', requireAuth, async (req, res) => {
|
||||
RETURNING *`,
|
||||
[conversation.id, aiResponse, 'assistant', 'assistant', 0, 'web', new Date()]
|
||||
);
|
||||
|
||||
|
||||
const response = {
|
||||
success: true,
|
||||
userMessage: userMessageResult.rows[0],
|
||||
aiMessage: aiMessageResult.rows[0],
|
||||
conversation
|
||||
conversation,
|
||||
};
|
||||
|
||||
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error processing message:', error);
|
||||
@@ -296,9 +302,9 @@ router.get('/history', async (req, res) => {
|
||||
userId: req.session.userId,
|
||||
address: req.session.address,
|
||||
authenticated: req.session.authenticated,
|
||||
guestId: req.session.guestId
|
||||
guestId: req.session.guestId,
|
||||
});
|
||||
|
||||
|
||||
const limit = parseInt(req.query.limit) || 50;
|
||||
const offset = parseInt(req.query.offset) || 0;
|
||||
|
||||
@@ -308,11 +314,11 @@ router.get('/history', async (req, res) => {
|
||||
try {
|
||||
console.log('Automatically linking guest messages before fetching history');
|
||||
await processGuestMessages(req.session.userId, req.session.guestId);
|
||||
|
||||
|
||||
// Очищаем guestId из сессии после связывания
|
||||
req.session.guestId = null;
|
||||
await req.session.save();
|
||||
|
||||
|
||||
console.log('Guest messages automatically linked');
|
||||
} catch (linkError) {
|
||||
console.error('Error auto-linking guest messages:', linkError);
|
||||
@@ -349,17 +355,16 @@ router.get('/history', async (req, res) => {
|
||||
LIMIT $2 OFFSET $3`,
|
||||
[req.session.userId, limit, offset]
|
||||
);
|
||||
|
||||
|
||||
messages = result.rows;
|
||||
console.log(`Found ${messages.length} messages for authenticated user`);
|
||||
}
|
||||
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
messages: messages,
|
||||
total: total
|
||||
total: total,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Error getting chat history:', error);
|
||||
return res.status(500).json({ error: 'Internal server error' });
|
||||
@@ -368,4 +373,4 @@ router.get('/history', async (req, res) => {
|
||||
|
||||
// Экспортируем маршрутизатор и функцию processGuestMessages отдельно
|
||||
module.exports = router;
|
||||
module.exports.processGuestMessages = processGuestMessages;
|
||||
module.exports.processGuestMessages = processGuestMessages;
|
||||
|
||||
@@ -26,20 +26,20 @@ router.post('/link', requireAuth, async (req, res) => {
|
||||
// Если тип - wallet, сначала проверим, не привязан ли он уже к другому пользователю
|
||||
if (type === 'wallet') {
|
||||
const normalizedWallet = value.toLowerCase();
|
||||
|
||||
|
||||
// Проверяем, существует ли уже такой кошелек
|
||||
const existingCheck = await db.query(
|
||||
`SELECT user_id FROM user_identities
|
||||
WHERE provider = 'wallet' AND provider_id = $1`,
|
||||
[normalizedWallet]
|
||||
);
|
||||
|
||||
|
||||
if (existingCheck.rows.length > 0) {
|
||||
const existingUserId = existingCheck.rows[0].user_id;
|
||||
if (existingUserId !== userId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: `This wallet (${value}) is already linked to another account`
|
||||
error: `This wallet (${value}) is already linked to another account`,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -57,22 +57,22 @@ router.post('/link', requireAuth, async (req, res) => {
|
||||
req.session.email = value;
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Identity linked successfully',
|
||||
isAdmin: req.session.isAdmin
|
||||
isAdmin: req.session.isAdmin,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error linking identity:', error);
|
||||
|
||||
|
||||
// Делаем более понятные сообщения об ошибках
|
||||
if (error.message && error.message.includes('already belongs to another user')) {
|
||||
return res.status(400).json({
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: `This identity is already linked to another account`
|
||||
error: `This identity is already linked to another account`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
res.status(500).json({ error: error.message || 'Internal server error' });
|
||||
}
|
||||
});
|
||||
@@ -93,13 +93,13 @@ router.get('/token-balances', requireAuth, async (req, res) => {
|
||||
|
||||
// Здесь логирование инициирования получения баланса может быть полезно
|
||||
logger.info(`Fetching token balances for user ${userId} with wallet ${wallet}`);
|
||||
|
||||
|
||||
// Получаем балансы токенов
|
||||
const balances = await authService.getTokenBalances(wallet);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
balances
|
||||
balances,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error getting token balances:', error);
|
||||
|
||||
@@ -8,23 +8,23 @@ const logger = require('../utils/logger');
|
||||
router.get('/balances', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { address } = req.session;
|
||||
|
||||
|
||||
if (!address) {
|
||||
return res.status(400).json({
|
||||
error: 'No wallet address in session'
|
||||
return res.status(400).json({
|
||||
error: 'No wallet address in session',
|
||||
});
|
||||
}
|
||||
|
||||
logger.info(`Fetching token balances for address: ${address}`);
|
||||
const balances = await authService.getTokenBalances(address);
|
||||
|
||||
|
||||
res.json(balances);
|
||||
} catch (error) {
|
||||
logger.error('Error fetching token balances:', error);
|
||||
res.status(500).json({
|
||||
error: 'Failed to fetch token balances'
|
||||
res.status(500).json({
|
||||
error: 'Failed to fetch token balances',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
|
||||
@@ -23,19 +23,16 @@ router.post('/update-language', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { language } = req.body;
|
||||
const userId = req.session.userId;
|
||||
|
||||
|
||||
// Проверка валидности языка
|
||||
const validLanguages = ['ru', 'en'];
|
||||
if (!validLanguages.includes(language)) {
|
||||
return res.status(400).json({ error: 'Неподдерживаемый язык' });
|
||||
}
|
||||
|
||||
|
||||
// Обновление языка в базе данных
|
||||
await db.query(
|
||||
'UPDATE users SET preferred_language = $1 WHERE id = $2',
|
||||
[language, userId]
|
||||
);
|
||||
|
||||
await db.query('UPDATE users SET preferred_language = $1 WHERE id = $2', [language, userId]);
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('Error updating language:', error);
|
||||
@@ -48,22 +45,23 @@ router.post('/update-profile', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { firstName, lastName } = req.body;
|
||||
const userId = req.session.userId;
|
||||
|
||||
|
||||
// Проверка валидности данных
|
||||
if (firstName && firstName.length > 255) {
|
||||
return res.status(400).json({ error: 'Имя слишком длинное (максимум 255 символов)' });
|
||||
}
|
||||
|
||||
|
||||
if (lastName && lastName.length > 255) {
|
||||
return res.status(400).json({ error: 'Фамилия слишком длинная (максимум 255 символов)' });
|
||||
}
|
||||
|
||||
|
||||
// Обновление имени и фамилии в базе данных
|
||||
await db.query(
|
||||
'UPDATE users SET first_name = $1, last_name = $2 WHERE id = $3',
|
||||
[firstName || null, lastName || null, userId]
|
||||
);
|
||||
|
||||
await db.query('UPDATE users SET first_name = $1, last_name = $2 WHERE id = $3', [
|
||||
firstName || null,
|
||||
lastName || null,
|
||||
userId,
|
||||
]);
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('Error updating user profile:', error);
|
||||
@@ -75,29 +73,29 @@ router.post('/update-profile', requireAuth, async (req, res) => {
|
||||
router.get('/profile/current', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const userId = req.session.userId;
|
||||
|
||||
|
||||
// Получение данных пользователя
|
||||
const userResult = await db.query(
|
||||
'SELECT id, username, first_name, last_name, role, status, created_at, preferred_language FROM users WHERE id = $1',
|
||||
[userId]
|
||||
);
|
||||
|
||||
|
||||
if (userResult.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Пользователь не найден' });
|
||||
}
|
||||
|
||||
|
||||
// Получение идентификаторов пользователя
|
||||
const identitiesResult = await db.query(
|
||||
'SELECT provider, provider_id FROM user_identities WHERE user_id = $1',
|
||||
[userId]
|
||||
);
|
||||
|
||||
|
||||
const user = userResult.rows[0];
|
||||
const identities = identitiesResult.rows.reduce((acc, identity) => {
|
||||
acc[identity.provider] = identity.provider_id;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
|
||||
res.json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
@@ -107,7 +105,7 @@ router.get('/profile/current', requireAuth, async (req, res) => {
|
||||
status: user.status,
|
||||
createdAt: user.created_at,
|
||||
preferredLanguage: user.preferred_language,
|
||||
identities
|
||||
identities,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error getting user profile:', error);
|
||||
|
||||
Reference in New Issue
Block a user