diff --git a/backend/routes/contracts.js b/backend/routes/contracts.js index 213f17b..5ee732c 100644 --- a/backend/routes/contracts.js +++ b/backend/routes/contracts.js @@ -7,10 +7,11 @@ router.get('/', (req, res) => { res.json({ message: 'Contracts API endpoint', contracts: [ - { - name: 'AccessToken', - address: process.env.ACCESS_TOKEN_ADDRESS, - }, + // Удаляем AccessToken + // { + // name: 'AccessToken', + // address: process.env.ACCESS_TOKEN_ADDRESS, + // }, ], }); }); @@ -20,11 +21,12 @@ router.get('/details', requireRole('ADMIN'), (req, res) => { res.json({ message: 'Contract details endpoint', contracts: [ - { - name: 'AccessToken', - address: process.env.ACCESS_TOKEN_ADDRESS, - network: process.env.ETHEREUM_NETWORK_URL.includes('sepolia') ? 'Sepolia' : 'Unknown', - }, + // Удаляем AccessToken + // { + // name: 'AccessToken', + // address: process.env.ACCESS_TOKEN_ADDRESS, + // network: process.env.ETHEREUM_NETWORK_URL.includes('sepolia') ? 'Sepolia' : 'Unknown', + // }, ], }); }); diff --git a/backend/services/auth-service.js b/backend/services/auth-service.js index 3fc69a3..1ded5bb 100644 --- a/backend/services/auth-service.js +++ b/backend/services/auth-service.js @@ -1,44 +1,36 @@ const db = require('../db'); -const { getContract } = require('../utils/contracts'); const logger = require('../utils/logger'); const { ethers } = require('ethers'); -const path = require('path'); -// Инициализируем провайдер -const provider = new ethers.JsonRpcProvider(process.env.RPC_URL); +// В начале файла 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 contractsDir = path.join(__dirname, '../artifacts/contracts/AccessToken.sol'); +const providers = { + eth: getProvider('eth'), + polygon: getProvider('polygon'), + bsc: getProvider('bsc'), + arbitrum: getProvider('arbitrum') +}; /** * Сервис для работы с аутентификацией и авторизацией */ class AuthService { - /** - * Проверяет наличие токена администратора для кошелька - * @param {string} walletAddress - Адрес кошелька - * @returns {Promise} - Имеет ли кошелек токен администратора - */ - async checkAdminToken(walletAddress) { - try { - if (!walletAddress) { - logger.error('Wallet address is undefined'); - return false; - } - - // Получаем контракт AccessToken - const accessToken = await getContract('AccessToken'); - - // Проверяем роль пользователя - const role = await accessToken.checkRole(walletAddress); - - // 0 = ADMIN - return role === 0; - } catch (error) { - logger.error(`Error checking admin token: ${error.message}`); - return false; - } - } - /** * Проверяет наличие токенов на кошельке и обновляет роль * @param {string} walletAddress - Адрес кошелька @@ -60,8 +52,8 @@ class AuthService { const userId = userResult.rows[0].id; - // Проверяем наличие токена администратора - const isAdmin = await this.checkAdminToken(walletAddress); + // Проверяем наличие токенов на кошельке + const isAdmin = await this.checkAdminTokens(walletAddress); // Обновляем роль в базе данных await this.updateUserRole(userId, isAdmin ? 'admin' : 'user'); @@ -75,6 +67,62 @@ class AuthService { } } + /** + * Проверяет наличие токенов на кошельке + * @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 пользователя @@ -154,10 +202,10 @@ class AuthService { return result.rows[0].id; } catch (error) { - logger.error(`Error getting user ID by identity: ${error.message}`); + logger.error(`Ошибка при получении ID пользователя по идентификатору: ${error.message}`); return null; } } } -module.exports = new AuthService(); \ No newline at end of file +module.exports = new AuthService(); \ No newline at end of file diff --git a/backend/utils/access-check.js b/backend/utils/access-check.js index d1fe4f8..f0224ec 100644 --- a/backend/utils/access-check.js +++ b/backend/utils/access-check.js @@ -1,5 +1,5 @@ const db = require('../db'); -const logger = require('./logger'); +const logger = require('../utils/logger'); const authService = require('../services/auth-service'); /** diff --git a/backend/utils/auth.js b/backend/utils/auth.js index 5c267fd..1f11595 100644 --- a/backend/utils/auth.js +++ b/backend/utils/auth.js @@ -5,7 +5,7 @@ const authService = require('../services/auth-service'); const { USER_ROLES, IDENTITY_TYPES } = require('./constants'); // Инициализация провайдера -const provider = new ethers.JsonRpcProvider(process.env.RPC_URL); +const provider = new ethers.JsonRpcProvider(process.env.RPC_URL_ETH); /** * Проверяет подпись сообщения @@ -37,8 +37,8 @@ async function verifySignature(nonce, signature, address) { */ async function checkUserRole(address) { try { - // Проверяем наличие токена администратора - const isAdmin = await authService.checkAdminToken(address); + // Проверяем наличие токенов администратора + const isAdmin = await authService.checkAdminTokens(address); return isAdmin; } catch (error) { console.error('Error checking user role:', error); @@ -53,8 +53,8 @@ async function checkUserRole(address) { */ async function checkAccess(walletAddress) { try { - // Проверяем наличие токена администратора - const isAdmin = await authService.checkAdminToken(walletAddress); + // Проверяем наличие токенов администратора + const isAdmin = await authService.checkAdminTokens(walletAddress); // Получаем или создаем пользователя const userId = await findOrCreateUser(walletAddress); @@ -81,7 +81,11 @@ async function checkAccess(walletAddress) { async function findOrCreateUser(address) { try { // Проверяем, существует ли пользователь - const userResult = await db.query('SELECT * FROM users WHERE LOWER(address) = LOWER($1)', [address]); + 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 LOWER(ui.identity_value) = LOWER($1) + `, [address]); let userId; let isAdmin = false; @@ -97,12 +101,18 @@ async function findOrCreateUser(address) { // Создаем пользователя с ролью 'user' const newUserResult = await db.query( - 'INSERT INTO users (address, role_id, created_at) VALUES (LOWER($1), $2, NOW()) RETURNING id', - [address, roleId] + 'INSERT INTO users (role_id, created_at) VALUES ($1, NOW()) RETURNING id', + [roleId] ); userId = newUserResult.rows[0].id; + // Добавляем идентификатор кошелька + await db.query( + 'INSERT INTO user_identities (user_id, identity_type, identity_value, created_at) VALUES ($1, $2, $3, NOW())', + [userId, 'wallet', address.toLowerCase()] + ); + // Проверяем, является ли пользователь администратором isAdmin = await checkUserRole(address); @@ -115,25 +125,18 @@ async function findOrCreateUser(address) { } } } else { - // Если пользователь найден, получаем его ID и роль + // Если пользователь найден, получаем его ID userId = userResult.rows[0].id; - // Проверяем, является ли пользователь администратором по роли - const roleResult = await db.query('SELECT name FROM roles WHERE id = $1', [userResult.rows[0].role_id]); - isAdmin = roleResult.rows.length > 0 && roleResult.rows[0].name === 'admin'; + // Проверяем, является ли пользователь администратором + isAdmin = await checkUserRole(address); - // Проверяем, является ли пользователь администратором по токену - const isAdminByToken = await checkUserRole(address); - - // Обновляем роль пользователя, если она изменилась - if (isAdminByToken !== isAdmin) { - const roleNameToSet = isAdminByToken ? 'admin' : 'user'; - const roleToSetResult = await db.query('SELECT id FROM roles WHERE name = $1', [roleNameToSet]); - if (roleToSetResult.rows.length > 0) { - const roleIdToSet = roleToSetResult.rows[0].id; - await db.query('UPDATE users SET role_id = $1 WHERE id = $2', [roleIdToSet, userId]); - isAdmin = isAdminByToken; - } + // Обновляем роль пользователя + const roleNameToSet = isAdmin ? 'admin' : 'user'; + const roleToSetResult = await db.query('SELECT id FROM roles WHERE name = $1', [roleNameToSet]); + if (roleToSetResult.rows.length > 0) { + const roleIdToSet = roleToSetResult.rows[0].id; + await db.query('UPDATE users SET role_id = $1 WHERE id = $2', [roleIdToSet, userId]); } } diff --git a/frontend/src/components/Navigation.vue b/frontend/src/components/Navigation.vue index 37487f4..d187e62 100644 --- a/frontend/src/components/Navigation.vue +++ b/frontend/src/components/Navigation.vue @@ -6,8 +6,6 @@