const db = require('../db'); const logger = require('../utils/logger'); const { ethers } = require('ethers'); // В начале файла auth-service.js const getProvider = (network) => { const primaryUrl = process.env[`RPC_URL_${network.toUpperCase()}`]; const backupUrls = { eth: 'https://eth-mainnet.public.blastapi.io', polygon: 'https://polygon-rpc.com', bsc: 'https://bsc-dataseed.binance.org', arbitrum: 'https://arb1.arbitrum.io/rpc' }; try { return new ethers.JsonRpcProvider(primaryUrl); } catch (error) { logger.warn(`Failed to connect to primary URL for ${network}, using backup`); return new ethers.JsonRpcProvider(backupUrls[network]); } }; const providers = { eth: getProvider('eth'), polygon: getProvider('polygon'), bsc: getProvider('bsc'), arbitrum: getProvider('arbitrum') }; /** * Сервис для работы с аутентификацией и авторизацией */ class AuthService { /** * Проверяет наличие токенов на кошельке и обновляет роль * @param {string} walletAddress - Адрес кошелька * @returns {Promise} - Имеет ли пользователь права администратора */ async checkTokensAndUpdateRole(walletAddress) { try { // Получаем ID пользователя по адресу кошелька const userResult = await db.query(` SELECT u.id FROM users u JOIN user_identities ui ON u.id = ui.user_id WHERE ui.identity_type = 'wallet' AND ui.identity_value = $1 `, [walletAddress]); if (userResult.rows.length === 0) { logger.warn(`User with wallet ${walletAddress} not found`); return false; } const userId = userResult.rows[0].id; // Проверяем наличие токенов на кошельке const isAdmin = await this.checkAdminTokens(walletAddress); // Обновляем роль в базе данных await this.updateUserRole(userId, isAdmin ? 'admin' : 'user'); logger.info(`User ${userId} with address ${walletAddress}: admin=${isAdmin}`); return isAdmin; } catch (error) { logger.error(`Error checking tokens: ${error.message}`); return false; } } /** * Проверяет наличие токенов на кошельке * @param {string} walletAddress - Адрес кошелька * @returns {Promise} - Имеет ли кошелек токены */ async checkAdminTokens(walletAddress) { try { const tokenContracts = [ { address: "0xd95a45fc46a7300e6022885afec3d618d7d3f27c", network: "eth" }, // Ethereum { address: "0x1d47f12ffA279BFE59Ab16d56fBb10d89AECdD5D", network: "bsc" }, // Binance Smart Chain { address: "0xdce769b847a0a697239777d0b1c7dd33b6012ba0", network: "arbitrum" }, // Arbitrum { address: "0x351f59de4fedbdf7601f5592b93db3b9330c1c1d", network: "polygon" } // Polygon ]; const MIN_BALANCE = ethers.parseUnits("1.0", 18); // 1 токен for (const contract of tokenContracts) { try { const provider = providers[contract.network]; if (!provider) { logger.warn(`Provider not found for network: ${contract.network}`); continue; } // Проверка доступности провайдера try { await provider.getBlockNumber(); // Простой запрос для проверки соединения } catch (providerError) { logger.warn(`Provider for ${contract.network} is not responding: ${providerError.message}`); continue; } const tokenContract = new ethers.Contract(contract.address, [ "function balanceOf(address owner) view returns (uint256)" ], provider); const balance = await tokenContract.balanceOf(walletAddress); logger.info(`Balance for ${walletAddress} on ${contract.network}: ${balance.toString()}`); if (balance >= MIN_BALANCE) { logger.info(`Admin token found on ${contract.network} for ${walletAddress}`); return true; // Если найден хотя бы один токен, возвращаем true } } catch (error) { logger.error(`Error checking balance on ${contract.network}: ${error.message}`); } } logger.info(`No admin tokens found for ${walletAddress}`); return false; // Если не найдено ни одного токена, возвращаем false } catch (error) { logger.error(`Error in checkAdminTokens: ${error.message}`); return false; } } /** * Обновляет роль пользователя в базе данных * @param {number} userId - ID пользователя * @param {string} role - Новая роль ('admin' или 'user') * @returns {Promise} - Успешно ли обновлена роль */ async updateUserRole(userId, role) { try { // Получаем ID роли const roleResult = await db.query('SELECT id FROM roles WHERE name = $1', [role]); if (roleResult.rows.length === 0) { logger.error(`Role ${role} not found`); return false; } const roleId = roleResult.rows[0].id; // Обновляем роль пользователя await db.query('UPDATE users SET role_id = $1 WHERE id = $2', [roleId, userId]); logger.info(`Updated role for user ${userId} to ${role}`); return true; } catch (error) { logger.error(`Error updating user role: ${error.message}`); return false; } } /** * Получает все токены доступа * @returns {Promise} - Список токенов доступа */ async getAllTokens() { try { const result = await db.query(` SELECT * FROM access_tokens ORDER BY created_at DESC `); return result.rows.map(token => ({ id: token.id, walletAddress: token.wallet_address, role: token.role, createdAt: token.created_at, expiresAt: token.expires_at, })); } catch (error) { logger.error(`Error getting all tokens: ${error.message}`); return []; } } /** * Получает ID пользователя по идентификатору * @param {string} identityType - Тип идентификатора ('wallet', 'email', 'telegram') * @param {string} identityValue - Значение идентификатора * @returns {Promise} - ID пользователя или null, если пользователь не найден */ async getUserIdByIdentity(identityType, identityValue) { try { // Нормализуем значение идентификатора const normalizedValue = identityType === 'wallet' ? identityValue.toLowerCase() : identityValue; // Получаем ID пользователя const result = await db.query(` SELECT u.id FROM users u JOIN user_identities ui ON u.id = ui.user_id WHERE ui.identity_type = $1 AND LOWER(ui.identity_value) = LOWER($2) `, [identityType, normalizedValue]); if (result.rows.length === 0) { return null; } return result.rows[0].id; } catch (error) { logger.error(`Ошибка при получении ID пользователя по идентификатору: ${error.message}`); return null; } } /** * Получает все идентификаторы пользователя * @param {number} userId - ID пользователя * @returns {Promise} - Список идентификаторов */ async getAllUserIdentities(userId) { try { const result = await db.query(` SELECT identity_type, identity_value, verified, created_at FROM user_identities WHERE user_id = $1 `, [userId]); return result.rows; } catch (error) { logger.error(`Error getting user identities: ${error.message}`); return []; } } /** * Проверяет, является ли пользователь администратором * @param {number} userId - ID пользователя * @returns {Promise} - Является ли пользователь администратором */ async isAdmin(userId) { try { const result = await db.query('SELECT is_admin FROM users WHERE id = $1', [userId]); if (result.rows.length === 0) { return false; } return result.rows[0].is_admin; } catch (error) { logger.error(`Error checking admin status: ${error.message}`); return false; } } } module.exports = new AuthService();