import fs = require("fs"); import { database as db, settings } from "./database"; import prompt from "prompts"; import logger from "./logger"; import * as telegram from "telegram"; import { LogLevel } from "telegram/extensions/Logger"; import { AccountInterface } from "./interfaces/databaseInterface"; import { sleep } from "telegram/Helpers"; import findFreePorts from "find-free-ports"; import { waitNewMessages, startNewTorDocker, getIP, getMessagesByEntity, isBannedByClient, randomAB, } from "./utils"; import TorControl from "tor-control"; import Miner from "@ulixee/miner"; import Hero from "@ulixee/hero"; import { portsInterface, usedIPInterface } from "./interfaces/otherInterfaces"; import { doSitesTasks, vertification, doChatsTasks, doBotTasks, } from "./automatization"; import ExecuteJsPlugin from "@ulixee/execute-js-plugin"; import _ from "lodash"; import Docker from "dockerode"; import cliProgress from "cli-progress"; import BigInteger from "big-integer"; const addAccounts: () => Promise = async () => { let apiId = 0; let apiHash = ""; let accounts = await db.getUsers(); if (accounts.length != 0) { const usePrevData = await prompt({ type: "confirm", name: "confirmed", message: "Use apiId and apiHash from last added account?", }); if (usePrevData.confirmed == true) { apiId = accounts[accounts.length - 1].apiID; apiHash = accounts[accounts.length - 1].apiHash; } } if (apiId == 0 && apiHash == "") { const api = await prompt([ { type: "number", name: "apiId", message: "ApiId?", }, { type: "text", name: "apiHash", message: "ApiHash?", }, ]); apiId = Number(api.apiId); apiHash = api.apiHash; } const jsonFiles: prompt.Choice[] = []; fs.readdirSync("./").forEach((file) => { if ( file.search(".json") != -1 && file != "db.json" && file != "settings.json" ) { jsonFiles.push({ title: file, description: "json file", value: file, }); } }); const walletsFile = ( await prompt({ type: "select", name: "file", message: "Choose wallets json file", choices: jsonFiles, }) ).file; await db.findWallet(walletsFile); mainLoop: while (true) { accounts = await db.getUsers(); const answers = await prompt([ { type: "text", name: "number", message: "Phone number?", }, { type: "text", name: "password", message: "2FA Password?", }, ]); for (const account of accounts) { if (account.phoneNumber == answers.number) { logger.warn("You already added this number"); continue mainLoop; } } const session = new telegram.sessions.StringSession(""); const client = new telegram.TelegramClient(session, apiId, apiHash, { deviceModel: "Samsung SM-G980", connectionRetries: 5, systemVersion: "10", }); client.setLogLevel(LogLevel.ERROR); await client.start({ phoneNumber: async () => answers.number.replace(/ /g, ""), password: async () => answers.password.replace(/ /g, ""), phoneCode: async () => ( await prompt({ type: "number", name: "code", message: "Enter recieved code", }) ).code.toString(), onError: (err) => { logger.error( `Error due singning into telegram account\n${err}` ); throw err; }, }); if ((await client.isUserAuthorized()) == true) { const account: telegram.Api.User | telegram.Api.InputPeerUser = await client.getMe(false); if (account instanceof telegram.Api.User) { await db.addUser( { password: answers.password, phoneNumber: answers.number, apiHash: apiHash, telegramID: Number(account.id), apiID: apiId, stringSession: String(client.session.save()), refferal: await db.findRefferal(settings.maxRefferals), }, walletsFile ); } else { logger.error("Wrong type of account?"); } } else { logger.error("Client not authorized"); } if ( ( await prompt({ type: "confirm", name: "continue", message: "continue?", }) ).continue != true ) { return; } } }; const farm: () => Promise = async () => { const usedIPs: usedIPInterface[] = []; const proccesGroup = async ( workersGroups: AccountInterface[], ports: portsInterface ) => { workersLoop: for (const worker of workersGroups) { logger.info( `Current worker:${worker.phoneNumber}\nBalance:${worker.balance}` ); { let tor: any; try { tor = new TorControl({ host: "127.0.0.1", port: ports.control, password: "qwerty", // Your password for tor-control persistent: false, // Keep connection (persistent) }); } catch (err) { logger.error( `Cant connect to tor control via ${ports.control}\n${err}` ); continue; } function isFree(currentIP: string) { for (const usedIP of usedIPs) { if ( usedIP.usedIps.indexOf(currentIP) != -1 || usedIP.current == currentIP ) { return false; } } return true; } while (true) { const currentIP = await getIP(ports.http); if (currentIP != null) { if (isFree(currentIP)) { usedIPs.filter((value) => { return _.isEqual(worker, value.worker); })[0].current = currentIP; usedIPs .filter((value) => { return _.isEqual(worker, value.worker); })[0] .usedIps.push(currentIP); break; } else { await tor.signalNewnym(); await sleep(3_000); } } } } const fingerprint = worker.browserFingerprint; let hero: Hero; while (true) { hero = new Hero({ userProfile: { deviceProfile: { deviceMemory: fingerprint.navigator.deviceMemory, }, }, name: `${worker.telegramID}`, connectionToCore: { host: `ws://127.0.0.1:${ports.minerPort}`, }, disableDevtools: true, // to bypass hk site showChrome: true, // to debug userAgent: fingerprint.navigator.userAgent, viewport: fingerprint.screen, locale: fingerprint.navigator.language, upstreamProxyUrl: `socks5://127.0.0.1:${ports.socks}`, upstreamProxyIpMask: { ipLookupService: "icanhazip.com", proxyIp: usedIPs.filter((value) => { return _.isEqual(worker, value.worker); })[0].current, }, }); hero.use(ExecuteJsPlugin); try { await hero.goto("https://www.google.com"); } catch (err) { await hero.close(); logger.warn( `Some error due openning Hero. Trying again...\n${err}` ); continue; } break; } const client = new telegram.TelegramClient( new telegram.sessions.StringSession(worker.stringSession), worker.apiID, worker.apiHash, { deviceModel: "Samsung SM-G980", connectionRetries: 5, systemVersion: "10", } ); client.setLogLevel(LogLevel.NONE); await client.connect(); if ((await client.checkAuthorization()) == false) { logger.error( `Account ${worker.phoneNumber} is not authorizated` ); continue workersLoop; } else { logger.debug( `Successfully connected to account ${worker.phoneNumber}` ); // https://gram.js.org/beta/modules/Api.channels.html // https://gram.js.org/beta/classes/Api.messages.DeleteChat.html let botEntity: telegram.Api.User; try { botEntity = (await client.getEntity( settings.telegramLinks.botLink )) as telegram.Api.User; } catch (err) { if (err instanceof telegram.errors.FloodWaitError) { switch (err.errorMessage) { case "FLOOD": logger.warn( `Account has flood(${err.seconds} secs timeout) error,skipping` ); break; default: logger.error( `Unknown error due getEntity ${err}` ); break; } } else { logger.error(`Unknown error due getEntity ${err}`); } usedIPs.filter((value) => { return _.isEqual(worker, value.worker); })[0].current = ""; usedIPs .filter((value) => { return _.isEqual(worker, value.worker); })[0] .usedIps.pop(); await hero.close(); continue workersLoop; } // leaving old groups { const now = new Date(); worker.completedGroupsTasks = worker.completedGroupsTasks.filter(async (oldGroup) => { if (+now > oldGroup.timeToLeave) { const olderGroups = worker.completedGroupsTasks.filter( (value) => { if ( value.groupID == oldGroup.groupID && value.timeToLeave > oldGroup.timeToLeave ) { return true; } else { return false; } } ); if (olderGroups.length == 0) { let peerChannel: telegram.Api.TypeInputPeer; try { peerChannel = await client.getInputEntity( BigInteger(oldGroup.groupID) ); } catch (err) { return false; } try { await client.invoke( new telegram.Api.channels.GetParticipant( { channel: peerChannel, participant: "me", } ) ); } catch (err) { if (err.code == 400) { return false; } else { logger.error( `Unknown error due GetParticipant | ${worker.phoneNumber}` ); return true; } } try { await client.invoke( new telegram.Api.channels.LeaveChannel( { channel: peerChannel, } ) ); } catch (err) { logger.debug( `Cant leave channel | ${worker.phoneNumber}` ); return true; } } return false; } else { return true; } }); } // for (const chat of settings.telegramLinks.groupsToJoin) { try { await client.invoke( new telegram.Api.channels.GetParticipant({ channel: chat, participant: "me", }) ); } catch (err) { if (err.code == 400) { try { await client.invoke( new telegram.Api.channels.JoinChannel({ channel: chat, }) ); } catch (err) { if (err instanceof telegram.errors.RPCError) { switch (err.errorMessage) { case "CHANNELS_TOO_MUCH": logger.error( `Too much groups | ${worker.phoneNumber}` ); continue workersLoop; default: logger.error( `Some error due joining HK groups | ${worker.phoneNumber}\n${err.message}\n${err.stack}` ); continue workersLoop; } } } } else { logger.error( `Unknown error due GetParticipant | ${worker.phoneNumber}` ); throw err; } } } { // unblock hkbot if ( await isBannedByClient( client, settings.telegramLinks.botLink ) ) { const result = await client.invoke( new telegram.Api.contacts.Unblock({ id: settings.telegramLinks.botLink, }) ); if (result != true) { logger.error( `Cant unblock ${settings.telegramLinks.botLink} | ${worker.phoneNumber}` ); continue workersLoop; } else { logger.info( `HK bot unblocked | ${worker.phoneNumber}` ); } } } await sleep(Math.random() * 50_000); if ( (await getMessagesByEntity(client, botEntity, botEntity)) .length == 0 ) { // sending start message let id = -1; if (worker.refferal !== null) { id = ( await client.sendMessage(botEntity, { message: `/start ${worker.refferal}`, }) ).id; logger.debug( `First start of ${botEntity.username} via refferal link of ${worker.refferal} | ${worker.phoneNumber}` ); } else { id = ( await client.sendMessage(botEntity, { message: `/start`, }) ).id; logger.debug( `First start of ${botEntity.username} | ${worker.phoneNumber}` ); } await waitNewMessages(client, worker, botEntity, id); } logger.info(`Sending earn message... | ${worker.phoneNumber}`); const requestTasksMessage = await client.sendMessage( botEntity, { message: settings.botButtons.earn, } ); await waitNewMessages( client, worker, botEntity, requestTasksMessage.id ); let tasksSelector: telegram.Api.Message = ( await client.getMessages(botEntity, { minId: requestTasksMessage.id, }) )[0]; if ( tasksSelector.message.includes( settings.botMessages.verification ) == true ) { // vertification logger.warn( `Account ${worker.phoneNumber} is unvertificated` ); const url: string = tasksSelector.buttons![0][0].url!; await vertification(hero, url); const requestTasksMessage = await client.sendMessage( botEntity, { message: settings.botButtons.earn, } ); await waitNewMessages( client, worker, botEntity, requestTasksMessage.id ); tasksSelector = ( await client.getMessages(botEntity, { minId: requestTasksMessage.id, }) )[0]; } try { await doSitesTasks( client, worker, hero, botEntity, tasksSelector ); await doChatsTasks( client, worker, hero, botEntity, tasksSelector ); try { await doBotTasks( client, worker, hero, botEntity, tasksSelector ); } catch (err) { await client.sendMessage(botEntity, { message: "/cancel", }); throw err; } } catch (err) { logger.error( `Some error due doing tasks\n${err}\n${err.stack}` ); } db.updateUser(worker); await hero.close(); await client.disconnect(); await sleep( randomAB( settings.sleepTime.betweenSessions[0], settings.sleepTime.betweenSessions[1] ) * 1_000 ); } } }; const workers = await db.getUsers(); if (settings.shuffleAccounts) { workers.sort(() => Math.random() - 0.5); } const workersGroups: Array = []; for (const worker of workers) { usedIPs.push({ worker: worker, usedIps: [], current: "", }); } for (let i = 0; i != settings.pararels; i++) { const startIndex = i * Math.ceil(workers.length / settings.pararels); const _workers = workers.slice( startIndex, startIndex + Math.ceil(workers.length / settings.pararels) ); workersGroups.push(_workers); } const pararels: Promise[] = []; const miner = new Miner(); await miner.listen({ port: (await findFreePorts(1))[0] }); const _ports = await findFreePorts(workers.length * 3); // logger.debug(`Is there port of miner:${_ports.indexOf(await miner.port)}, ${await miner.port}`) let containers: Docker.Container[] = []; { const multibar = new cliProgress.MultiBar({ hideCursor: true, barsize: 50, barCompleteChar: "❌", barIncompleteChar: "✔️", clearOnComplete: true, format: `{status} | {bar} | {value}/{total}sec timeout`, }); const _containers: Promise[] = []; for (let i = 0; i != workersGroups.length; i++) { _containers.push( startNewTorDocker( _ports[i * 3], _ports[i * 3 + 1], _ports[i * 3 + 2], multibar ) ); } containers = (await Promise.allSettled(_containers)).map((value) => { return (value as PromiseFulfilledResult).value; }); multibar.stop(); } for (let i = 0; i != workersGroups.length; i++) { pararels.push( proccesGroup(workersGroups[i], { http: _ports[i * 3], socks: _ports[i * 3 + 1], control: _ports[i * 3 + 2], minerPort: await miner.port, }) ); } const results = await Promise.allSettled(pararels); for (const result of results) { if (result.status == "rejected") { logger.warn(`Promise is canceled due ${result.reason}`); } } logger.debug("Closing opened docker containers "); for (const container of containers) { try { await container.stop(); } catch (err) {} } await db.save(); await miner.close(true); }; // menu (async () => { while (true) { let accounts: AccountInterface[] = []; try { accounts = await db.getUsers(); } catch (err) { continue; } const answer = await prompt({ type: "select", name: "menu", message: "Choose action", choices: [ accounts.length > 0 ? { title: "Start", description: `Starting farm for ${accounts.length} accounts`, value: "start", } : { title: "Start", description: "Add accounts first...", value: "start", disabled: true, }, { title: "Add accounts", description: "Add accounts to database", value: "addAccounts", }, { title: "Check balances", value: "checkBalances", disabled: true, }, { title: "Withdraw", value: "withdraw", disabled: true }, { title: "Exit", description: "You realy dont know what it mean?", }, ], }); switch (answer.menu) { case "addAccounts": await addAccounts(); break; case "start": while (true) { try { await farm(); const sleepTime = randomAB( settings.sleepTime.afterDoing[0], settings.sleepTime.afterDoing[1] ); logger.info(`Sleeping for ${sleepTime} secs`); await sleep(sleepTime * 1_000); } catch (err) { logger.error( `Unknown error\n${err.stack}\n${typeof err}` ); break; } } break; default: logger.info("Bye bye"); process.exit(); } } })(); process.on("SIGINT", function () { db.save().then(() => { logger.info("Bye bye"); process.exit(); }); });