const fs = require('fs'); const path = require('path'); const { TelegramClient } = require('telegram'); const { StringSession } = require('telegram/sessions'); const { Api } = require('telegram'); const TelegramBot = require('node-telegram-bot-api'); const { Logger } = require('telegram/extensions'); const input = require('input'); // Custom logger implementation class CustomLogger { constructor(prefix) { this.prefix = prefix; } log(level, message) { // Implement your own logging if needed // console.log(`[${this.prefix}] ${level}: ${message}`); } error(message) { this.log('ERROR', message); } warn(message) { this.log('WARN', message); } info(message) { this.log('INFO', message); } debug(message) { this.log('DEBUG', message); } } // Bot token from environment const BOT_TOKEN = process.env.BOT_TOKEN || '8019149324:AAGBAmRy0M-q6u0FqzREzwDtH-c5V-f9xoM'; // Create a new bot instance const bot = new TelegramBot(BOT_TOKEN, { polling: true }); // Define conversation states const STATES = { IDLE: 'idle', API_ID: 'api_id', API_HASH: 'api_hash', PHONE: 'phone', CODE: 'code', PASSWORD: 'password' }; // Store user sessions and their current state const userSessions = new Map(); // Validate phone number format function isValidPhone(phone) { return /^\+\d{10,15}$/.test(phone); } // Create a clean session object for a user function createUserSession(userId) { return { userId, state: STATES.IDLE, apiId: null, apiHash: null, phone: null, client: null, sessionName: `aayco_${userId}`, stringSession: null, phoneCodeHash: null }; } // Clean up resources for a user session async function cleanupSession(userId) { const session = userSessions.get(userId); if (!session) return; try { if (session.client) { await session.client.disconnect(); } // Remove session file if it exists const sessionFile = `${session.sessionName}.session`; if (fs.existsSync(sessionFile)) { fs.unlinkSync(sessionFile); } } catch (error) { console.error(`Error cleaning up session for user ${userId}:`, error); } finally { userSessions.delete(userId); } } // Start command handler bot.onText(/\/start/, async (msg) => { const userId = msg.from.id; await bot.sendMessage(userId, "👋 Welcome to the Userbot Session Generator!\n\n" + "Use /pair to start creating your session file.\n" + "Use /cancel at any time to stop the process." ); }); // Pair command handler bot.onText(/\/pair/, async (msg) => { const userId = msg.from.id; // Check if user already has an active session if (userSessions.has(userId)) { const existingSession = userSessions.get(userId); if (existingSession.state !== STATES.IDLE) { await bot.sendMessage(userId, "⚠️ You already have an active session process.\n" + "Complete or /cancel it before starting a new one." ); return; } } // Create new session for user const session = createUserSession(userId); session.state = STATES.API_ID; userSessions.set(userId, session); await bot.sendMessage(userId, "🔐 Let's create your userbot session.\n" + "Please provide your **API ID** (a number from my.telegram.org):\n" + "Example: 1234567" ); }); // Cancel command handler bot.onText(/\/cancel/, async (msg) => { const userId = msg.from.id; if (userSessions.has(userId)) { await cleanupSession(userId); await bot.sendMessage(userId, "🛑 Session creation cancelled."); } else { await bot.sendMessage(userId, "There's no active session to cancel."); } }); // Handle all text messages bot.on('message', async (msg) => { if (msg.text && msg.text.startsWith('/')) return; const userId = msg.from.id; const text = msg.text?.trim(); if (!userSessions.has(userId) || !text) return; const session = userSessions.get(userId); try { switch (session.state) { case STATES.API_ID: await handleApiId(userId, text); break; case STATES.API_HASH: await handleApiHash(userId, text); break; case STATES.PHONE: await handlePhone(userId, text); break; case STATES.CODE: await handleCode(userId, text); break; case STATES.PASSWORD: await handlePassword(userId, text); break; } } catch (error) { console.error(`Error handling message for user ${userId}:`, error); await bot.sendMessage(userId, `⚠️ An error occurred: ${error.message}\n` + "Please try again with /pair." ); await cleanupSession(userId); } }); // Process API ID input async function handleApiId(userId, text) { if (!text.match(/^\d+$/)) { await bot.sendMessage(userId, "❌ API ID must be a number.\n" + "Please send a valid **API ID**:" ); return; } const session = userSessions.get(userId); session.apiId = parseInt(text, 10); session.state = STATES.API_HASH; await bot.sendMessage(userId, "✅ API ID received.\n" + "Now provide your **API Hash** (a string from my.telegram.org):\n" + "Example: abcdef1234567890abcdef1234567890" ); } // Process API Hash input async function handleApiHash(userId, text) { if (text.length < 32) { await bot.sendMessage(userId, "❌ API Hash must be at least 32 characters long.\n" + "Please send a valid **API Hash**:" ); return; } const session = userSessions.get(userId); session.apiHash = text; session.state = STATES.PHONE; await bot.sendMessage(userId, "✅ API Hash received.\n" + "Now provide your **phone number** (with country code):\n" + "Example: +12025550123" ); } // Process phone number input async function handlePhone(userId, phone) { if (!isValidPhone(phone)) { await bot.sendMessage(userId, "❌ Invalid phone number format.\n" + "Please send a valid phone number (e.g., +12025550123):" ); return; } const session = userSessions.get(userId); session.phone = phone; try { // Create a new StringSession const stringSession = new StringSession(""); // Create a new TelegramClient with custom logger const client = new TelegramClient( stringSession, session.apiId, session.apiHash, { connectionRetries: 5, baseLogger: new CustomLogger('GramJS'), useWSS: false, autoReconnect: true } ); session.client = client; // Connect and send code await client.connect(); const result = await client.invoke( new Api.auth.SendCode({ phoneNumber: session.phone, apiId: session.apiId, apiHash: session.apiHash, settings: new Api.CodeSettings({}) }) ); session.phoneCodeHash = result.phoneCodeHash; session.state = STATES.CODE; await bot.sendMessage(userId, "✅ Code request sent to your phone.\n" + "Please enter the verification code you received:" ); } catch (error) { console.error('Error in handlePhone:', error); let errorMessage = error.message; if (error.errorMessage === 'PHONE_NUMBER_INVALID') { errorMessage = "The phone number is invalid. Please check and try again."; } else if (error.errorMessage === 'PHONE_NUMBER_BANNED') { errorMessage = "This phone number is banned from Telegram."; } else if (error.errorMessage.includes('FLOOD')) { errorMessage = "Too many attempts. Please wait before trying again."; } await bot.sendMessage(userId, `❌ Error sending code: ${errorMessage}\n` + "Please try again with /pair or contact support." ); await cleanupSession(userId); } } // Process verification code input async function handleCode(userId, code) { if (!code.match(/^\d+$/)) { await bot.sendMessage(userId, "❌ Code must be a number.\n" + "Please enter the verification code:" ); return; } const session = userSessions.get(userId); try { // Sign in with the code const result = await session.client.invoke( new Api.auth.SignIn({ phoneNumber: session.phone, phoneCodeHash: session.phoneCodeHash, phoneCode: code }) ); if (result._ === 'auth.authorizationSignUpRequired') { throw new Error("This phone number is not registered. Please sign up first."); } await finishSession(userId); } catch (error) { console.error('Error in handleCode:', error); if (error.errorMessage === "SESSION_PASSWORD_NEEDED") { session.state = STATES.PASSWORD; await bot.sendMessage(userId, "🔒 Your account has two-factor authentication enabled.\n" + "Please enter your 2FA password:" ); } else { let errorMessage = error.message; if (error.errorMessage === 'PHONE_CODE_INVALID') { errorMessage = "The verification code is invalid."; } else if (error.errorMessage === 'PHONE_CODE_EXPIRED') { errorMessage = "The verification code has expired. Please request a new one."; } await bot.sendMessage(userId, `❌ Sign-in failed: ${errorMessage}\n` + "Please try again with /pair." ); await cleanupSession(userId); } } } // Process 2FA password input async function handlePassword(userId, password) { const session = userSessions.get(userId); try { // Sign in with 2FA password await session.client.invoke( new Api.auth.CheckPassword({ password: password }) ); await finishSession(userId); } catch (error) { console.error('Error in handlePassword:', error); let errorMessage = error.message; if (error.errorMessage === 'PASSWORD_HASH_INVALID') { errorMessage = "The 2FA password is incorrect."; } await bot.sendMessage(userId, `❌ 2FA authentication failed: ${errorMessage}\n` + "Please try again with /pair." ); await cleanupSession(userId); } } // Complete the session creation and send the file async function finishSession(userId) { const session = userSessions.get(userId); try { await bot.sendMessage(userId, "🎉 Successfully signed in!\n" + "Generating your session file..." ); const sessionString = session.client.session.save(); const sessionFile = `aayco_${userId}.session`; fs.writeFileSync(sessionFile, sessionString); await bot.sendDocument(userId, sessionFile, { caption: "Here's your session file for your userbot. Keep it safe!", filename: 'aayco.session' }); await cleanupSession(userId); } catch (error) { console.error('Error in finishSession:', error); await bot.sendMessage(userId, `❌ Error creating session file: ${error.message}\n` + "Please try again with /pair." ); await cleanupSession(userId); } } // Start the bot console.log("Starting bot..."); // Error handling bot.on('polling_error', (error) => { console.error('Polling error:', error); }); process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection at:', promise, 'reason:', reason); }); // Graceful shutdown process.on('SIGINT', async () => { console.log('Shutting down...'); for (const [userId, session] of userSessions.entries()) { try { await cleanupSession(userId); } catch (error) { console.error(`Error cleaning up session for user ${userId}:`, error); } } bot.stopPolling(); process.exit(0); });