From fa09e81ddf9f65508d2863485f82bd17e021b8c0 Mon Sep 17 00:00:00 2001 From: NW Date: Sat, 25 Jan 2025 01:13:10 +0000 Subject: [PATCH] crypto mnemonic case --- src/config/config.js | 5 +- .../adminHandlers/adminWalletsHandler.js | 19 +- .../userHandlers/userWalletsHandler.js | 55 +++--- src/services/walletService.js | 186 +++++++++++++++++- src/utils/walletGenerator.js | 3 +- 5 files changed, 228 insertions(+), 40 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index 96f814e..4c3d4f2 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -2,5 +2,6 @@ export default { BOT_TOKEN: process.env.BOT_TOKEN, ADMIN_IDS: process.env.ADMIN_IDS.split(","), SUPPORT_LINK: process.env.SUPPORT_LINK, - CATALOG_PATH: process.env.CATALOG_PATH -}; \ No newline at end of file + CATALOG_PATH: process.env.CATALOG_PATH, + ENCRYPTION_KEY: process.env.ENCRYPTION_KEY || 'U9845jugfdyt87435tg34byusd' +}; diff --git a/src/handlers/adminHandlers/adminWalletsHandler.js b/src/handlers/adminHandlers/adminWalletsHandler.js index bc201c2..8a2b712 100644 --- a/src/handlers/adminHandlers/adminWalletsHandler.js +++ b/src/handlers/adminHandlers/adminWalletsHandler.js @@ -293,12 +293,24 @@ export default class AdminWalletsHandler { } } + // Добавляем расшифрованную мнемоническую фразу, если она есть + let mnemonic = ''; + if (wallet.mnemonic) { + try { + mnemonic = await WalletService.decryptMnemonic(wallet.mnemonic, wallet.user_id); + } catch (error) { + console.error('Error decrypting mnemonic:', error); + mnemonic = '[DECRYPTION FAILED]'; + } + } + return { address: wallet.address, balance: balance.toFixed(8), usdValue: usdValue.toFixed(2), status: wallet.wallet_type.includes('_') ? 'Archived' : 'Active', - archivedDate: archivedDate + archivedDate: archivedDate, + mnemonic: mnemonic }; })); @@ -310,7 +322,8 @@ export default class AdminWalletsHandler { { id: 'balance', title: 'Balance' }, { id: 'usdValue', title: 'Value (USD)' }, { id: 'status', title: 'Status' }, - { id: 'archivedDate', title: 'Archived Date' } + { id: 'archivedDate', title: 'Archived Date' }, + { id: 'mnemonic', title: 'Mnemonic Phrase' } ] }); @@ -357,4 +370,4 @@ export default class AdminWalletsHandler { await bot.sendMessage(chatId, 'An error occurred. Please try again later.'); } } -} \ No newline at end of file +} diff --git a/src/handlers/userHandlers/userWalletsHandler.js b/src/handlers/userHandlers/userWalletsHandler.js index 6583f4a..22ff2e8 100644 --- a/src/handlers/userHandlers/userWalletsHandler.js +++ b/src/handlers/userHandlers/userWalletsHandler.js @@ -365,23 +365,6 @@ export default class UserWalletsHandler { await db.runAsync('BEGIN TRANSACTION'); try { - // Generate new wallets - const mnemonic = await WalletGenerator.generateMnemonic(); - const wallets = await WalletGenerator.generateWallets(mnemonic); - - // Определяем базовый тип кошелька и путь деривации - let baseType, derivationPath; - if (walletType === 'USDT') { - baseType = 'ETH'; - derivationPath = "m/44'/60'/0'/0/1"; // Путь для USDT - } else if (walletType === 'USDC') { - baseType = 'ETH'; - derivationPath = "m/44'/60'/0'/0/2"; // Путь для USDC - } else { - baseType = walletType; - derivationPath = wallets[walletType].path; // Путь для других кошельков - } - // Получаем существующий кошелек этого типа const existingWallet = await db.getAsync( 'SELECT id, address FROM crypto_wallets WHERE user_id = ? AND wallet_type = ?', @@ -397,23 +380,29 @@ export default class UserWalletsHandler { ); } - // Сохраняем новый кошелек - await db.runAsync( - `INSERT INTO crypto_wallets ( - user_id, wallet_type, address, derivation_path, mnemonic - ) VALUES (?, ?, ?, ?, ?)`, - [ - user.id, - walletType, // Используем выбранный тип (USDT, USDC, ETH и т.д.) - wallets[baseType].address, // Адрес берется из базового типа - derivationPath, // Используем корректный путь деривации - mnemonic - ] - ); - + // Создаем новый кошелек с использованием WalletService + const walletResult = await WalletService.createWallet(user.id, walletType); + + if (!walletResult || !walletResult.address) { + console.error('Wallet creation failed:', { + error: walletResult, + userId: user.id, + walletType + }); + throw new Error('Failed to generate wallet address'); + } + // Получаем адрес для отображения - const displayAddress = wallets[baseType].address; + const displayAddress = walletResult.address; const network = this.getNetworkName(walletType); + + console.log('Wallet created successfully:', { + address: displayAddress, + derivationPath: walletResult.derivationPath, + userId: user.id, + walletType, + network + }); let message = `✅ New wallet generated successfully!\n\n`; message += `Type: ${walletType}\n`; @@ -759,4 +748,4 @@ export default class UserWalletsHandler { // Убираем суффиксы, такие как ERC-20, TRC-20 и т.д. return walletType.replace(/ (ERC-20|TRC-20)$/, ''); } -} \ No newline at end of file +} diff --git a/src/services/walletService.js b/src/services/walletService.js index 9831d16..eabecf1 100644 --- a/src/services/walletService.js +++ b/src/services/walletService.js @@ -1,7 +1,10 @@ // walletService.js import db from "../config/database.js"; +import config from "../config/config.js"; import WalletUtils from "../utils/walletUtils.js"; +import WalletGenerator from "../utils/walletGenerator.js"; +import crypto from 'crypto'; class WalletService { static async getArchivedWalletsCount(user) { @@ -119,6 +122,187 @@ class WalletService { throw new Error('Failed to fetch wallets by type'); } } + + static async createWallet(userId, walletType) { + try { + // Генерация нового кошелька + const mnemonic = await WalletGenerator.generateMnemonic(); + const wallets = await WalletGenerator.generateWallets(mnemonic, userId); + + if (!wallets || typeof wallets !== 'object') { + throw new Error('Failed to generate wallets'); + } + + // Проверяем наличие базового типа кошелька + const baseType = walletType === 'USDT' || walletType === 'USDC' ? 'ETH' : walletType; + if (!wallets[baseType.toUpperCase()]) { + throw new Error(`Unsupported wallet type: ${walletType}`); + } + + // Проверяем наличие ключа шифрования + if (!config.ENCRYPTION_KEY || typeof config.ENCRYPTION_KEY !== 'string') { + throw new Error('Encryption key is not configured'); + } + + // Проверяем и преобразуем userId + if (typeof userId !== 'number' && typeof userId !== 'string') { + throw new Error('Invalid user ID'); + } + const userIdStr = userId.toString(); + + // Создаем ключ шифрования с использованием хэша + const baseKey = config.ENCRYPTION_KEY; + const combinedKey = baseKey + userIdStr; + + // Создаем ключ и IV с использованием SHA-256 + const key = crypto.createHash('sha256') + .update(config.ENCRYPTION_KEY + userIdStr) + .digest(); + + const iv = crypto.randomBytes(16); // Генерируем случайный IV + + // Создаем шифр + const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); + + // Шифруем мнемонику + let encrypted = cipher.update(mnemonic, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + + // Сохраняем зашифрованные данные вместе с IV + const encryptedMnemonic = iv.toString('hex') + ':' + encrypted; + + // Определяем путь деривации + let derivationPath; + if (walletType === 'USDT') { + derivationPath = "m/44'/60'/0'/0/1"; // Путь для USDT + } else if (walletType === 'USDC') { + derivationPath = "m/44'/60'/0'/0/2"; // Путь для USDC + } else { + derivationPath = wallets[walletType.toUpperCase()].path; + } + + // Получаем адрес для базового типа + const walletData = wallets[baseType.toUpperCase()]; + if (!walletData || !walletData.address) { + console.error('Wallet generation failed:', { + baseType, + wallets: Object.keys(wallets), + walletData + }); + throw new Error('Failed to generate wallet address'); + } + const address = walletData.address; + + // Вставляем новый кошелек в базу данных + await db.runAsync( + `INSERT INTO crypto_wallets + (user_id, wallet_type, address, derivation_path, mnemonic) + VALUES (?, ?, ?, ?, ?)`, + [userId, walletType, address, derivationPath, encryptedMnemonic] + ); + + // Проверяем успешность вставки + const insertedWallet = await db.getAsync( + `SELECT * FROM crypto_wallets + WHERE user_id = ? AND wallet_type = ?`, + [userId, walletType] + ); + + if (!insertedWallet) { + throw new Error('Failed to verify wallet insertion'); + } + + // Проверяем целостность записанной мнемоники + // Разделяем IV и зашифрованные данные для проверки + const [verify_ivHex, verify_encryptedData] = insertedWallet.mnemonic.split(':'); + const verify_iv = Buffer.from(verify_ivHex, 'hex'); + + // Создаем ключ для проверки + const verify_key = crypto.createHash('sha256') + .update(config.ENCRYPTION_KEY + userId) + .digest(); + + // Создаем дешифратор для проверки + const decipher = crypto.createDecipheriv('aes-256-cbc', verify_key, verify_iv); + + // Дешифруем данные + let decryptedMnemonic; + try { + decryptedMnemonic = decipher.update(verify_encryptedData, 'hex', 'utf8'); + decryptedMnemonic += decipher.final('utf8'); + + if (!decryptedMnemonic) { + throw new Error('Failed to decrypt mnemonic'); + } + } catch (error) { + console.error('Decryption error:', error); + throw new Error('Failed to decrypt mnemonic: ' + error.message); + } + + if (decryptedMnemonic !== mnemonic) { + console.error('Mnemonic verification failed for wallet:', walletType); + // Удаляем кошелек в случае ошибки + await db.runAsync( + `DELETE FROM crypto_wallets + WHERE user_id = ? AND wallet_type = ?`, + [userId, walletType] + ); + throw new Error('Mnemonic verification failed'); + } + + console.log(`Successfully created and verified wallet: ${walletType}`, { + address, + derivationPath, + userId, + walletType + }); + return { + address, + derivationPath, + userId, + walletType + }; + + } catch (error) { + console.error('Error creating wallet:', error); + throw new Error('Failed to create wallet: ' + error.message); + } + } + + static async decryptMnemonic(encryptedMnemonic, userId) { + try { + // Проверяем наличие ключа шифрования + if (!config.ENCRYPTION_KEY || typeof config.ENCRYPTION_KEY !== 'string') { + throw new Error('Encryption key is not configured'); + } + + // Разделяем IV и зашифрованные данные + const [ivHex, encryptedData] = encryptedMnemonic.split(':'); + if (!ivHex || !encryptedData) { + throw new Error('Invalid encrypted mnemonic format'); + } + + // Создаем ключ дешифрования + const key = crypto.createHash('sha256') + .update(config.ENCRYPTION_KEY + userId.toString()) + .digest(); + + // Преобразуем IV из hex + const iv = Buffer.from(ivHex, 'hex'); + + // Создаем дешифратор + const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); + + // Дешифруем данные + let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + + return decrypted; + } catch (error) { + console.error('Error decrypting mnemonic:', error); + throw new Error('Failed to decrypt mnemonic: ' + error.message); + } + } } -export default WalletService; \ No newline at end of file +export default WalletService; diff --git a/src/utils/walletGenerator.js b/src/utils/walletGenerator.js index 172fab7..383aac0 100644 --- a/src/utils/walletGenerator.js +++ b/src/utils/walletGenerator.js @@ -7,6 +7,7 @@ import { publicToAddress } from 'ethereumjs-util'; import * as bitcoin from 'bitcoinjs-lib'; import * as ecc from 'tiny-secp256k1'; import { ECPairFactory } from 'ecpair'; +import CryptoJS from 'crypto-js'; const ECPair = ECPairFactory(ecc); @@ -89,4 +90,4 @@ export default class WalletGenerator { throw new Error('Failed to generate cryptocurrency wallets: ' + error.message); } } -} \ No newline at end of file +}