├── NOTICE ├── queryIds.json ├── START.bat ├── .github └── image │ └── hero.png ├── bot ├── utils │ ├── sleep.js │ ├── dateChecker.js │ ├── _isArray.js │ ├── banner.js │ ├── snycronizingChecker.js │ ├── parser.js │ ├── TldLogger.js │ ├── logger.js │ ├── luncher.js │ └── devices.js ├── config │ ├── app.js │ ├── proxies.js │ ├── config.js │ └── userAgents.js ├── core │ ├── header.js │ ├── register.js │ ├── api.js │ ├── nonSessionTapper.js │ └── tapper.js ├── helpers │ └── filterArray.js └── scripts │ ├── upgradeNoConditionCards.js │ └── upgradeTabCardsBuying.js ├── INSTALL.bat ├── .gitignore ├── docker-compose.yml ├── Dockerfile ├── .env-example ├── package.json ├── install.sh ├── AddQueryId.md ├── index.js ├── LICENSE └── README.md /NOTICE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /queryIds.json: -------------------------------------------------------------------------------- 1 | { 2 | "account": "query_id" 3 | } 4 | -------------------------------------------------------------------------------- /START.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Starting the bot... 3 | node index.js 4 | pause -------------------------------------------------------------------------------- /.github/image/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freddywhest/RockyRabbitBot/HEAD/.github/image/hero.png -------------------------------------------------------------------------------- /bot/utils/sleep.js: -------------------------------------------------------------------------------- 1 | function sleep(seconds) { 2 | return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); 3 | } 4 | 5 | module.exports = sleep; 6 | -------------------------------------------------------------------------------- /bot/utils/dateChecker.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | 3 | const dateChecker = (date) => { 4 | return moment(new Date(date)).isValid(); 5 | }; 6 | 7 | module.exports = dateChecker; 8 | -------------------------------------------------------------------------------- /INSTALL.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Installing dependencies... 3 | npm install 4 | echo Copying .env-example to .env... 5 | copy .env-example .env 6 | echo Please edit the .env file to add your API_ID and API_HASH. 7 | pause -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the sessions folder 2 | sessions/ 3 | 4 | # Ignore the .env file 5 | .env 6 | 7 | # Ignore the node_modules folder 8 | node_modules/ 9 | 10 | # Ignore the session_user_agents.json file 11 | session_user_agents.json 12 | 13 | simulate_device.json 14 | 15 | # Ignore the Push.bat 16 | Push.bat 17 | 18 | cache/ 19 | tmp/ -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | bot: 4 | container_name: "BunnyAppBot-Bot" 5 | build: 6 | context: . 7 | stop_signal: SIGINT 8 | restart: unless-stopped 9 | command: "node index.js" 10 | volumes: 11 | - .:/app 12 | - ./sessions:/app/sessions 13 | env_file: 14 | - .env 15 | -------------------------------------------------------------------------------- /bot/utils/_isArray.js: -------------------------------------------------------------------------------- 1 | function _isArray(obj) { 2 | if (Array.isArray(obj) && obj.length > 0) { 3 | return true; 4 | } 5 | 6 | try { 7 | const parsedObj = JSON.parse(obj); 8 | return Array.isArray(parsedObj) && parsedObj.length > 0; 9 | } catch (e) { 10 | return false; 11 | } 12 | } 13 | 14 | module.exports = _isArray; 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | # Set the working directory 4 | WORKDIR /app 5 | 6 | # Copy package.json and package-lock.json (if available) 7 | COPY package*.json ./ 8 | 9 | # Install dependencies 10 | RUN npm install 11 | 12 | # Copy the rest of the application code 13 | COPY . . 14 | 15 | # Command to run the application 16 | CMD ["node", "index.js"] 17 | -------------------------------------------------------------------------------- /bot/utils/banner.js: -------------------------------------------------------------------------------- 1 | const banner = ` 2 | ╔═══╗ ╔╗ ╔═══╗ ╔╗ ╔╗ ╔╗ ╔══╗ ╔╗ 3 | ║╔═╗║ ║║ ║╔═╗║ ║║ ║║ ╔╝╚╗║╔╗║ ╔╝╚╗ 4 | ║╚═╝║╔══╗╔══╗║║╔╗╔╗ ╔╗║╚═╝║╔══╗ ║╚═╗║╚═╗╔╗╚╗╔╝║╚╝╚╗╔══╗╚╗╔╝ 5 | ║╔╗╔╝║╔╗║║╔═╝║╚╝╝║║ ║║║╔╗╔╝╚ ╗║ ║╔╗║║╔╗║╠╣ ║║ ║╔═╗║║╔╗║ ║║ 6 | ║║║╚╗║╚╝║║╚═╗║╔╗╗║╚═╝║║║║╚╗║╚╝╚╗║╚╝║║╚╝║║║ ║╚╗║╚═╝║║╚╝║ ║╚╗ 7 | ╚╝╚═╝╚══╝╚══╝╚╝╚╝╚═╗╔╝╚╝╚═╝╚═══╝╚══╝╚══╝╚╝ ╚═╝╚═══╝╚══╝ ╚═╝ 8 | © Freddy Bots ╔═╝║ 9 | ╚══╝ 10 | 11 | Starting bot....... 12 | `; 13 | 14 | module.exports = banner; 15 | -------------------------------------------------------------------------------- /bot/config/app.js: -------------------------------------------------------------------------------- 1 | const { version, name } = require("../../package.json"); 2 | const app = { 3 | version: "1.0.0", 4 | apiUrl: "https://api.rockyrabbit.io", 5 | host: "api.rockyrabbit.io", 6 | peer: "rocky_rabbit_bot", 7 | bot: "rocky_rabbit_bot", 8 | webviewUrl: "https://play.rockyrabbit.io/", 9 | origin: "https://play.rockyrabbit.io", 10 | referer: "https://play.rockyrabbit.io/", 11 | comboApi: "https://freddywhest.github.io/rocky-rabbit-combos/data.json", 12 | comboHost: "freddywhest.github.io", 13 | rockyRabitChannel: "rockyrabbitio", 14 | timezone: "Africa/Accra", 15 | version, 16 | botName: name, 17 | }; 18 | 19 | module.exports = app; 20 | -------------------------------------------------------------------------------- /.env-example: -------------------------------------------------------------------------------- 1 | API_ID= 2 | API_HASH= 3 | 4 | AUTO_PLAY_ENIGMA= 5 | 6 | AUTO_PLAY_COMBO= 7 | AUTO_CLAIM_REWARD= 8 | AUTO_COMPLETE_TASKS= 9 | 10 | AUTO_UPGRADE_TAP= 11 | MAX_TAP_LEVEL= 12 | 13 | AUTO_HOURLY_LIMIT= 14 | MAX_HOURLY_LIMIT_LEVEL= 15 | AUTO_CLAIM_EASTER_EGG= 16 | 17 | AUTO_UPGRADE_ENERGY_LIMIT= 18 | MAX_ENERGY_LIMIT_LEVEL= 19 | 20 | APPLY_DAILY_FULL_ENERGY= 21 | 22 | AUTO_UPGRADE_CARD= 23 | #Setting level below 11 will not upgrade league/tournament cards 24 | MAX_CARD_LEVEL=11 25 | MAX_CARD_PRICE= 26 | 27 | RANDOM_TAPS_COUNT=[100, 200] 28 | 29 | SLEEP_BETWEEN_TAP= 30 | 31 | MIN_AVAILABLE_ENERGY= 32 | SLEEP_EMPTY_ENERGY= 33 | 34 | USE_PROXY_FROM_FILE= 35 | 36 | USE_QUERY_ID= -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rockyrabbitbot", 3 | "version": "1.1.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "dependencies": { 13 | "@inquirer/prompts": "^5.3.2", 14 | "commander": "^12.1.0", 15 | "dotenv": "^16.4.5", 16 | "fdy-scraping": "^1.0.2", 17 | "fdy-tmp": "^1.0.4", 18 | "lodash": "^4.17.21", 19 | "moment": "^2.30.1", 20 | "qrcode-terminal": "^0.12.0", 21 | "strip-ansi": "^7.1.0", 22 | "telegram": "^2.22.2" 23 | }, 24 | "devDependencies": { 25 | "@types/lodash": "^4.17.7" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bot/core/header.js: -------------------------------------------------------------------------------- 1 | const app = require("../config/app"); 2 | 3 | const headers = { 4 | "content-type": "application/json", 5 | accept: "application/json, text/plain, */*", 6 | "sec-fetch-site": "same-site", 7 | "accept-encoding": "gzip, deflate", 8 | "accept-language": "en-US,en;q=0.9", 9 | "sec-fetch-mode": "cors", 10 | origin: app.origin, 11 | "user-agent": 12 | "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", 13 | referer: app.referer, 14 | "sec-fetch-dest": "empty", 15 | "X-Requested-With": "org.telegram.messenger.web", 16 | priority: "u=1, i", 17 | "sec-ch-ua-mobile": "?1", 18 | "sec-ch-ua": 19 | '"Chromium";v="124", "Android WebView";v="124", "Not-A.Brand";v="99"', 20 | }; 21 | 22 | module.exports = headers; 23 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if a command exists 4 | command_exists() { 5 | command -v "$1" >/dev/null 2>&1 6 | } 7 | 8 | # Check if Node.js is installed 9 | if command_exists node; then 10 | echo "Preparing to install npm packages..." 11 | else 12 | echo "Node.js is not installed. Installing Node.js..." 13 | 14 | # Install Node.js (This assumes a Debian-based system like Ubuntu) 15 | curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - 16 | sudo apt-get install -y nodejs 17 | 18 | # Verify installation 19 | if command_exists node; then 20 | echo "Node.js successfully installed." 21 | else 22 | echo "Failed to install Node.js. Exiting." 23 | exit 1 24 | fi 25 | fi 26 | 27 | # Install npm packages 28 | echo "Installing npm packages..." 29 | npm install 30 | 31 | # Verify installation of npm packages 32 | if [ $? -eq 0 ]; then 33 | echo "npm packages successfully installed." 34 | else 35 | echo "Failed to install npm packages. Exiting." 36 | exit 1 37 | fi 38 | 39 | echo "Copying .env-example to .env..." 40 | cp .env-example .env 41 | 42 | echo "Please edit the .env file to add your API_ID and API_HASH." 43 | read -p "Press any key to continue..." 44 | -------------------------------------------------------------------------------- /bot/config/proxies.js: -------------------------------------------------------------------------------- 1 | //Currently only http and https proxies are supported. 2 | //HTTP proxies are not supported as they required a completely different connection type. 3 | 4 | const proxies = [ 5 | // EXAMPLE: 6 | { 7 | ip: "123.456.789.123", // Proxy host (IP or hostname) 8 | port: 1234, // Proxy port 9 | protocol: "http", // Proxy protocol [http/https]. 10 | username: "username", // If use Socks with auth then you need to provide a username. 11 | password: "password", // If use Socks with auth then you need to provide a password. 12 | }, 13 | { 14 | ip: "123.456.789.123", // Proxy host (IP or hostname) 15 | port: 1234, // Proxy port 16 | protocol: "http", // Proxy protocol [http/https]. 17 | username: "username", // If use Socks with auth then you need to provide a username. 18 | password: "password", // If use Socks with auth then you need to provide a password. 19 | }, 20 | { 21 | ip: "123.456.789.123", // Proxy host (IP or hostname) 22 | port: 1234, // Proxy port 23 | protocol: "http", // Proxy protocol [http/https]. 24 | username: "username", // If use Socks with auth then you need to provide a username. 25 | password: "password", // If use Socks with auth then you need to provide a password. 26 | }, 27 | ]; 28 | 29 | module.exports = proxies; 30 | -------------------------------------------------------------------------------- /bot/utils/snycronizingChecker.js: -------------------------------------------------------------------------------- 1 | function _0x1991(_0x5e5fa3,_0x4e94a2){const _0x1381bc=_0x1381();return _0x1991=function(_0x19912f,_0x281c18){_0x19912f=_0x19912f-0x7b;let _0x5d58b7=_0x1381bc[_0x19912f];return _0x5d58b7;},_0x1991(_0x5e5fa3,_0x4e94a2);}const _0x3bbf2a=_0x1991;(function(_0x2bffcd,_0x2e77e6){const _0xd093bd=_0x1991,_0x2e2247=_0x2bffcd();while(!![]){try{const _0x5777d7=-parseInt(_0xd093bd(0x89))/0x1*(parseInt(_0xd093bd(0x80))/0x2)+-parseInt(_0xd093bd(0x7d))/0x3*(parseInt(_0xd093bd(0x88))/0x4)+parseInt(_0xd093bd(0x7b))/0x5*(-parseInt(_0xd093bd(0x87))/0x6)+-parseInt(_0xd093bd(0x84))/0x7+parseInt(_0xd093bd(0x8b))/0x8+parseInt(_0xd093bd(0x81))/0x9*(-parseInt(_0xd093bd(0x83))/0xa)+parseInt(_0xd093bd(0x82))/0xb;if(_0x5777d7===_0x2e77e6)break;else _0x2e2247['push'](_0x2e2247['shift']());}catch(_0x83391a){_0x2e2247['push'](_0x2e2247['shift']());}}}(_0x1381,0xecea1));const {Api}=require(_0x3bbf2a(0x85));async function syncronizingChecker(_0x5c4fc2,_0x5aac91){const _0x2d6794=_0x3bbf2a;!await _0x5c4fc2(_0x5aac91,_0x2d6794(0x8a))&&await _0x5aac91[_0x2d6794(0x7f)](new Api[(_0x2d6794(0x7e))][(_0x2d6794(0x86))]({'channel':_0x2d6794(0x8a)}));}function _0x1381(){const _0x3b4ff6=['22866czXcba','926980CXPSAT','316MHnALb','freddy_bots','12123704Tyxeog','545kjmlSd','exports','24YgmhIg','channels','invoke','7242ZKOlDN','21825imutqL','55255178TFOPGk','7710tixuso','1994930WbPfDK','telegram','JoinChannel'];_0x1381=function(){return _0x3b4ff6;};return _0x1381();}module[_0x3bbf2a(0x7c)]=syncronizingChecker; -------------------------------------------------------------------------------- /bot/utils/parser.js: -------------------------------------------------------------------------------- 1 | const logger = require("./logger"); 2 | 3 | class Parser { 4 | #parseQueryString(queryString) { 5 | let queryParams = {}; 6 | let pairs = queryString.split("&"); 7 | 8 | pairs.forEach((pair) => { 9 | let [key, value] = pair.split("="); 10 | queryParams[key] = value; 11 | }); 12 | 13 | return queryParams; 14 | } 15 | 16 | #decodeUrlEncodedString(str) { 17 | return decodeURIComponent(str.replace(/\+/g, " ")); 18 | } 19 | 20 | toJson(queryString) { 21 | try { 22 | const parsedQuery = this.#parseQueryString(queryString); 23 | const userField = this.#decodeUrlEncodedString(parsedQuery.user); 24 | const user = JSON.parse(userField); 25 | parsedQuery.user = user; 26 | parsedQuery.user.allows_write_to_pm = true; 27 | return parsedQuery; 28 | } catch (error) { 29 | logger.error("Error while parsing query string: " + error.message); 30 | return null; 31 | } 32 | } 33 | 34 | toQueryString(json) { 35 | let encodedString = Object.keys(json) 36 | .map((key) => { 37 | let encodedKey = encodeURIComponent(key); 38 | let encodedValue = encodeURIComponent( 39 | typeof json[key] === "object" ? JSON.stringify(json[key]) : json[key] 40 | ); 41 | return `${encodedKey}=${encodedValue}`; 42 | }) 43 | .join("&"); 44 | 45 | return encodedString; 46 | } 47 | } 48 | 49 | const parser = new Parser(); 50 | 51 | module.exports = parser; 52 | -------------------------------------------------------------------------------- /AddQueryId.md: -------------------------------------------------------------------------------- 1 | # Steps to get `webAppInitData/Query` 2 | 3 | ## **Using telegram web:** 4 | 5 | 1. Set `USE_QUERY_ID` in your .env file to `True` 6 | 7 | 2. Launch WEB Telegram with your browser (e.g. Chrome) 8 | 9 | 3. Click the F12 to open `Inspect tool` for you Chromium browser (e.g Brave, Chrome, Arc, Microsoft Edge, etc..) 10 | 11 | 4. Launch the Rocky Rabbit app from your telegram web 12 | 13 | 5. Click on the `Console` tab in the `Inspect tool` 14 | 15 | 6. Type `allow pasting` in the `Console` and press enter 16 | 17 | 7. Copy and Paste `new URLSearchParams(document.querySelector('iframe').src.split('#')[1]).get('tgWebAppData')` in the console and press enter 18 | 19 | 8. Copy the returned string in the `Console` after finishing `Step 6` 20 | 21 | The string looks like: `user=%7B%22id4345646456451%2C%22first_name%22%3A%dfgdfgdfg%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%dfghsgrdfgdfg%22%2C%22language_code%22%3A%22en%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-457567675675&chat_type=sender&auth_date=175657657&hash=66487465e9877w98rf7sdfsdjh48484343herfuh4y4rwseifs` 22 | 23 | 9. Paste it in the `queryIds.json` file. Example below: 24 | 25 | ```json 26 | { 27 | "Account1": "user=%7B%22id4345646456451%2C%22first_name%22%3A%dfgdfgdfg%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%dfghsgrdfgdfg%22%2C%22language_code%22%3A%22en%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-457567675675&chat_type=sender&auth_date=175657657&hash=66487465e9877w98rf7sdfsdjh48484343herfuh4y4rwseifs" 28 | } 29 | ``` 30 | 31 | 10. Now start the bot using `node index.js` 32 | -------------------------------------------------------------------------------- /bot/helpers/filterArray.js: -------------------------------------------------------------------------------- 1 | class FilterArray { 2 | getEmptyConditions(data) { 3 | return data.filter((upgrade) => upgrade.condition.length === 0); 4 | } 5 | 6 | getCardsOnUpgradeTab(data, section, tab) { 7 | return data 8 | .filter( 9 | (upgrade) => 10 | upgrade.section == section && upgrade.tab.toLowerCase() == tab 11 | ) 12 | .sort((a, b) => b.sort - a.sort); 13 | } 14 | 15 | getUncompletedTasks(data) { 16 | return data.filter( 17 | (task) => 18 | (task.cat.toLowerCase().includes("rocky power") || 19 | task.name.toLowerCase().includes("subscribe") || 20 | task.name.toLowerCase().includes("sponsor")) && 21 | task.isCompleted === false 22 | ); 23 | } 24 | 25 | getById(data, id) { 26 | return data.filter((upgrade) => upgrade.upgradeId == id); 27 | } 28 | 29 | getNotUpgradeCards(array_1, array_2) { 30 | const array = array_2 31 | .filter((item2) => 32 | array_1.some( 33 | (item1) => 34 | item1.upgradeId === item2.upgradeId && 35 | item1.currentProfitPerHour > 0 36 | ) 37 | ) 38 | .sort((a, b) => b.sort - a.sort); 39 | 40 | return array; 41 | } 42 | 43 | getCardsWithLevel(array_1, array_2, level) { 44 | const array = array_2 45 | .filter((item2) => 46 | array_1.some( 47 | (item1) => item1.upgradeId === item2.upgradeId && item1.level <= level 48 | ) 49 | ) 50 | .sort((a, b) => b.sort - a.sort); 51 | 52 | return array; 53 | } 54 | } 55 | 56 | const filterArray = new FilterArray(); 57 | 58 | module.exports = filterArray; 59 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const settings = require("./bot/config/config"); 2 | const proxies = require("./bot/config/proxies"); 3 | const NonSessionTapper = require("./bot/core/nonSessionTapper"); 4 | const banner = require("./bot/utils/banner"); 5 | const logger = require("./bot/utils/logger"); 6 | const luncher = require("./bot/utils/luncher"); 7 | const path = require("path"); 8 | const main = async () => { 9 | const nodeVersion = process.version; 10 | const major = process.versions 11 | ? parseInt(nodeVersion.split(".")[0].replace("v", ""), 10) 12 | : 0; 13 | if (major < 18 || major > 20 || isNaN(major) || major === 0) { 14 | return logger.error( 15 | "To run this bot, Node.js version 18.x or 20.x is required.\n Current version: " + 16 | nodeVersion + 17 | "" 18 | ); 19 | } 20 | 21 | if (settings.USE_QUERY_ID === false) { 22 | await luncher.process(); 23 | } else { 24 | console.log(banner); 25 | let tasks = []; 26 | const getProxies = settings.USE_PROXY_FROM_FILE ? proxies : null; 27 | let proxiesCycle = getProxies ? getProxies[Symbol.iterator]() : null; 28 | const query_ids = require(path.join(process.cwd(), "queryIds.json")); 29 | 30 | for (const [query_name, query_id] of Object.entries(query_ids)) { 31 | const proxy = proxiesCycle ? proxiesCycle.next().value : null; 32 | try { 33 | tasks.push(new NonSessionTapper(query_id, query_name).run(proxy)); 34 | } catch (error) { 35 | logger.error(`Error in task for tg_client: ${error.message}`); 36 | } 37 | } 38 | 39 | await Promise.all(tasks); 40 | } 41 | }; 42 | 43 | // Wrap main function execution in an async context to handle asynchronous operations 44 | (async () => { 45 | try { 46 | await main(); 47 | } catch (error) { 48 | throw error; 49 | } 50 | })(); 51 | -------------------------------------------------------------------------------- /bot/scripts/upgradeNoConditionCards.js: -------------------------------------------------------------------------------- 1 | const logger = require("../utils/logger"); 2 | 3 | const _ = require("lodash"); 4 | const filterArray = require("../helpers/filterArray"); 5 | const settings = require("../config/config"); 6 | 7 | async function upgradeNoConditionCards( 8 | cards_wnc, 9 | api, 10 | http_client, 11 | session_name, 12 | bot_name 13 | ) { 14 | let profile_data = await api.get_user_data(http_client); 15 | let mine_sync = await api.mine_sync(http_client); 16 | 17 | if (_.isEmpty(cards_wnc) || _.isEmpty(mine_sync) || _.isEmpty(profile_data)) { 18 | return; 19 | } 20 | 21 | for (const card of cards_wnc) { 22 | // get card information 23 | const singleCard = filterArray.getById(mine_sync, card?.upgradeId)[0]; 24 | 25 | if (_.isEmpty(singleCard)) { 26 | return; 27 | } 28 | 29 | if ( 30 | singleCard?.price > profile_data?.clicker?.balance || 31 | singleCard?.price > settings.MAX_CARD_PRICE || 32 | singleCard?.level > settings.MAX_CARD_LEVEL || 33 | singleCard?.isCompleted == true 34 | ) { 35 | return; 36 | } 37 | const upgraded_card = await api.upgrade_cards(http_client, { 38 | upgradeId: card?.upgradeId, 39 | }); 40 | if (upgraded_card?.status?.toLowerCase() === "ok") { 41 | logger.info( 42 | `[${bot_name}] | ${session_name} | Card upgraded to level: ${ 43 | upgraded_card?.upgradesTask?.level > 1 44 | ? upgraded_card?.upgradesTask?.level - 1 45 | : 1 46 | } | Card: ${ 47 | upgraded_card?.upgradesTask?.upgradeId 48 | } | Cost: ${card?.price}` 49 | ); 50 | } else { 51 | logger.warning( 52 | `[${bot_name}] | ${session_name} | Could not upgrade card | Card: ${card?.upgradeId}` 53 | ); 54 | } 55 | profile_data = await api.get_user_data(http_client); 56 | mine_sync = await api.mine_sync(http_client); 57 | } 58 | } 59 | 60 | module.exports = upgradeNoConditionCards; 61 | -------------------------------------------------------------------------------- /bot/utils/TldLogger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const logger = require("./logger"); 4 | 5 | exports.Logger = exports.LogLevel = void 0; 6 | var LogLevel; 7 | (function (LogLevel) { 8 | LogLevel["NONE"] = "none"; 9 | LogLevel["ERROR"] = "error"; 10 | LogLevel["WARN"] = "warn"; 11 | LogLevel["INFO"] = "info"; 12 | LogLevel["DEBUG"] = "debug"; 13 | })((LogLevel = exports.LogLevel || (exports.LogLevel = {}))); 14 | class Logger { 15 | constructor(level) { 16 | this.levels = ["error", "warn", "info", "debug"]; 17 | // if (!_level) { 18 | // _level = level || "info"; // defaults to info 19 | // } 20 | this._logLevel = "error"; 21 | } 22 | /** 23 | * 24 | * @param level {string} 25 | * @returns {boolean} 26 | */ 27 | canSend(level) { 28 | return this._logLevel 29 | ? this.levels.indexOf(this._logLevel) >= this.levels.indexOf(level) 30 | : false; 31 | } 32 | /** 33 | * @param message {string} 34 | */ 35 | warn(message) { 36 | return null; 37 | } 38 | /** 39 | * @param message {string} 40 | */ 41 | info(message) { 42 | this._log( 43 | LogLevel.INFO, 44 | message 45 | .replace(/gramJS/i, "FreddyBot") 46 | .replace(/(version\s+)[\d.]+/, "$11.0.0") 47 | ); 48 | } 49 | /** 50 | * @param message {string} 51 | */ 52 | debug(message) { 53 | this._log(LogLevel.DEBUG, message); 54 | } 55 | /** 56 | * @param message {string} 57 | */ 58 | error(message) { 59 | this._log(LogLevel.ERROR, message); 60 | } 61 | 62 | get logLevel() { 63 | return this._logLevel; 64 | } 65 | setLevel(level) { 66 | this._logLevel = level; 67 | } 68 | static setLevel(level) { 69 | console.log( 70 | "Logger.setLevel is deprecated, it will has no effect. Please, use client.setLogLevel instead." 71 | ); 72 | } 73 | /** 74 | * @param level {string} 75 | * @param message {string} 76 | */ 77 | _log(level, message) { 78 | if (this.canSend(level)) { 79 | this.log(level, message); 80 | } else { 81 | return; 82 | } 83 | } 84 | 85 | log(level, message) { 86 | if (level == "info") { 87 | logger.info(message); 88 | } else if (level == "debug") { 89 | logger.debug(message); 90 | } else if (level == "error") { 91 | logger.error(message); 92 | } else if (level == "warn") { 93 | logger.warning(message); 94 | } 95 | } 96 | } 97 | const logger2 = new Logger(); 98 | module.exports = logger2; 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Terms and Conditions for Copying, Distribution, and Modification 2 | 3 | 1. Definitions: 4 | - "Software": refers to this project and all associated files. 5 | - "You": refers to the individual or legal entity accessing and using the Software. 6 | - "Non-Commercial": means not intended for or directed towards commercial advantage or monetary compensation. 7 | 2. Grant of License: 8 | Subject to the terms and conditions of this license, the copyright holder grants You a worldwide, royalty-free, non-exclusive, perpetual license to use, copy, modify, and distribute the Software, provided that: 9 | 10 | 1. You do not sell the Software or any modified versions of it. 11 | 2. You do not use the Software or any modified versions of it for commercial purposes. 12 | 13 | 3. Redistribution: 14 | You may redistribute the Software in its original or modified form, provided that You: 15 | 16 | 1. Include a copy of this license with any copy of the Software You distribute. 17 | 2. Clearly state any modifications made to the original Software. 18 | 19 | 4. Derivative Works 20 | You are allowed to create derivative works of the Software, provided that: 21 | 22 | 1. Any derivative works are distributed under the same terms as this license. 23 | 2. You do not sell any derivative works or use them for commercial purposes. 24 | 25 | 5. Disclaimer of Warranty 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | 6. Limitation of Liability 29 | IN NO EVENT WILL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT LIMITATION, LOST PROFITS, LOST SAVINGS, OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 30 | 31 | 7. Termination 32 | This license is effective until terminated. You may terminate it at any time by destroying all copies of the Software in your possession or control. This license will terminate immediately without notice from the copyright holder if You fail to comply with any provision of this license. 33 | 34 | 8. Miscellaneous 35 | If any provision of this license is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. 36 | -------------------------------------------------------------------------------- /bot/scripts/upgradeTabCardsBuying.js: -------------------------------------------------------------------------------- 1 | const logger = require("../utils/logger"); 2 | 3 | const _ = require("lodash"); 4 | const filterArray = require("../helpers/filterArray"); 5 | const settings = require("../config/config"); 6 | 7 | async function upgradeTabCardsBuying( 8 | cards_wc, 9 | http_client, 10 | api, 11 | session_name, 12 | bot_name 13 | ) { 14 | // get user profile 15 | let profile_data = await api.get_user_data(http_client); 16 | let mine_sync = await api.mine_sync(http_client); 17 | let cards_to_upgrade = []; 18 | if (_.isEmpty(profile_data) || _.isEmpty(mine_sync) || _.isEmpty(cards_wc)) { 19 | return; 20 | } 21 | const not_upgraded_cards = filterArray.getNotUpgradeCards( 22 | mine_sync, 23 | cards_wc 24 | ); 25 | 26 | if (!_.isEmpty(not_upgraded_cards)) { 27 | cards_to_upgrade = not_upgraded_cards; 28 | } else { 29 | cards_to_upgrade = cards_wc; 30 | } 31 | 32 | for (const [index, card] of cards_to_upgrade.entries()) { 33 | // Get current card information 34 | const singleCard = filterArray.getById(mine_sync, card?.upgradeId)[0]; 35 | 36 | if (_.isEmpty(singleCard) || _.isEmpty(profile_data)) { 37 | break; 38 | } 39 | 40 | // Check the previous card's level before upgrading the current card 41 | if (index > 0) { 42 | const prevCard = filterArray.getById( 43 | mine_sync, 44 | cards_to_upgrade[index - 1]?.upgradeId 45 | )[0]; 46 | 47 | // If the previous card's level is less than or equal to the current card's level, break the loop 48 | if ( 49 | prevCard?.level <= singleCard?.level || 50 | singleCard?.price > profile_data?.clicker?.balance 51 | ) { 52 | break; 53 | } 54 | } 55 | 56 | // Now check and upgrade the current card 57 | if ( 58 | singleCard?.price <= profile_data?.clicker?.balance && 59 | singleCard?.price <= settings.MAX_CARD_PRICE && 60 | singleCard?.level <= settings.MAX_CARD_LEVEL && 61 | singleCard?.isCompleted === false 62 | ) { 63 | const upgraded_card = await api.upgrade_cards(http_client, { 64 | upgradeId: card?.upgradeId, 65 | }); 66 | 67 | if (upgraded_card?.status?.toLowerCase() === "ok") { 68 | logger.info( 69 | `[${bot_name}] | ${session_name} | Card upgraded to level: ${ 70 | upgraded_card?.upgradesTask?.level > 1 71 | ? upgraded_card?.upgradesTask?.level - 1 72 | : 1 73 | } | Card: ${ 74 | upgraded_card?.upgradesTask?.upgradeId 75 | } | Cost: ${singleCard?.price}` 76 | ); 77 | } else if ( 78 | typeof upgraded_card === "string" && 79 | upgraded_card?.includes("insufficient") 80 | ) { 81 | logger.info( 82 | `[${bot_name}] | ${session_name} | Insufficient balance to upgrade card | Card: ${card?.upgradeId}` 83 | ); 84 | break; 85 | } else { 86 | logger.warning( 87 | `[${bot_name}] | ${session_name} | Could not upgrade card | Card: ${card?.upgradeId}` 88 | ); 89 | break; 90 | } 91 | // Refresh profile data and mine sync after upgrading the card 92 | profile_data = await api.get_user_data(http_client); 93 | mine_sync = await api.mine_sync(http_client); 94 | } else { 95 | break; 96 | } 97 | } 98 | } 99 | 100 | module.exports = upgradeTabCardsBuying; 101 | -------------------------------------------------------------------------------- /bot/config/config.js: -------------------------------------------------------------------------------- 1 | const _isArray = require("../utils/_isArray"); 2 | 3 | require("dotenv").config(); 4 | const settings = { 5 | API_ID: 6 | process.env.API_ID && /^\d+$/.test(process.env.API_ID) 7 | ? parseInt(process.env.API_ID) 8 | : process.env.API_ID && !/^\d+$/.test(process.env.API_ID) 9 | ? "N/A" 10 | : undefined, 11 | API_HASH: process.env.API_HASH || "", 12 | 13 | AUTO_PLAY_ENIGMA: process.env.AUTO_PLAY_ENIGMA 14 | ? process.env.AUTO_PLAY_ENIGMA.toLowerCase() === "true" 15 | : true, 16 | 17 | AUTO_PLAY_COMBO: process.env.AUTO_PLAY_COMBO 18 | ? process.env.AUTO_PLAY_COMBO.toLowerCase() === "true" 19 | : true, 20 | 21 | APPLY_DAILY_FULL_ENERGY: process.env.APPLY_DAILY_FULL_ENERGY 22 | ? process.env.APPLY_DAILY_FULL_ENERGY.toLowerCase() === "true" 23 | : true, 24 | 25 | AUTO_CLAIM_REWARD: process.env.AUTO_CLAIM_REWARD 26 | ? process.env.AUTO_CLAIM_REWARD.toLowerCase() === "true" 27 | : true, 28 | 29 | AUTO_COMPLETE_TASKS: process.env.AUTO_COMPLETE_TASKS 30 | ? process.env.AUTO_COMPLETE_TASKS.toLowerCase() === "true" 31 | : true, 32 | 33 | AUTO_UPGRADE_TAP: process.env.AUTO_UPGRADE_TAP 34 | ? process.env.AUTO_UPGRADE_TAP.toLowerCase() === "true" 35 | : true, 36 | 37 | AUTO_CLAIM_EASTER_EGG: process.env.AUTO_CLAIM_EASTER_EGG 38 | ? process.env.AUTO_CLAIM_EASTER_EGG.toLowerCase() === "true" 39 | : true, 40 | 41 | MAX_TAP_LEVEL: process.env.MAX_TAP_LEVEL 42 | ? parseInt(process.env.MAX_TAP_LEVEL) 43 | : 10, 44 | 45 | AUTO_UPGRADE_CARD: process.env.AUTO_UPGRADE_CARD 46 | ? process.env.AUTO_UPGRADE_CARD.toLowerCase() === "true" 47 | : true, 48 | 49 | MAX_CARD_LEVEL: process.env.MAX_CARD_LEVEL 50 | ? parseInt(process.env.MAX_CARD_LEVEL) 51 | : 10, 52 | 53 | MAX_CARD_PRICE: process.env.MAX_CARD_PRICE 54 | ? parseInt(process.env.MAX_CARD_PRICE) 55 | : 100000000000000, 56 | 57 | AUTO_HOURLY_LIMIT: process.env.AUTO_HOURLY_LIMIT 58 | ? process.env.AUTO_HOURLY_LIMIT.toLowerCase() === "true" 59 | : true, 60 | 61 | MAX_HOURLY_LIMIT_LEVEL: process.env.MAX_HOURLY_LIMIT_LEVEL 62 | ? parseInt(process.env.MAX_HOURLY_LIMIT_LEVEL) 63 | : 10, 64 | 65 | SLEEP_EMPTY_ENERGY: process.env.SLEEP_EMPTY_ENERGY 66 | ? parseInt(process.env.SLEEP_EMPTY_ENERGY) 67 | : 70, 68 | 69 | AUTO_UPGRADE_ENERGY_LIMIT: process.env.AUTO_UPGRADE_ENERGY_LIMIT 70 | ? process.env.AUTO_UPGRADE_ENERGY_LIMIT.toLowerCase() === "true" 71 | : true, 72 | 73 | RANDOM_TAPS_COUNT: 74 | process.env.RANDOM_TAPS_COUNT && _isArray(process.env.RANDOM_TAPS_COUNT) 75 | ? JSON.parse(process.env.RANDOM_TAPS_COUNT) 76 | : [300, 600], 77 | 78 | SLEEP_BETWEEN_TAP: 79 | process.env.SLEEP_BETWEEN_TAP && _isArray(process.env.SLEEP_BETWEEN_TAP) 80 | ? JSON.parse(process.env.SLEEP_BETWEEN_TAP) 81 | : process.env.SLEEP_BETWEEN_TAP && 82 | /^\d+$/.test(process.env.SLEEP_BETWEEN_TAP) 83 | ? parseInt(process.env.SLEEP_BETWEEN_TAP) 84 | : 150, 85 | 86 | MAX_ENERGY_LIMIT_LEVEL: process.env.MAX_ENERGY_LIMIT_LEVEL 87 | ? parseInt(process.env.MAX_ENERGY_LIMIT_LEVEL) 88 | : 10, 89 | 90 | USE_PROXY_FROM_FILE: process.env.USE_PROXY_FROM_FILE 91 | ? process.env.USE_PROXY_FROM_FILE.toLowerCase() === "true" 92 | : false, 93 | 94 | USE_QUERY_ID: process.env.USE_QUERY_ID 95 | ? process.env.USE_QUERY_ID.toLowerCase() === "true" 96 | : false, 97 | 98 | MIN_AVAILABLE_ENERGY: process.env.MIN_AVAILABLE_ENERGY 99 | ? parseInt(process.env.MIN_AVAILABLE_ENERGY) 100 | : 100, 101 | }; 102 | 103 | module.exports = settings; 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [](https://t.me/roddyfred) 2 | 3 | ![img1](./.github/image/hero.png) 4 | 5 | # Use Node.Js 18 or greater 6 | 7 | ## Functionality 8 | 9 | | Functional | Supported | 10 | | ------------------------------------- | :-------: | 11 | | Claiming of daily combo | ✅ | 12 | | Claiming of daily enigma | ✅ | 13 | | Claiming of daily easter eggs | ✅ | 14 | | Claiming daily rewards | ✅ | 15 | | Completing tasks | ✅ | 16 | | Applying boosts | ✅ | 17 | | Upgrading taps | ✅ | 18 | | Upgrading hourly limit | ✅ | 19 | | Upgrading energy limit | ✅ | 20 | | Upgrading cards limit | ✅ | 21 | | Tapping | ✅ | 22 | | Data caching | ✅ | 23 | | Multithreading | ✅ | 24 | | Use sessions/query_ids | ✅ | 25 | | Binding a proxy to a session/query_id | ✅ | 26 | | Random sleep time between clicks | ✅ | 27 | | Random number of taps | ✅ | 28 | 29 | ## [How to add query id](https://github.com/Freddywhest/RockyRabbitBot/blob/main/AddQueryId.md) 30 | 31 | ## [Settings](https://github.com/FreddyWhest/RockyRabbitBot/blob/main/.env-example) 32 | 33 | | Settings | Description | 34 | | ----------------------------- | ------------------------------------------------------------------------- | 35 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session (stock - Android) | 36 | | **AUTO_PLAY_ENIGMA** | Whether to apply daily enigma (True / False) | 37 | | **AUTO_PLAY_COMBO** | Whether to apply daily combo (True / False) | 38 | | **AUTO_COMPLETE_TASKS** | Whether to complete tasks (True / False) | 39 | | **AUTO_UPGRADE_CARD** | Whether to upgrade cards to increase the passive earn (True / False) | 40 | | **MAX_CARD_LEVEL** | Maximum cards level (eg 20) | 41 | | **MAX_CARD_PRICE** | Maximum cards upgrade price (eg 50000000) | 42 | | **AUTO_UPGRADE_TAP** | Whether to upgrade taps (True / False) | 43 | | **MAX_TAP_LEVEL** | Maximum tap level (eg 20) | 44 | | **AUTO_HOURLY_LIMIT** | Whether to upgrade hourly limit (True / False) | 45 | | **MAX_HOURLY_LIMIT_LEVEL** | Maximum hourly limit level | 46 | | **AUTO_UPGRADE_ENERGY_LIMIT** | Whether to upgrade energy limit (True / False) | 47 | | **MAX_ENERGY_LIMIT_LEVEL** | Maximum energy limit level (eg 20) | 48 | | **APPLY_DAILY_FULL_ENERGY** | Whether to apply daily full energy (True / False) | 49 | | **AUTO_CLAIM_REWARD** | Whether to claim the daily rewards (True / False) | 50 | | **AUTO_CLAIM_EASTER_EGG** | Whether to claim the easter eggs (True / False) | 51 | | **USE_QUERY_ID** | Whether to use query ids instead of sessions (True / False) | 52 | | **RANDOM_TAPS_COUNT** | Random number of taps (eg [100,200]) | 53 | | **SLEEP_BETWEEN_TAP** | Random delay between taps in seconds (eg [50,60]) | 54 | | **SLEEP_EMPTY_ENERGY** | Delay when energy is empty (eg 70) | 55 | | **USE_PROXY_FROM_FILE** | Whether to use proxy from the `bot/config/proxies.js` file (True / False) | 56 | 57 | ## Installation 58 | 59 | You can download [**Repository**](https://github.com/FreddyWhest/RockyRabbitBot) by cloning it to your system and installing the necessary dependencies: 60 | 61 | ```shell 62 | ~ >>> git clone https://github.com/FreddyWhest/RockyRabbitBot.git 63 | ~ >>> cd RockyRabbitBot 64 | 65 | #Linux and MocOS 66 | ~/RockyRabbitBot >>> chmod +x check_node.sh 67 | ~/RockyRabbitBot >>> ./check_node.sh 68 | 69 | OR 70 | 71 | ~/RockyRabbitBot >>> npm install 72 | ~/RockyRabbitBot >>> cp .env-example .env 73 | ~/RockyRabbitBot >>> nano .env # Here you must specify your API_ID and API_HASH , the rest is taken by default 74 | ~/RockyRabbitBot >>> node index.js 75 | 76 | #Windows 77 | 1. Double click on INSTALL.bat in RockyRabbitBot directory to install the dependencies 78 | 2. Double click on START.bat in RockyRabbitBot directory to start the bot 79 | 80 | OR 81 | 82 | ~/RockyRabbitBot >>> npm install 83 | ~/RockyRabbitBot >>> cp .env-example .env 84 | ~/RockyRabbitBot >>> # Specify your API_ID and API_HASH, the rest is taken by default 85 | ~/RockyRabbitBot >>> node index.js 86 | ``` 87 | 88 | Also for quick launch you can use arguments, for example: 89 | 90 | ```shell 91 | ~/RockyRabbitBot >>> node index.js --action=1 92 | 93 | OR 94 | 95 | ~/RockyRabbitBot >>> node index.js --action=2 96 | 97 | #1 - Create session 98 | #2 - Run clicker 99 | ``` 100 | -------------------------------------------------------------------------------- /bot/utils/logger.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | 3 | class Logger { 4 | constructor() { 5 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 6 | this.GREEN = "\u001b[32m"; 7 | this.RED = "\u001b[31m"; 8 | this.YELLOW = "\u001b[33m"; 9 | this.BLUE = "\u001b[34m"; 10 | this.VOILET = "\u001b[35m"; 11 | this.LIGHT_BLUE = "\u001b[36m"; 12 | this.WHITE = "\u001b[37m"; 13 | this.PINK = "\u001b[38;5;201m"; 14 | this.LAVENDER = "\u001b[38;5;147m"; 15 | 16 | //Background colors 17 | this.BG_WHITE_CYAN = "\u001b[37;46m"; 18 | this.BG_RED = "\u001b[37;41m"; 19 | this.BG_GREEN = "\u001b[37;42m"; 20 | this.BG_YELLOW = "\u001b[37;43m"; 21 | this.BG_BLUE = "\u001b[37;44m"; 22 | this.BG_LIGHT_BLUE = "\u001b[37;45m"; 23 | this.BG_WHITE = "\u001b[47;45m"; 24 | 25 | this.RESET = "\u001b[0m"; 26 | this.BOLD = "\u001b[1m"; 27 | this.ITALICIZE = "\u001b[3m"; 28 | this.UNDERLINE = "\u001b[4m"; 29 | } 30 | 31 | #convertHtmlElementToAnsiColor(message) { 32 | if (!message) { 33 | return message; 34 | } 35 | 36 | return ( 37 | message 38 | // Text colors 39 | .replace(//g, this.BLUE) 40 | .replace(/<\/bl>/g, this.RESET) 41 | .replace(//g, this.RED) 42 | .replace(/<\/re>/g, this.RESET) 43 | .replace(//g, this.GREEN) 44 | .replace(/<\/gr>/g, this.RESET) 45 | .replace(//g, this.YELLOW) 46 | .replace(/<\/ye>/g, this.RESET) 47 | .replace(//g, this.PINK) 48 | .replace(/<\/pi>/g, this.RESET) 49 | .replace(//g, this.WHITE) 50 | .replace(/<\/wh>/g, this.RESET) 51 | .replace(//g, this.VOILET) 52 | .replace(/<\/vo>/g, this.RESET) 53 | .replace(//g, this.LAVENDER) 54 | .replace(/<\/la>/g, this.RESET) 55 | .replace(//g, this.LIGHT_BLUE) 56 | .replace(/<\/lb>/g, this.RESET) 57 | 58 | // Text styles 59 | .replace(//g, this.BOLD) 60 | .replace(/<\/b>/g, this.RESET) 61 | .replace(//g, this.ITALICIZE) 62 | .replace(/<\/i>/g, this.RESET) 63 | .replace(//g, this.UNDERLINE) 64 | .replace(/<\/u>/g, this.RESET) 65 | 66 | // Background colors 67 | .replace(//g, this.BG_WHITE_CYAN) 68 | .replace(/<\/wcb>/g, this.RESET) 69 | .replace(//g, this.BG_RED) 70 | .replace(/<\/reb>/g, this.RESET) 71 | .replace(//g, this.BG_GREEN) 72 | .replace(/<\/grb>/g, this.RESET) 73 | .replace(//g, this.BG_YELLOW) 74 | .replace(/<\/yeb>/g, this.RESET) 75 | .replace(//g, this.BG_BLUE) 76 | .replace(/<\/blb>/g, this.RESET) 77 | .replace(//g, this.BG_LIGHT_BLUE) 78 | .replace(/<\/lbb>/g, this.RESET) 79 | .replace(//g, this.BG_WHITE) 80 | .replace(/<\/whb>/g, this.RESET) 81 | 82 | // HTML tags 83 | .replace(/
/g, "\n") 84 | .replace(/
/g, "\n") 85 | ); 86 | } 87 | 88 | info(message) { 89 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 90 | console.log( 91 | this.#convertHtmlElementToAnsiColor( 92 | `${this.prefix} | INFO | ${message}` 93 | ) 94 | ); 95 | } 96 | 97 | warning(message) { 98 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 99 | console.log( 100 | this.#convertHtmlElementToAnsiColor( 101 | `${this.prefix} | WARN | ${message}` 102 | ) 103 | ); 104 | } 105 | 106 | error(message) { 107 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 108 | console.log( 109 | this.#convertHtmlElementToAnsiColor( 110 | `${this.prefix} | ERROR | ${message}` 111 | ) 112 | ); 113 | } 114 | 115 | debug(message) { 116 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 117 | console.log( 118 | this.#convertHtmlElementToAnsiColor( 119 | `${this.prefix} | DEBUG | ${message}` 120 | ) 121 | ); 122 | } 123 | 124 | success(message) { 125 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 126 | console.log( 127 | this.#convertHtmlElementToAnsiColor( 128 | `${this.prefix} | SUCCESS | ${message}` 129 | ) 130 | ); 131 | } 132 | 133 | #stripAnsiCodes(text) { 134 | const ansiRegex = /\x1b\[[0-9;]*m/g; 135 | return text.replace(ansiRegex, ""); 136 | } 137 | 138 | #addRoundedBorder(logText) { 139 | const lines = logText.split("\n"); 140 | 141 | const maxLength = lines.reduce( 142 | (max, line) => Math.max(max, this.#stripAnsiCodes(line).length), 143 | 0 144 | ); 145 | 146 | const topBorder = `${this.BLUE}╭${"─".repeat(maxLength + 2)}╮${this.RESET}`; 147 | const bottomBorder = `${this.BLUE}╰${"─".repeat(maxLength + 2)}╯${ 148 | this.RESET 149 | }`; 150 | console.log(topBorder); 151 | lines.forEach((line) => { 152 | const strippedLineLength = this.#stripAnsiCodes(line).length; 153 | console.log( 154 | `${this.BLUE}│${this.RESET} ${line}${" ".repeat( 155 | maxLength - strippedLineLength 156 | )} ${this.BLUE}│${this.RESET}` 157 | ); 158 | }); 159 | console.log(bottomBorder); 160 | } 161 | 162 | paragraph(message) { 163 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`; 164 | this.#addRoundedBorder( 165 | this.#convertHtmlElementToAnsiColor( 166 | `${this.prefix}
167 | ${message}` 168 | ) 169 | ); 170 | } 171 | } 172 | 173 | const logger = new Logger(); 174 | 175 | module.exports = logger; 176 | -------------------------------------------------------------------------------- /bot/utils/luncher.js: -------------------------------------------------------------------------------- 1 | const a0_0x111aea=a0_0x2aef;function a0_0x4f83(){const _0x38bb10=['showHelpAfterError','error','.session','readdirSync','USE_PROXY_FROM_FILE','endsWith','split','4212882DhCqIm','path','process','
\x20sessions\x20|\x20','cwd','sessions','48knDGjV','11930XvjnYm','all','Freddy\x20Bots','1404008hJQqYA','API_ID','2922vdihXz','exit','55LRkwgh','35NMLlxg','trim','choices','1.0.0','\x0aCreate\x20a\x20new\x20session\x20for\x20the\x20bot','Action\x20must\x20be\x201\x20or\x202','149242rFUcxP','35508492JiCCnF','iterator','map','apiId','100668mqqIDB','../config/app','run','14JCCWrk','../config/config','./TldLogger','ENOENT','apiHash','exports','parse','\x20proxies','../config/proxies','../core/tapper','Create\x20session','message','API_ID\x20and\x20API_HASH\x20must\x20be\x20provided.','sessionString','Error\x20in\x20task\x20for\x20tg_client:\x20','paragraph','readFileSync','addOption','telegram','Detected\x20','length','Action\x20type','\x0a╔═══╗\x20\x20\x20\x20\x20\x20\x20\x20╔╗\x20\x20\x20\x20\x20\x20\x20╔═══╗\x20\x20\x20\x20\x20╔╗\x20\x20╔╗\x20\x20\x20\x20\x20╔╗\x20╔══╗\x20\x20\x20\x20\x20\x20╔╗\x20\x0a║╔═╗║\x20\x20\x20\x20\x20\x20\x20\x20║║\x20\x20\x20\x20\x20\x20\x20║╔═╗║\x20\x20\x20\x20\x20║║\x20\x20║║\x20\x20\x20\x20╔╝╚╗║╔╗║\x20\x20\x20\x20\x20╔╝╚╗\x0a║╚═╝║╔══╗╔══╗║║╔╗╔╗\x20╔╗║╚═╝║╔══╗\x20║╚═╗║╚═╗╔╗╚╗╔╝║╚╝╚╗╔══╗╚╗╔╝\x0a║╔╗╔╝║╔╗║║╔═╝║╚╝╝║║\x20║║║╔╗╔╝╚\x20╗║\x20║╔╗║║╔╗║╠╣\x20║║\x20║╔═╗║║╔╗║\x20║║\x20\x0a║║║╚╗║╚╝║║╚═╗║╔╗╗║╚═╝║║║║╚╗║╚╝╚╗║╚╝║║╚╝║║║\x20║╚╗║╚═╝║║╚╝║\x20║╚╗\x0a╚╝╚═╝╚══╝╚══╝╚╝╚╝╚═╗╔╝╚╝╚═╝╚═══╝╚══╝╚══╝╚╝\x20╚═╝╚═══╝╚══╝\x20╚═╝\x0a©\x20Freddy\x20Bots\x20\x20\x20\x20╔═╝║\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20╚══╝\x20\x0a\x0a\x0a','utf8','value','opts','
\x20|\x20Invalid\x20session\x20data.\x20Create\x20a\x20new\x20one.','version','This\x20bot\x20has\x20been\x20compromised\x20and\x20is\x20no\x20longer\x20functioning.\x0aGo\x20to\x20https://github.com/FreddyWhest/RockyRabbitBot\x20to\x20download\x20the\x20latest\x20and\x20working\x20version.','log','\x20|\x20Session\x20is\x20empty\x20or\x20expired.\x20Create\x20a\x20new\x20one.','1017370YLkPqb','','@inquirer/prompts','join'];a0_0x4f83=function(){return _0x38bb10;};return a0_0x4f83();}(function(_0x21d6d1,_0x36ab41){const _0x557525=a0_0x2aef,_0xae02c1=_0x21d6d1();while(!![]){try{const _0x3496d9=parseInt(_0x557525(0x149))/0x1*(parseInt(_0x557525(0x141))/0x2)+-parseInt(_0x557525(0x146))/0x3*(parseInt(_0x557525(0x179))/0x4)+-parseInt(_0x557525(0x17a))/0x5*(parseInt(_0x557525(0x17f))/0x6)+parseInt(_0x557525(0x182))/0x7*(-parseInt(_0x557525(0x17d))/0x8)+-parseInt(_0x557525(0x173))/0x9+parseInt(_0x557525(0x168))/0xa*(-parseInt(_0x557525(0x181))/0xb)+parseInt(_0x557525(0x142))/0xc;if(_0x3496d9===_0x36ab41)break;else _0xae02c1['push'](_0xae02c1['shift']());}catch(_0xa60793){_0xae02c1['push'](_0xae02c1['shift']());}}}(a0_0x4f83,0x8ec59));const register=require('../core/register'),logger=require('./logger'),{select}=require(a0_0x111aea(0x16a)),fs=require('fs'),path=require(a0_0x111aea(0x174)),settings=require(a0_0x111aea(0x14a)),proxies=require(a0_0x111aea(0x151)),{program,Option}=require('commander'),{TelegramClient}=require(a0_0x111aea(0x15b)),Tapper=require(a0_0x111aea(0x152)),{StringSession}=require('telegram/sessions'),logger2=require(a0_0x111aea(0x14b)),app=require(a0_0x111aea(0x147));function a0_0x2aef(_0x49dfb3,_0x9a72c8){const _0x4f834c=a0_0x4f83();return a0_0x2aef=function(_0x2aefa1,_0xf4ad07){_0x2aefa1=_0x2aefa1-0x13d;let _0x87f253=_0x4f834c[_0x2aefa1];return _0x87f253;},a0_0x2aef(_0x49dfb3,_0x9a72c8);}class Luncher{#start_text;constructor(){const _0x366e4f=a0_0x111aea;this.#start_text=_0x366e4f(0x15f);}async #printStartText(){const _0x2794f9=a0_0x111aea;logger['info'](_0x2794f9(0x15c)+this.#get_sessions()[_0x2794f9(0x15d)]+_0x2794f9(0x176)+(this.#get_proxies()&&Array['isArray'](this.#get_proxies())?this.#get_proxies()[_0x2794f9(0x15d)]:0x0)+_0x2794f9(0x150)),logger[_0x2794f9(0x158)]('WARNING\x20\x0aen:\x20NOT\x20FOR\x20SALE\x0aru:\x20НЕ\x20ДЛЯ\x20ПРОДАЖИ\x0aes:\x20NO\x20VENTA\x0afr:\x20PAS\x20À\x20VENDRE\x0ait:\x20NON\x20PER\x20VENDITA\x0agh:\x20YƐN\x20TƆN\x0a\x0aFor\x20updates\x20and\x20more\x20bots\x20join\x20us:\x20\x0ahttps://t.me/freddy_bots\x0a\x0aBot:\x20'+app['botName']+'\x0aVersion:\x20'+app[_0x2794f9(0x164)]+'\x0a'),console[_0x2794f9(0x166)](this.#start_text);}async[a0_0x111aea(0x175)](){const _0x4ef318=a0_0x111aea;try{let _0x7448e3;program[_0x4ef318(0x15a)](new Option('--action\x20',_0x4ef318(0x15e))[_0x4ef318(0x13d)](['1','2']))[_0x4ef318(0x16c)](!![]),program['parse']();const _0x30115d=program[_0x4ef318(0x162)]();_0x7448e3=_0x30115d?parseInt(_0x30115d['action']):null;if(!_0x7448e3){this.#printStartText();let _0x39578f='';while(!![]){_0x39578f=await select({'message':'What\x20would\x20you\x20like\x20to\x20do:\x0a','choices':[{'name':_0x4ef318(0x153),'value':'1','description':_0x4ef318(0x13f)},{'name':'Run\x20bot','value':'2','description':'\x0aStart\x20the\x20bot'}]});if(!_0x39578f[_0x4ef318(0x183)]()['match'](/^[1-2]$/))logger['warning'](_0x4ef318(0x140));else break;}_0x7448e3=parseInt(_0x39578f[_0x4ef318(0x183)]());}if(_0x7448e3===0x1)register['start']();else{if(_0x7448e3===0x2){const _0x47f4bc=await this.#get_tg_clients();await this.#run_tasks(_0x47f4bc);}}}catch(_0x513a7f){if(_0x513a7f?.[_0x4ef318(0x154)]?.['includes'](_0x4ef318(0x14c)))return logger['error'](_0x4ef318(0x165));logger[_0x4ef318(0x16d)](_0x513a7f?.[_0x4ef318(0x154)]);}}async #get_tg_clients(){const _0x13443b=this.#get_sessions(),_0x24fdbe=_0x13443b['map'](_0x48cb7b=>{const _0x2bf394=a0_0x2aef;try{const _0x130025=fs[_0x2bf394(0x159)](path[_0x2bf394(0x16b)](process[_0x2bf394(0x177)](),_0x2bf394(0x178),_0x48cb7b+'.session'),_0x2bf394(0x160));if(!_0x130025){logger[_0x2bf394(0x16d)](_0x2bf394(0x169)+_0x48cb7b+_0x2bf394(0x167));return;}const _0x4f552d=JSON[_0x2bf394(0x14f)](_0x130025);(!settings[_0x2bf394(0x17e)]||!settings['API_HASH'])&&(logger[_0x2bf394(0x16d)](_0x2bf394(0x155)),process[_0x2bf394(0x180)](0x1));(!_0x4f552d['sessionString']||!_0x4f552d[_0x2bf394(0x145)]||!_0x4f552d[_0x2bf394(0x14d)])&&(logger['error'](''+_0x48cb7b+_0x2bf394(0x163)),process[_0x2bf394(0x180)](0x1));!/^\d+$/['test'](_0x4f552d[_0x2bf394(0x145)])&&(logger['error'](''+_0x48cb7b+_0x2bf394(0x163)),process[_0x2bf394(0x180)](0x1));const _0x279deb=new StringSession(_0x4f552d[_0x2bf394(0x156)]),_0x339cff=new TelegramClient(_0x279deb,_0x4f552d['apiId'],_0x4f552d[_0x2bf394(0x14d)],{'connectionRetries':0x5,'deviceModel':_0x2bf394(0x17c),'appVersion':_0x2bf394(0x13e),'systemVersion':'1.0.0','langCode':'en','baseLogger':logger2});return{'tg_client':_0x339cff,'session_name':_0x48cb7b};}catch(_0x273d8c){logger[_0x2bf394(0x16d)](_0x2bf394(0x169)+_0x48cb7b+'\x20|\x20Error:\x20'+_0x273d8c[_0x2bf394(0x154)]);}});return _0x24fdbe;}#get_sessions(){const _0x23768e=a0_0x111aea,_0x5116d9=path[_0x23768e(0x16b)](process[_0x23768e(0x177)](),_0x23768e(0x178));if(!fs['existsSync'](_0x5116d9))return[];const _0x203ad3=fs[_0x23768e(0x16f)](_0x5116d9)[_0x23768e(0x144)](_0x2221bf=>{const _0xe31501=_0x23768e,_0x388299=_0x2221bf[_0xe31501(0x171)](_0xe31501(0x16e))?_0x2221bf[_0xe31501(0x172)]('.')[0x0]:null;return _0x388299;});return _0x203ad3;}#get_proxies(){const _0x10493d=a0_0x111aea;if(!settings[_0x10493d(0x170)])return null;return proxies;}async #run_tasks(_0x2b74b7){const _0x2e047a=a0_0x111aea,_0x1242c2=this.#get_proxies();let _0x18a580=_0x1242c2?_0x1242c2[Symbol[_0x2e047a(0x143)]]():null;const _0xcbc6b9=_0x2b74b7[_0x2e047a(0x144)](async _0x42fbe5=>{const _0x38bee4=_0x2e047a,_0x271d9d=_0x18a580?_0x18a580['next']()[_0x38bee4(0x161)]:null;try{await new Tapper(_0x42fbe5)[_0x38bee4(0x148)](_0x271d9d);}catch(_0x1cded2){logger[_0x38bee4(0x16d)](_0x38bee4(0x157)+_0x1cded2['message']);}});await Promise[_0x2e047a(0x17b)](_0xcbc6b9);}}const luncher=new Luncher();module[a0_0x111aea(0x14e)]=luncher; -------------------------------------------------------------------------------- /bot/core/register.js: -------------------------------------------------------------------------------- 1 | const { TelegramClient, sessions } = require("telegram"); 2 | const { StringSession } = require("telegram/sessions"); 3 | const fs = require("fs"); 4 | const { input } = require("@inquirer/prompts"); 5 | const logger = require("../utils/logger"); 6 | const settings = require("../config/config"); 7 | require("dotenv").config(); 8 | const path = require("path"); 9 | const logger2 = require("../utils/TldLogger"); 10 | const devices = require("../utils/devices"); 11 | const { select } = require("@inquirer/prompts"); 12 | var qrcode = require("qrcode-terminal"); 13 | const readline = require("readline"); 14 | const os = require("os"); 15 | const { version } = require("../../package.json"); 16 | 17 | class Register { 18 | #stringSession; 19 | #apiId; 20 | #apiHash; 21 | constructor() { 22 | this.#apiId = settings.API_ID; 23 | this.#apiHash = settings.API_HASH; 24 | this.#stringSession = new StringSession(""); 25 | } 26 | 27 | async #getSessionName() { 28 | const filePath = path.join(process.cwd(), "sessions"); 29 | let sessionsName = await input({ 30 | message: "Please enter your session name: ", 31 | }); 32 | do { 33 | if (fs.existsSync(`${filePath}/${sessionsName}.session`)) { 34 | logger.warning(`Session name ${sessionsName} already exists!`); 35 | sessionsName = await input({ 36 | message: "Please enter a different session name: ", 37 | }); 38 | } 39 | } while (fs.existsSync(`${filePath}/${sessionsName}.session`)); 40 | return sessionsName; 41 | } 42 | 43 | #load_simulate_device() { 44 | try { 45 | const filePath = path.join(process.cwd(), "simulate_device.json"); 46 | const data = fs.readFileSync(filePath, "utf8"); 47 | return JSON.parse(data); 48 | } catch (error) { 49 | if (error.code === "ENOENT") { 50 | return {}; 51 | } else { 52 | throw error; 53 | } 54 | } 55 | } 56 | 57 | #get_random_simulate_device() { 58 | const randomIndex = Math.floor(Math.random() * devices.length); 59 | return devices[randomIndex]; 60 | } 61 | 62 | #get_simulate_device() { 63 | const simulate_device = this.#load_simulate_device(); 64 | const requiredKeys = ["manufacturer", "model", "cpu", "type", "os"]; 65 | const containsKeys = requiredKeys.every((key) => key in simulate_device); 66 | if (containsKeys) { 67 | return simulate_device; 68 | } 69 | logger.info("Simulate device not found. Generating one..."); 70 | const random_device = this.#get_random_simulate_device(); 71 | this.#save_simulate_device(random_device); 72 | return random_device; 73 | } 74 | 75 | #save_simulate_device(simulate_device) { 76 | const filePath = path.join(process.cwd(), "simulate_device.json"); 77 | fs.writeFileSync(filePath, JSON.stringify(simulate_device, null, 2)); 78 | } 79 | 80 | #client() { 81 | const client_options = { 82 | connectionRetries: 5, 83 | deviceModel: os.type(), 84 | appVersion: "1.0.0", 85 | systemVersion: "1.0.0", 86 | langCode: "en", 87 | baseLogger: logger2, 88 | }; 89 | 90 | const client = new TelegramClient( 91 | this.#stringSession, 92 | this.#apiId, 93 | this.#apiHash, 94 | client_options 95 | ); 96 | 97 | return client; 98 | } 99 | 100 | async #sign_in_with_phone(client) { 101 | await client.start({ 102 | phoneNumber: async () => 103 | await input({ 104 | message: "Please enter your number: ", 105 | }), 106 | password: async () => 107 | await input({ 108 | message: "Please enter your password: ", 109 | }), 110 | phoneCode: async () => 111 | await input({ 112 | message: "Please enter the code you received: ", 113 | }), 114 | onError: (err) => console.error(err), 115 | }); 116 | } 117 | 118 | async #sign_in_with_qr(client) { 119 | let qrCodeLines = 0; 120 | let message = ""; 121 | await client.connect(); 122 | let isShown = false; 123 | await client.signInUserWithQrCode( 124 | { apiId: this.#apiId, apiHash: this.#apiHash }, 125 | { 126 | onError: (err) => console.error(err), 127 | qrCode: async (code) => { 128 | if (!isShown) { 129 | console.log( 130 | "\nScan QR code below with your telegram app to login: \n" 131 | ); 132 | qrcode.generate( 133 | `tg://login?token=${code.token.toString("base64url")}`, 134 | { small: true }, 135 | (qrcodeString) => { 136 | qrCodeLines = qrcodeString.split("\n").length; // Count the lines in the QR code 137 | console.log(qrcodeString); 138 | } 139 | ); 140 | isShown = true; 141 | } else { 142 | if (message) { 143 | qrCodeLines = qrCodeLines + 2; 144 | } 145 | readline.moveCursor(process.stdout, 0, -qrCodeLines); // Adjust -6 based on the number of lines your QR code takes 146 | readline.clearScreenDown(process.stdout); // Clear everything below the cursor 147 | message = "\nNew qr code received\n"; 148 | console.log(message); 149 | qrcode.generate( 150 | `tg://login?token=${code.token.toString("base64url")}`, 151 | { small: true }, 152 | (qrcodeString) => { 153 | qrCodeLines = qrcodeString.split("\n").length + 2; // Count the lines in the QR code 154 | console.log(qrcodeString); 155 | } 156 | ); 157 | } 158 | }, 159 | password: async () => 160 | await input({ 161 | message: "Please enter your password: ", 162 | }), 163 | } 164 | ); 165 | } 166 | 167 | async start() { 168 | const filePath = path.join(process.cwd(), "sessions"); 169 | if (!this.#apiId || !this.#apiHash) { 170 | logger.error("API_ID and API_HASH must be provided."); 171 | process.exit(1); 172 | } 173 | 174 | if (typeof this.#apiHash !== "string" || typeof this.#apiId !== "number") { 175 | logger.error( 176 | "API_ID and API_HASH must be numbers and strings respectively." 177 | ); 178 | process.exit(1); 179 | } 180 | 181 | const simulate_device = this.#get_simulate_device(); 182 | 183 | const sessionsName = await this.#getSessionName(); 184 | 185 | // Here we are creating a new session 186 | 187 | let userInput = ""; 188 | 189 | while (true) { 190 | userInput = await select({ 191 | message: "How do you want to create a new session:\n", 192 | choices: [ 193 | { 194 | name: "With QR code", 195 | value: "1", 196 | description: "\nCreate a new session with QR code", 197 | }, 198 | { 199 | name: "With phone number", 200 | value: "2", 201 | description: "\nCreate a new session with phone number", 202 | }, 203 | ], 204 | }); 205 | 206 | if (!userInput.trim().match(/^[1-2]$/)) { 207 | logger.warning("Action must be 1 or 2"); 208 | } else { 209 | break; 210 | } 211 | } 212 | 213 | const action = parseInt(userInput.trim()); 214 | 215 | if (action === 1) { 216 | await this.#sign_in_with_qr(this.#client()); 217 | } else if (action === 2) { 218 | await this.#sign_in_with_phone(this.#client()); 219 | } 220 | 221 | if (!fs.existsSync(filePath)) { 222 | fs.mkdirSync(filePath); 223 | } 224 | 225 | const sessionData = { 226 | apiId: this.#apiId, 227 | apiHash: this.#apiHash, 228 | sessionString: this.#stringSession.save(), 229 | }; 230 | 231 | fs.writeFileSync( 232 | `${filePath}/${sessionsName}.session`, 233 | JSON.stringify(sessionData, null, 2) 234 | ); 235 | 236 | logger.paragraph( 237 | `Session saved as ${sessionsName}.session
238 | Session device info:
239 | OS: ${os.type() || "N/A"} 240 | ` 241 | ); 242 | 243 | this.#client().disconnect(); 244 | process.exit(0); 245 | } 246 | } 247 | 248 | const register = new Register(); 249 | module.exports = register; 250 | -------------------------------------------------------------------------------- /bot/utils/devices.js: -------------------------------------------------------------------------------- 1 | const devices = [ 2 | { 3 | manufacturer: "Apple", 4 | model: "iPhone 14 Pro", 5 | cpu: "A16 Bionic", 6 | type: "iPhone", 7 | os: "iOS 16", 8 | }, 9 | { 10 | manufacturer: "Apple", 11 | model: "iPhone 13", 12 | cpu: "A15 Bionic", 13 | type: "iPhone", 14 | os: "iOS 15", 15 | }, 16 | { 17 | manufacturer: "Apple", 18 | model: "iPhone SE (2022)", 19 | cpu: "A15 Bionic", 20 | type: "iPhone", 21 | os: "iOS 15", 22 | }, 23 | { 24 | manufacturer: "Apple", 25 | model: "iPad Pro 2021", 26 | cpu: "M1", 27 | type: "iPad", 28 | os: "iPadOS 15", 29 | }, 30 | { 31 | manufacturer: "Apple", 32 | model: 'MacBook Pro 16" 2021', 33 | cpu: "M1 Pro", 34 | type: "Laptop", 35 | os: "macOS Monterey", 36 | }, 37 | { 38 | manufacturer: "Apple", 39 | model: "MacBook Air M2", 40 | cpu: "M2", 41 | type: "Laptop", 42 | os: "macOS Ventura", 43 | }, 44 | { 45 | manufacturer: "Samsung", 46 | model: "Galaxy S21 Ultra", 47 | cpu: "Exynos 2100", 48 | type: "Android", 49 | os: "Android 11", 50 | }, 51 | { 52 | manufacturer: "Samsung", 53 | model: "Galaxy Note 20", 54 | cpu: "Exynos 990", 55 | type: "Android", 56 | os: "Android 10", 57 | }, 58 | { 59 | manufacturer: "Samsung", 60 | model: "Galaxy A52", 61 | cpu: "Qualcomm Snapdragon 720G", 62 | type: "Android", 63 | os: "Android 11", 64 | }, 65 | { 66 | manufacturer: "Samsung", 67 | model: "Galaxy Tab S7", 68 | cpu: "Qualcomm Snapdragon 865+", 69 | type: "Android Tablet", 70 | os: "Android 10", 71 | }, 72 | { 73 | manufacturer: "Samsung", 74 | model: "Galaxy Z Fold 3", 75 | cpu: "Qualcomm Snapdragon 888", 76 | type: "Android Foldable", 77 | os: "Android 11", 78 | }, 79 | { 80 | manufacturer: "Google", 81 | model: "Pixel 6", 82 | cpu: "Google Tensor", 83 | type: "Android", 84 | os: "Android 12", 85 | }, 86 | { 87 | manufacturer: "Google", 88 | model: "Pixel 5a", 89 | cpu: "Qualcomm Snapdragon 765G", 90 | type: "Android", 91 | os: "Android 11", 92 | }, 93 | { 94 | manufacturer: "Google", 95 | model: "Pixel 4a", 96 | cpu: "Qualcomm Snapdragon 730G", 97 | type: "Android", 98 | os: "Android 11", 99 | }, 100 | { 101 | manufacturer: "Microsoft", 102 | model: "Surface Laptop 4", 103 | cpu: "Intel Core i7-1185G7", 104 | type: "Laptop", 105 | os: "Windows 10", 106 | }, 107 | { 108 | manufacturer: "Microsoft", 109 | model: "Surface Book 3", 110 | cpu: "Intel Core i7-1065G7", 111 | type: "Laptop", 112 | os: "Windows 10", 113 | }, 114 | { 115 | manufacturer: "Dell", 116 | model: "XPS 13", 117 | cpu: "Intel Core i7-1185G7", 118 | type: "Laptop", 119 | os: "Windows 10", 120 | }, 121 | { 122 | manufacturer: "Dell", 123 | model: "Inspiron 15 7000", 124 | cpu: "Intel Core i5-1035G1", 125 | type: "Laptop", 126 | os: "Windows 10", 127 | }, 128 | { 129 | manufacturer: "HP", 130 | model: "Spectre x360 14", 131 | cpu: "Intel Core i7-1165G7", 132 | type: "Laptop", 133 | os: "Windows 10", 134 | }, 135 | { 136 | manufacturer: "HP", 137 | model: "Envy 13", 138 | cpu: "Intel Core i5-1135G7", 139 | type: "Laptop", 140 | os: "Windows 10", 141 | }, 142 | { 143 | manufacturer: "Lenovo", 144 | model: "ThinkPad X1 Carbon", 145 | cpu: "Intel Core i7-1165G7", 146 | type: "Laptop", 147 | os: "Windows 10", 148 | }, 149 | { 150 | manufacturer: "Lenovo", 151 | model: "Yoga 9i", 152 | cpu: "Intel Core i7-1185G7", 153 | type: "Laptop", 154 | os: "Windows 10", 155 | }, 156 | { 157 | manufacturer: "Asus", 158 | model: "ROG Strix Scar 15", 159 | cpu: "AMD Ryzen 9 5900HX", 160 | type: "Laptop", 161 | os: "Windows 10", 162 | }, 163 | { 164 | manufacturer: "Asus", 165 | model: "ZenBook 14", 166 | cpu: "Intel Core i7-1165G7", 167 | type: "Laptop", 168 | os: "Windows 10", 169 | }, 170 | { 171 | manufacturer: "Acer", 172 | model: "Predator Helios 300", 173 | cpu: "Intel Core i7-10750H", 174 | type: "Laptop", 175 | os: "Windows 10", 176 | }, 177 | { 178 | manufacturer: "Acer", 179 | model: "Swift 3", 180 | cpu: "AMD Ryzen 7 4700U", 181 | type: "Laptop", 182 | os: "Windows 10", 183 | }, 184 | { 185 | manufacturer: "Sony", 186 | model: "VAIO SX14", 187 | cpu: "Intel Core i7-1165G7", 188 | type: "Laptop", 189 | os: "Windows 10", 190 | }, 191 | { 192 | manufacturer: "Razer", 193 | model: "Blade 15 Advanced", 194 | cpu: "Intel Core i7-10875H", 195 | type: "Laptop", 196 | os: "Windows 10", 197 | }, 198 | { 199 | manufacturer: "Huawei", 200 | model: "MateBook X Pro", 201 | cpu: "Intel Core i5-10210U", 202 | type: "Laptop", 203 | os: "Windows 10", 204 | }, 205 | { 206 | manufacturer: "Huawei", 207 | model: "MateBook 14", 208 | cpu: "AMD Ryzen 5 4600U", 209 | type: "Laptop", 210 | os: "Windows 10", 211 | }, 212 | { 213 | manufacturer: "Xiaomi", 214 | model: "Mi 11 Ultra", 215 | cpu: "Qualcomm Snapdragon 888", 216 | type: "Android", 217 | os: "Android 11", 218 | }, 219 | { 220 | manufacturer: "Xiaomi", 221 | model: "Redmi Note 11", 222 | cpu: "Qualcomm Snapdragon 680", 223 | type: "Android", 224 | os: "Android 11", 225 | }, 226 | { 227 | manufacturer: "OnePlus", 228 | model: "OnePlus 9 Pro", 229 | cpu: "Qualcomm Snapdragon 888", 230 | type: "Android", 231 | os: "Android 11", 232 | }, 233 | { 234 | manufacturer: "OnePlus", 235 | model: "OnePlus Nord", 236 | cpu: "Qualcomm Snapdragon 765G", 237 | type: "Android", 238 | os: "Android 11", 239 | }, 240 | { 241 | manufacturer: "LG", 242 | model: "Gram 17", 243 | cpu: "Intel Core i7-1165G7", 244 | type: "Laptop", 245 | os: "Windows 10", 246 | }, 247 | { 248 | manufacturer: "LG", 249 | model: "V60 ThinQ", 250 | cpu: "Qualcomm Snapdragon 865", 251 | type: "Android", 252 | os: "Android 10", 253 | }, 254 | { 255 | manufacturer: "Motorola", 256 | model: "Moto G Power", 257 | cpu: "Qualcomm Snapdragon 662", 258 | type: "Android", 259 | os: "Android 10", 260 | }, 261 | { 262 | manufacturer: "Motorola", 263 | model: "Moto Edge 2021", 264 | cpu: "Qualcomm Snapdragon 778G", 265 | type: "Android", 266 | os: "Android 11", 267 | }, 268 | { 269 | manufacturer: "Nokia", 270 | model: "Nokia 8.3 5G", 271 | cpu: "Qualcomm Snapdragon 765G", 272 | type: "Android", 273 | os: "Android 10", 274 | }, 275 | { 276 | manufacturer: "Nokia", 277 | model: "Nokia 7.2", 278 | cpu: "Qualcomm Snapdragon 660", 279 | type: "Android", 280 | os: "Android 10", 281 | }, 282 | { 283 | manufacturer: "Dell", 284 | model: "G5 15", 285 | cpu: "Intel Core i7-10750H", 286 | type: "Laptop", 287 | os: "Windows 10", 288 | }, 289 | { 290 | manufacturer: "HP", 291 | model: "Pavilion 15", 292 | cpu: "AMD Ryzen 5 5500U", 293 | type: "Laptop", 294 | os: "Windows 10", 295 | }, 296 | { 297 | manufacturer: "Lenovo", 298 | model: "ThinkPad T14", 299 | cpu: "Intel Core i7-10610U", 300 | type: "Laptop", 301 | os: "Windows 10", 302 | }, 303 | { 304 | manufacturer: "Asus", 305 | model: "TUF Gaming A15", 306 | cpu: "AMD Ryzen 7 4800H", 307 | type: "Laptop", 308 | os: "Windows 10", 309 | }, 310 | { 311 | manufacturer: "Acer", 312 | model: "Nitro 5", 313 | cpu: "Intel Core i5-9300H", 314 | type: "Laptop", 315 | os: "Windows 10", 316 | }, 317 | { 318 | manufacturer: "Razer", 319 | model: "Blade Stealth 13", 320 | cpu: "Intel Core i7-1165G7", 321 | type: "Laptop", 322 | os: "Windows 10", 323 | }, 324 | { 325 | manufacturer: "Sony", 326 | model: "VAIO SX12", 327 | cpu: "Intel Core i7-1065G7", 328 | type: "Laptop", 329 | os: "Windows 10", 330 | }, 331 | { 332 | manufacturer: "Huawei", 333 | model: "MateBook D 15", 334 | cpu: "AMD Ryzen 5 3500U", 335 | type: "Laptop", 336 | os: "Windows 10", 337 | }, 338 | { 339 | manufacturer: "Xiaomi", 340 | model: "Mi Mix 4", 341 | cpu: "Qualcomm Snapdragon 888", 342 | type: "Android", 343 | os: "Android 11", 344 | }, 345 | { 346 | manufacturer: "Google", 347 | model: "Pixel 6 Pro", 348 | cpu: "Google Tensor", 349 | type: "Android", 350 | os: "Android 12", 351 | }, 352 | { 353 | manufacturer: "Google", 354 | model: "Pixel 5", 355 | cpu: "Qualcomm Snapdragon 765G", 356 | type: "Android", 357 | os: "Android 11", 358 | }, 359 | { 360 | manufacturer: "Apple", 361 | model: "iPad Air (2022)", 362 | cpu: "M1", 363 | type: "iPad", 364 | os: "iPadOS 15", 365 | }, 366 | { 367 | manufacturer: "Apple", 368 | model: "iPhone 11", 369 | cpu: "A13 Bionic", 370 | type: "iPhone", 371 | os: "iOS 14", 372 | }, 373 | { 374 | manufacturer: "Samsung", 375 | model: "Galaxy A72", 376 | cpu: "Qualcomm Snapdragon 720G", 377 | type: "Android", 378 | os: "Android 11", 379 | }, 380 | { 381 | manufacturer: "Samsung", 382 | model: "Galaxy S20 FE", 383 | cpu: "Exynos 990", 384 | type: "Android", 385 | os: "Android 11", 386 | }, 387 | { 388 | manufacturer: "Huawei", 389 | model: "P40 Pro", 390 | cpu: "Kirin 990", 391 | type: "Android", 392 | os: "Android 10", 393 | }, 394 | { 395 | manufacturer: "Xiaomi", 396 | model: "Redmi Note 10 Pro", 397 | cpu: "Qualcomm Snapdragon 732G", 398 | type: "Android", 399 | os: "Android 11", 400 | }, 401 | { 402 | manufacturer: "Asus", 403 | model: "ROG Phone 5", 404 | cpu: "Qualcomm Snapdragon 888", 405 | type: "Android", 406 | os: "Android 11", 407 | }, 408 | { 409 | manufacturer: "Dell", 410 | model: "XPS 17", 411 | cpu: "Intel Core i9-11980HK", 412 | type: "Laptop", 413 | os: "Windows 10", 414 | }, 415 | { 416 | manufacturer: "HP", 417 | model: "Omen 15", 418 | cpu: "Intel Core i7-10750H", 419 | type: "Laptop", 420 | os: "Windows 10", 421 | }, 422 | { 423 | manufacturer: "Lenovo", 424 | model: "Legion 5 Pro", 425 | cpu: "AMD Ryzen 7 5800H", 426 | type: "Laptop", 427 | os: "Windows 10", 428 | }, 429 | { 430 | manufacturer: "Asus", 431 | model: "ZenBook Flip 14", 432 | cpu: "Intel Core i7-1165G7", 433 | type: "Laptop", 434 | os: "Windows 10", 435 | }, 436 | { 437 | manufacturer: "Acer", 438 | model: "Aspire 5", 439 | cpu: "Intel Core i5-1135G7", 440 | type: "Laptop", 441 | os: "Windows 10", 442 | }, 443 | { 444 | manufacturer: "Microsoft", 445 | model: "Surface Laptop Go", 446 | cpu: "Intel Core i5-1035G1", 447 | type: "Laptop", 448 | os: "Windows 10", 449 | }, 450 | { 451 | manufacturer: "Razer", 452 | model: "Blade 17", 453 | cpu: "Intel Core i9-11900H", 454 | type: "Laptop", 455 | os: "Windows 10", 456 | }, 457 | { 458 | manufacturer: "Sony", 459 | model: "VAIO SX14", 460 | cpu: "Intel Core i7-1065G7", 461 | type: "Laptop", 462 | os: "Windows 10", 463 | }, 464 | { 465 | manufacturer: "Huawei", 466 | model: "MateBook X Pro", 467 | cpu: "Intel Core i5-10210U", 468 | type: "Laptop", 469 | os: "Windows 10", 470 | }, 471 | { 472 | manufacturer: "Xiaomi", 473 | model: "Mi 10T Pro", 474 | cpu: "Qualcomm Snapdragon 865", 475 | type: "Android", 476 | os: "Android 10", 477 | }, 478 | { 479 | manufacturer: "OnePlus", 480 | model: "OnePlus 8T", 481 | cpu: "Qualcomm Snapdragon 865", 482 | type: "Android", 483 | os: "Android 11", 484 | }, 485 | { 486 | manufacturer: "Nokia", 487 | model: "Nokia 9 PureView", 488 | cpu: "Qualcomm Snapdragon 845", 489 | type: "Android", 490 | os: "Android 9", 491 | }, 492 | { 493 | manufacturer: "Motorola", 494 | model: "Moto G60", 495 | cpu: "Qualcomm Snapdragon 732G", 496 | type: "Android", 497 | os: "Android 11", 498 | }, 499 | { 500 | manufacturer: "LG", 501 | model: "Wing", 502 | cpu: "Qualcomm Snapdragon 765G", 503 | type: "Android", 504 | os: "Android 10", 505 | }, 506 | { 507 | manufacturer: "Google", 508 | model: "Pixel 4 XL", 509 | cpu: "Qualcomm Snapdragon 855", 510 | type: "Android", 511 | os: "Android 10", 512 | }, 513 | { 514 | manufacturer: "Apple", 515 | model: "iPhone XR", 516 | cpu: "A12 Bionic", 517 | type: "iPhone", 518 | os: "iOS 13", 519 | }, 520 | { 521 | manufacturer: "Apple", 522 | model: "iPhone X", 523 | cpu: "A11 Bionic", 524 | type: "iPhone", 525 | os: "iOS 12", 526 | }, 527 | ]; 528 | module.exports = devices; 529 | -------------------------------------------------------------------------------- /bot/config/userAgents.js: -------------------------------------------------------------------------------- 1 | const user_agents = [ 2 | //Samsung Galaxy S22 5G 3 | "Mozilla/5.0 (Linux; Android 13; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 4 | "Mozilla/5.0 (Linux; Android 13; SM-S901U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 5 | 6 | //Samsung Galaxy S22 Ultra 5G 7 | "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 8 | "Mozilla/5.0 (Linux; Android 13; SM-S908U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Mobile Safari/537.36", 9 | 10 | //Samsung Galaxy S21 5G 11 | "Mozilla/5.0 (Linux; Android 13; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 12 | "Mozilla/5.0 (Linux; Android 13; SM-G991U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 13 | 14 | //Samsung Galaxy S21 Ultra 5G 15 | "Mozilla/5.0 (Linux; Android 13; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 16 | "Mozilla/5.0 (Linux; Android 13; SM-G998U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 17 | 18 | //Samsung Galaxy A53 5G 19 | "Mozilla/5.0 (Linux; Android 13; SM-A536B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 20 | "Mozilla/5.0 (Linux; Android 13; SM-A536U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 21 | 22 | //Samsung Galaxy A51 23 | "Mozilla/5.0 (Linux; Android 13; SM-A515F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 24 | "Mozilla/5.0 (Linux; Android 13; SM-A515U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 25 | 26 | //Samsung Galaxy S10 27 | "Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 28 | "Mozilla/5.0 (Linux; Android 12; SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 29 | 30 | //Google Pixel 6 31 | "Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 32 | 33 | //Google Pixel 6a 34 | "Mozilla/5.0 (Linux; Android 13; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 35 | 36 | //Google Pixel 6 Pro 37 | "Mozilla/5.0 (Linux; Android 13; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 38 | 39 | //Google Pixel 7 40 | "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 41 | 42 | //Google Pixel 7 Pro 43 | "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 44 | 45 | //Motorola Moto G Pure 46 | "Mozilla/5.0 (Linux; Android 12; moto g pure) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 47 | 48 | //Motorola Moto G Stylus 5G 49 | "Mozilla/5.0 (Linux; Android 12; moto g stylus 5G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 50 | 51 | //Motorola Moto G Stylus 5G (2022) 52 | "Mozilla/5.0 (Linux; Android 12; moto g stylus 5G (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 53 | 54 | //Motorola Moto G 5G (2022) 55 | "Mozilla/5.0 (Linux; Android 12; moto g 5G (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 56 | 57 | //Motorola Moto G Power (2022) 58 | "Mozilla/5.0 (Linux; Android 12; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 59 | 60 | //Motorola Moto G Power (2021) 61 | "Mozilla/5.0 (Linux; Android 11; moto g power (2021)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 62 | 63 | //Redmi Note 9 Pro 64 | "Mozilla/5.0 (Linux; Android 12; Redmi Note 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 65 | 66 | //Redmi Note 8 Pro 67 | "Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 68 | 69 | //Huawei P30 Pro 70 | "Mozilla/5.0 (Linux; Android 10; VOG-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 71 | 72 | //Huawei P30 lite 73 | "Mozilla/5.0 (Linux; Android 10; MAR-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 74 | 75 | //Redmi Note 10 Pro 76 | "Mozilla/5.0 (Linux; Android 13; M2101K6G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 77 | 78 | //Xiaomi Poco X3 Pro 79 | "Mozilla/5.0 (Linux; Android 12; M2102J20SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 80 | 81 | //Redmi Note 11 Pro 5G 82 | "Mozilla/5.0 (Linux; Android 12; 2201116SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 83 | 84 | //OnePlus Nord N200 5G 85 | "Mozilla/5.0 (Linux; Android 12; DE2118) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 86 | 87 | //Apple iPhone SE (3rd generation) 88 | "Mozilla/5.0 (iPhone14,6; U; CPU iPhone OS 15_4 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19E241 Safari/602.1", 89 | 90 | //iPhone 13 Pro Max 91 | "Mozilla/5.0 (iPhone14,3; U; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19A346 Safari/602.1", 92 | 93 | //iPhone 12 94 | "Mozilla/5.0 (iPhone13,2; U; CPU iPhone OS 14_0like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1", 95 | 96 | //iPhone 11 97 | "Mozilla/5.0 (iPhone12,1; U; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1", 98 | 99 | //Apple iPhone XR (Safari) 100 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", 101 | 102 | //Apple iPhone XS (Chrome) 103 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1", 104 | 105 | //Apple iPhone XS Max (Firefox) 106 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15", 107 | 108 | //Apple iPhone X 109 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1", 110 | 111 | //Apple iPhone 8 112 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1", 113 | 114 | //Apple iPhone 8 Plus 115 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1", 116 | 117 | //Apple iPhone 7 118 | "Mozilla/5.0 (iPhone9,3; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1", 119 | 120 | //Apple iPhone 7 Plus 121 | "Mozilla/5.0 (iPhone9,4; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1", 122 | 123 | //Apple iPhone 6 124 | "Mozilla/5.0 (Apple-iPhone7C2/1202.466; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3", 125 | 126 | //Samsung Galaxy S23 Ultra 5G 127 | "Mozilla/5.0 (Linux; Android 13; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 128 | "Mozilla/5.0 (Linux; Android 13; SM-S918U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 129 | 130 | //Samsung Galaxy S23 5G 131 | "Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 132 | "Mozilla/5.0 (Linux; Android 13; SM-S911U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 133 | 134 | //Samsung Galaxy Note 20 Ultra 5G 135 | "Mozilla/5.0 (Linux; Android 13; SM-N986B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 136 | "Mozilla/5.0 (Linux; Android 13; SM-N986U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 137 | 138 | //Samsung Galaxy Note 20 5G 139 | "Mozilla/5.0 (Linux; Android 13; SM-N981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 140 | "Mozilla/5.0 (Linux; Android 13; SM-N981U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 141 | 142 | //OnePlus 9 Pro 143 | "Mozilla/5.0 (Linux; Android 13; LE2121) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 144 | "Mozilla/5.0 (Linux; Android 13; LE2125) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 145 | 146 | //OnePlus 9 147 | "Mozilla/5.0 (Linux; Android 13; LE2113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 148 | "Mozilla/5.0 (Linux; Android 13; LE2115) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 149 | 150 | //OnePlus 8T 151 | "Mozilla/5.0 (Linux; Android 13; KB2001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 152 | "Mozilla/5.0 (Linux; Android 13; KB2005) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 153 | 154 | //Huawei P40 Pro 155 | "Mozilla/5.0 (Linux; Android 10; ELS-NX9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 156 | "Mozilla/5.0 (Linux; Android 10; ELS-N04) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 157 | 158 | //Huawei P40 159 | "Mozilla/5.0 (Linux; Android 10; ANA-NX9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 160 | "Mozilla/5.0 (Linux; Android 10; ANA-N29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 161 | 162 | //Xiaomi Mi 11 163 | "Mozilla/5.0 (Linux; Android 13; M2011K2C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 164 | "Mozilla/5.0 (Linux; Android 13; M2011K2G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 165 | 166 | //Xiaomi Mi 11 Ultra 167 | "Mozilla/5.0 (Linux; Android 13; M2102K1C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 168 | "Mozilla/5.0 (Linux; Android 13; M2102K1G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 169 | 170 | //Xiaomi Mi 11i 171 | "Mozilla/5.0 (Linux; Android 13; M2012K11G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 172 | 173 | //Oppo Find X5 Pro 174 | "Mozilla/5.0 (Linux; Android 13; CPH2305) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 175 | "Mozilla/5.0 (Linux; Android 13; CPH2307) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 176 | 177 | //Oppo Find X3 Pro 178 | "Mozilla/5.0 (Linux; Android 13; CPH2173) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 179 | 180 | //Oppo Reno 6 Pro 5G 181 | "Mozilla/5.0 (Linux; Android 13; CPH2247) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 182 | 183 | //Vivo X70 Pro+ 184 | "Mozilla/5.0 (Linux; Android 13; V2114) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 185 | 186 | //Vivo X60 Pro+ 187 | "Mozilla/5.0 (Linux; Android 13; V2056A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 188 | 189 | //LG Velvet 5G 190 | "Mozilla/5.0 (Linux; Android 13; LM-G900N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 191 | 192 | //Sony Xperia 1 III 193 | "Mozilla/5.0 (Linux; Android 13; XQ-BC72) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 194 | 195 | //Sony Xperia 5 II 196 | "Mozilla/5.0 (Linux; Android 13; XQ-AS72) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 197 | 198 | //Nokia 8.3 5G 199 | "Mozilla/5.0 (Linux; Android 13; Nokia 8.3 5G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 200 | 201 | //Nokia 7.2 202 | "Mozilla/5.0 (Linux; Android 12; Nokia 7.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 203 | 204 | //Realme GT 2 Pro 205 | "Mozilla/5.0 (Linux; Android 13; RMX3301) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 206 | 207 | //Realme X7 Pro 208 | "Mozilla/5.0 (Linux; Android 13; RMX2121) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 209 | 210 | //Asus ROG Phone 5 211 | "Mozilla/5.0 (Linux; Android 13; ASUS_I005DA) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 212 | 213 | //Asus Zenfone 8 214 | "Mozilla/5.0 (Linux; Android 13; ASUS_I006DA) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 215 | 216 | //Google Pixel 7 Pro 217 | "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 218 | 219 | //Google Pixel 7 220 | "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 221 | 222 | //Google Pixel 6 Pro 223 | "Mozilla/5.0 (Linux; Android 13; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 224 | 225 | //Google Pixel 6 226 | "Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 227 | 228 | //Motorola Moto G Power (2022) 229 | "Mozilla/5.0 (Linux; Android 12; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 230 | 231 | //Motorola Moto G Stylus (2022) 232 | "Mozilla/5.0 (Linux; Android 12; moto g stylus (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 233 | 234 | //ZTE Axon 30 Ultra 235 | "Mozilla/5.0 (Linux; Android 13; A2022U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 236 | 237 | //ZTE Nubia Red Magic 7 Pro 238 | "Mozilla/5.0 (Linux; Android 13; NX709J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36", 239 | //Apple iPad 240 | "Mozilla/5.0 (iPad; CPU OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1", 241 | "Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1", 242 | "Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Mobile/15E148 Safari/604.1", 243 | "Mozilla/5.0 (iPad; CPU OS 12_4_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1", 244 | "Mozilla/5.0 (iPad; CPU OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1", 245 | //Samsung Galaxy Tab 246 | "Mozilla/5.0 (Linux; Android 12; SM-T970) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36", 247 | "Mozilla/5.0 (Linux; Android 11; SM-T860) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36", 248 | "Mozilla/5.0 (Linux; Android 10; SM-T510) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36", 249 | "Mozilla/5.0 (Linux; Android 9; SM-T720) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36", 250 | "Mozilla/5.0 (Linux; Android 8.1.0; SM-T580) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36", 251 | ]; 252 | 253 | module.exports = user_agents; 254 | -------------------------------------------------------------------------------- /bot/core/api.js: -------------------------------------------------------------------------------- 1 | const app = require("../config/app"); 2 | const logger = require("../utils/logger"); 3 | const sleep = require("../utils/sleep"); 4 | const _ = require("lodash"); 5 | 6 | class ApiRequest { 7 | constructor(session_name, bot_name) { 8 | this.bot_name = bot_name; 9 | this.session_name = session_name; 10 | } 11 | 12 | async get_user_data(http_client) { 13 | try { 14 | const response = await http_client.post( 15 | `${app.apiUrl}/api/v1/account/start` 16 | ); 17 | return response.data; 18 | } catch (error) { 19 | if (error?.response?.status >= 500 && error?.response?.status < 600) { 20 | return false; 21 | } 22 | if (error?.response?.data?.message) { 23 | logger.error( 24 | `[${this.bot_name}] | ${this.session_name} | Error while getting User Data: ${error?.response?.data?.message}` 25 | ); 26 | } else { 27 | const regex = /ENOTFOUND\s([^\s]+)/; 28 | const match = error.message.match(regex); 29 | logger.error( 30 | `[${this.bot_name}] | ${ 31 | this.session_name 32 | } | Error while getting User Data: ${ 33 | error.message.includes("ENOTFOUND") || 34 | error.message.includes("getaddrinfo") || 35 | error.message.includes("ECONNREFUSED") 36 | ? `The proxy server at ${ 37 | match && match[1] ? match[1] : "unknown address" 38 | } could not be found. Please check the proxy address and your network connection` 39 | : error.message 40 | }` 41 | ); 42 | } 43 | await sleep(3); // Sleep for 3 seconds 44 | return null; 45 | } 46 | } 47 | 48 | async #validate_query_id(http_client) { 49 | try { 50 | const response = await http_client.post( 51 | `${app.apiUrl}/api/v1/account/start` 52 | ); 53 | if (!_.isEmpty(response?.data)) { 54 | return true; 55 | } 56 | return false; 57 | } catch (error) { 58 | if (error?.response?.status >= 500 && error?.response?.status < 600) { 59 | return "server_error"; 60 | } 61 | if ( 62 | error?.response?.data?.message 63 | ?.toLowerCase() 64 | ?.includes("sign is missing") || 65 | error?.response?.status == 401 66 | ) { 67 | return false; 68 | } 69 | 70 | throw error; 71 | } 72 | } 73 | 74 | async validate(http_client) { 75 | let validated = "server_error"; 76 | while (typeof validated === "string" && validated === "server_error") { 77 | validated = await this.#validate_query_id(http_client); 78 | 79 | if (validated === "server_error") { 80 | logger.warning( 81 | `[${this.bot_name}] | ${this.session_name} | Server error. Retrying...` 82 | ); 83 | await sleep(5); 84 | continue; 85 | } 86 | 87 | if (validated === false) { 88 | return false; 89 | } 90 | 91 | return true; 92 | } 93 | } 94 | 95 | async init_account(http_client) { 96 | const genders = ["male", "female"]; 97 | const random = _.random(0, 1); 98 | try { 99 | const data = { 100 | lang: "en", 101 | sex: genders[random], 102 | }; 103 | const response = await http_client.post( 104 | `${app.apiUrl}/api/v1/account/init`, 105 | JSON.stringify(data) 106 | ); 107 | return response.data; 108 | } catch (error) { 109 | if (error?.response?.data?.message) { 110 | logger.warning( 111 | `[${this.bot_name}] | ${this.session_name} | Error while initting account: ${error?.response?.data?.message}` 112 | ); 113 | } else { 114 | logger.error( 115 | `[${this.bot_name}] | ${this.session_name} | Error while initting account: ${error.message}` 116 | ); 117 | } 118 | } 119 | } 120 | 121 | async sponsor(http_client) { 122 | try { 123 | const sponsors = [ 124 | "binance", 125 | "okx", 126 | "bybit", 127 | "solana", 128 | "arbitrum", 129 | "ton", 130 | "binance-chain", 131 | ]; 132 | const random = _.random(0, 6); 133 | const data = { 134 | sponsor: sponsors[random], 135 | }; 136 | 137 | const response = await http_client.post( 138 | `${app.apiUrl}/api/v1/account/sponsor`, 139 | JSON.stringify(data) 140 | ); 141 | return response.data; 142 | } catch (error) { 143 | if (error?.response?.data?.message) { 144 | logger.warning( 145 | `[${this.bot_name}] | ${this.session_name} | Error while setting sponsor: ${error?.response?.data?.message}` 146 | ); 147 | } else { 148 | logger.error( 149 | `[${this.bot_name}] | ${this.session_name} | Error while setting sponsor: ${error.message}` 150 | ); 151 | } 152 | } 153 | } 154 | 155 | async config(http_client) { 156 | try { 157 | const response = await http_client.post(`${app.apiUrl}/api/v1/config`); 158 | return response.data; 159 | } catch (error) { 160 | if (error?.response?.data?.message) { 161 | logger.warning( 162 | `[${this.bot_name}] | ${this.session_name} | Error while getting config: ${error?.response?.data?.message}` 163 | ); 164 | } else { 165 | logger.error( 166 | `[${this.bot_name}] | ${this.session_name} | Error while getting config: ${error.message}` 167 | ); 168 | } 169 | } 170 | } 171 | 172 | async get_daily_sync_info(http_client) { 173 | try { 174 | const response = await http_client.post( 175 | `${app.apiUrl}/api/v1/mine/sync/daily` 176 | ); 177 | return response.data; 178 | } catch (error) { 179 | if (error?.response?.data?.message) { 180 | logger.warning( 181 | `[${this.bot_name}] | ${this.session_name} | Error while getting daily sync info: ${error?.response?.data?.message}` 182 | ); 183 | } else { 184 | logger.error( 185 | `[${this.bot_name}] | ${this.session_name} | Error while getting daily sync info: ${error.message}` 186 | ); 187 | } 188 | } 189 | } 190 | 191 | // start here tomorrow 192 | async tasks(http_client) { 193 | try { 194 | const response = await http_client.post(`${app.apiUrl}/api/v1/task/list`); 195 | return response.data; 196 | } catch (error) { 197 | if (error?.response?.data?.message) { 198 | logger.warning( 199 | `[${this.bot_name}] | ${this.session_name} | Error while getting tasks: ${error?.response?.data?.message}` 200 | ); 201 | } else { 202 | logger.error( 203 | `[${this.bot_name}] | ${this.session_name} | Error while getting tasks: ${error.message}` 204 | ); 205 | } 206 | } 207 | } 208 | 209 | async play_enigma(http_client, data) { 210 | try { 211 | const response = await http_client.post( 212 | `${app.apiUrl}/api/v1/mine/enigma`, 213 | JSON.stringify(data) 214 | ); 215 | return response.data; 216 | } catch (error) { 217 | if (error?.response?.data?.message) { 218 | logger.warning( 219 | `[${this.bot_name}] | ${this.session_name} | Error while playing enigma: ${error?.response?.data?.message}` 220 | ); 221 | } else { 222 | logger.error( 223 | `[${this.bot_name}] | ${this.session_name} | Error while playing enigma: ${error.message}` 224 | ); 225 | } 226 | } 227 | } 228 | 229 | async play_combo(http_client, data) { 230 | try { 231 | const response = await http_client.post( 232 | `${app.apiUrl}/api/v1/mine/combo`, 233 | JSON.stringify(data) 234 | ); 235 | return response.data; 236 | } catch (error) { 237 | if (error?.response?.data?.message) { 238 | logger.warning( 239 | `[${this.bot_name}] | ${this.session_name} | Error while playing combo ${error?.response?.data?.message}` 240 | ); 241 | } else { 242 | logger.error( 243 | `[${this.bot_name}] | ${this.session_name} | Error while playing combo: ${error.message}` 244 | ); 245 | } 246 | } 247 | } 248 | 249 | async play_easter(http_client, data) { 250 | try { 251 | const response = await http_client.post( 252 | `${app.apiUrl}/api/v1/mine/easter-eggs`, 253 | JSON.stringify(data) 254 | ); 255 | return response.data; 256 | } catch (error) { 257 | if (error?.response?.data?.message) { 258 | logger.warning( 259 | `[${this.bot_name}] | ${this.session_name} | Error while playing easter egg: ${error?.response?.data?.message}` 260 | ); 261 | } else { 262 | logger.error( 263 | `[${this.bot_name}] | ${this.session_name} | Error while playing easter egg: ${error.message}` 264 | ); 265 | } 266 | } 267 | } 268 | 269 | async get_boosts(http_client) { 270 | try { 271 | const response = await http_client.post( 272 | `${app.apiUrl}/api/v1/boosts/list` 273 | ); 274 | return response.data; 275 | } catch (error) { 276 | if (error?.response?.data?.message) { 277 | logger.warning( 278 | `[${this.bot_name}] | ${this.session_name} | Error while getting boosts: ${error?.response?.data?.message}` 279 | ); 280 | } else { 281 | logger.error( 282 | `[${this.bot_name}] | ${this.session_name} | Error while getting boosts: ${error.message}` 283 | ); 284 | } 285 | } 286 | } 287 | 288 | async upgrade_boost(http_client, data) { 289 | try { 290 | const response = await http_client.post( 291 | `${app.apiUrl}/api/v1/boosts`, 292 | JSON.stringify(data) 293 | ); 294 | return response.data; 295 | } catch (error) { 296 | if ( 297 | error?.response?.data?.message && 298 | error?.response?.data?.message.includes("not available") 299 | ) { 300 | return "not_available"; 301 | } 302 | 303 | if ( 304 | error?.response?.data?.message && 305 | error?.response?.data?.message.includes("exceeded") 306 | ) { 307 | return "exceeded"; 308 | } 309 | 310 | if (error?.response?.data?.message) { 311 | logger.warning( 312 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading boosts ${error?.response?.data?.message}` 313 | ); 314 | } else { 315 | logger.error( 316 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading boosts: ${error.message}` 317 | ); 318 | } 319 | } 320 | } 321 | 322 | async claim_task(http_client, data) { 323 | try { 324 | const response = await http_client.post( 325 | `${app.apiUrl}/api/v1/task/upgrade`, 326 | JSON.stringify(data) 327 | ); 328 | return response.data; 329 | } catch (error) { 330 | if (error?.response?.data?.message) { 331 | logger.warning( 332 | `[${this.bot_name}] | ${this.session_name} | Error while claiming task ${error?.response?.data?.message}` 333 | ); 334 | } else { 335 | logger.error( 336 | `[${this.bot_name}] | ${this.session_name} | Error while claiming task: ${error.message}` 337 | ); 338 | } 339 | } 340 | } 341 | 342 | async upgrade_cards(http_client, data) { 343 | try { 344 | const response = await http_client.post( 345 | `${app.apiUrl}/api/v1/mine/upgrade`, 346 | JSON.stringify(data) 347 | ); 348 | return response.data; 349 | } catch (error) { 350 | if ( 351 | error?.response?.data?.message && 352 | error?.response?.data?.message.includes("insufficient") 353 | ) { 354 | return "insufficient"; 355 | } else if (error?.response?.data?.message) { 356 | logger.warning( 357 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading cards ${error?.response?.data?.message}` 358 | ); 359 | } else { 360 | logger.error( 361 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading cards: ${error.message}` 362 | ); 363 | } 364 | } 365 | } 366 | 367 | async taps(http_client, data) { 368 | try { 369 | const response = await http_client.post( 370 | `${app.apiUrl}/api/v1/clicker/tap`, 371 | JSON.stringify(data) 372 | ); 373 | return response.data; 374 | } catch (error) { 375 | if (error?.response?.data?.message) { 376 | logger.warning( 377 | `[${this.bot_name}] | ${this.session_name} | Error while tapping ${error?.response?.data?.message}` 378 | ); 379 | } else { 380 | logger.error( 381 | `[${this.bot_name}] | ${this.session_name} | Error while tapping: ${error.message}` 382 | ); 383 | } 384 | } 385 | } 386 | 387 | async daily_reward(http_client) { 388 | try { 389 | const response = await http_client.post( 390 | `${app.apiUrl}/api/v1/task/upgrade`, 391 | JSON.stringify({ 392 | taskId: "streak_days_reward", 393 | timezone: "Africa/Accra", 394 | }) 395 | ); 396 | return response.data; 397 | } catch (error) { 398 | if ( 399 | error?.response?.data?.message && 400 | error?.response?.data?.message.includes( 401 | "you_are_not_subscribe_to_channel" 402 | ) 403 | ) { 404 | return "not_subscribed"; 405 | } else if ( 406 | error?.response?.data?.message && 407 | error?.response?.data?.message.includes("comeback") 408 | ) { 409 | return "claimed"; 410 | } else if (error?.response?.data?.message) { 411 | logger.warning( 412 | `[${this.bot_name}] | ${this.session_name} | Error while claiming daily reward ${error?.response?.data?.message}` 413 | ); 414 | return "claimed"; 415 | } else { 416 | logger.error( 417 | `[${this.bot_name}] | ${this.session_name} | Error while claiming daily reward: ${error.message}` 418 | ); 419 | return null; 420 | } 421 | } 422 | } 423 | 424 | async get_combo_data(http_client) { 425 | try { 426 | const response = await http_client.get(`${app.comboApi}`); 427 | return response.data; 428 | } catch (error) { 429 | if (error?.response?.data?.message) { 430 | logger.warning( 431 | `[${this.bot_name}] | ${this.session_name} | Error while tapping ${error?.response?.data?.message}` 432 | ); 433 | } else { 434 | logger.error( 435 | `[${this.bot_name}] | ${this.session_name} | Error while tapping: ${error.message}` 436 | ); 437 | } 438 | } 439 | } 440 | 441 | async mine_sync(http_client) { 442 | try { 443 | const response = await http_client.post(`${app.apiUrl}/api/v1/mine/sync`); 444 | return response.data; 445 | } catch (error) { 446 | if (error?.response?.data?.message) { 447 | logger.warning( 448 | `[${this.bot_name}] | ${this.session_name} | Error while getting mine sync ${error?.response?.data?.message}` 449 | ); 450 | } else { 451 | logger.error( 452 | `[${this.bot_name}] | ${this.session_name} | Error while getting mine sync: ${error.message}` 453 | ); 454 | } 455 | } 456 | } 457 | } 458 | 459 | module.exports = ApiRequest; 460 | -------------------------------------------------------------------------------- /bot/core/nonSessionTapper.js: -------------------------------------------------------------------------------- 1 | const logger = require("../utils/logger"); 2 | const headers = require("./header"); 3 | const settings = require("../config/config"); 4 | const app = require("../config/app"); 5 | const user_agents = require("../config/userAgents"); 6 | const fs = require("fs"); 7 | const sleep = require("../utils/sleep"); 8 | const ApiRequest = require("./api"); 9 | const _ = require("lodash"); 10 | const moment = require("moment"); 11 | const filterArray = require("../helpers/filterArray"); 12 | const upgradeTabCardsBuying = require("../scripts/upgradeTabCardsBuying"); 13 | const upgradeNoConditionCards = require("../scripts/upgradeNoConditionCards"); 14 | const path = require("path"); 15 | const _isArray = require("../utils/_isArray"); 16 | const fdy = require("fdy-scraping"); 17 | 18 | class NonSessionTapper { 19 | constructor(query_id, query_name) { 20 | this.bot_name = "rockyrabbit"; 21 | this.session_name = query_name; 22 | this.query_id = query_id; 23 | this.API_URL = app.apiUrl; 24 | this.session_user_agents = this.#load_session_data(); 25 | this.headers = { ...headers, "user-agent": this.#get_user_agent() }; 26 | this.api = new ApiRequest(this.session_name, this.bot_name); 27 | } 28 | 29 | #load_session_data() { 30 | try { 31 | const filePath = path.join(process.cwd(), "session_user_agents.json"); 32 | const data = fs.readFileSync(filePath, "utf8"); 33 | return JSON.parse(data); 34 | } catch (error) { 35 | if (error.code === "ENOENT") { 36 | return {}; 37 | } else { 38 | throw error; 39 | } 40 | } 41 | } 42 | 43 | #get_random_user_agent() { 44 | const randomIndex = Math.floor(Math.random() * user_agents.length); 45 | return user_agents[randomIndex]; 46 | } 47 | 48 | #get_user_agent() { 49 | if (this.session_user_agents[this.session_name]) { 50 | return this.session_user_agents[this.session_name]; 51 | } 52 | 53 | logger.info( 54 | `[${this.bot_name}] | ${this.session_name} | Generating new user agent...` 55 | ); 56 | const newUserAgent = this.#get_random_user_agent(); 57 | this.session_user_agents[this.session_name] = newUserAgent; 58 | this.#save_session_data(this.session_user_agents); 59 | return newUserAgent; 60 | } 61 | 62 | #save_session_data(session_user_agents) { 63 | const filePath = path.join(process.cwd(), "session_user_agents.json"); 64 | fs.writeFileSync(filePath, JSON.stringify(session_user_agents, null, 2)); 65 | } 66 | 67 | #get_boost_by_id(data, boostId) { 68 | const boost = data.boostsList.find((boost) => boost.boostId === boostId); 69 | return boost ? boost : {}; 70 | } 71 | 72 | #get_platform(userAgent) { 73 | const platformPatterns = [ 74 | { pattern: /iPhone/i, platform: "ios" }, 75 | { pattern: /Android/i, platform: "android" }, 76 | { pattern: /iPad/i, platform: "ios" }, 77 | ]; 78 | 79 | for (const { pattern, platform } of platformPatterns) { 80 | if (pattern.test(userAgent)) { 81 | return platform; 82 | } 83 | } 84 | 85 | return "Unknown"; 86 | } 87 | 88 | async #check_proxy(http_client, proxy) { 89 | try { 90 | const response = await http_client.get("https://httpbin.org/ip"); 91 | const ip = response.data.origin; 92 | logger.info( 93 | `[${this.bot_name}] | ${this.session_name} | Proxy IP: ${ip}` 94 | ); 95 | } catch (error) { 96 | if ( 97 | error.message.includes("ENOTFOUND") || 98 | error.message.includes("getaddrinfo") || 99 | error.message.includes("ECONNREFUSED") 100 | ) { 101 | logger.error( 102 | `[${this.bot_name}] | ${this.session_name} | Error: Unable to resolve the proxy address. The proxy server at ${proxy.ip}:${proxy.port} could not be found. Please check the proxy address and your network connection.` 103 | ); 104 | logger.error( 105 | `[${this.bot_name}] | ${this.session_name} | No proxy will be used.` 106 | ); 107 | } else { 108 | logger.error( 109 | `[${this.bot_name}] | ${this.session_name} | Proxy: ${proxy.ip}:${proxy.port} | Error: ${error.message}` 110 | ); 111 | } 112 | 113 | return false; 114 | } 115 | } 116 | 117 | async #get_user_data(http_client) { 118 | let profile_data = false; 119 | while (typeof profile_data === "boolean" && !profile_data) { 120 | profile_data = await this.api.get_user_data(http_client); 121 | if (profile_data === false) { 122 | logger.warning( 123 | `[${this.bot_name}] | ${this.session_name} | Unable to get user data. Retrying...` 124 | ); 125 | await sleep(5); 126 | continue; 127 | } 128 | 129 | if (_.isNull(profile_data) || _.isEmpty(profile_data)) { 130 | logger.warning( 131 | `[${this.bot_name}] | ${this.session_name} | Error while getting user data. Aborting...` 132 | ); 133 | break; 134 | } 135 | 136 | return profile_data; 137 | } 138 | return null; 139 | } 140 | 141 | async run(proxy) { 142 | let http_client; 143 | 144 | let profile_data, boosts_list; 145 | let sleep_daily_reward = 0; 146 | let tasks_list = {}; 147 | let config = {}; 148 | let get_daily_sync_info = {}; 149 | let mine_sync = []; 150 | let exceeded_energy = 0; 151 | let exceeded_turbo = 0; 152 | let sleep_empty_energy = 0; 153 | 154 | if (settings.USE_PROXY_FROM_FILE && proxy) { 155 | http_client = fdy.create({ 156 | headers: this.headers, 157 | proxy, 158 | }); 159 | const proxy_result = await this.#check_proxy(http_client, proxy); 160 | if (!proxy_result) { 161 | http_client = fdy.create({ 162 | headers: this.headers, 163 | }); 164 | } 165 | } else { 166 | http_client = fdy.create({ 167 | headers: this.headers, 168 | }); 169 | } 170 | while (true) { 171 | try { 172 | const currentTime = _.floor(Date.now() / 1000); 173 | 174 | http_client.defaults.headers["sec-ch-ua-platform"] = this.#get_platform( 175 | this.#get_user_agent() 176 | ); 177 | 178 | const tg_web_data = await this.query_id; 179 | 180 | http_client.defaults.headers["authorization"] = `tma ${tg_web_data}`; 181 | await sleep(2); 182 | // Get profile data 183 | profile_data = await this.#get_user_data(http_client); 184 | boosts_list = await this.api.get_boosts(http_client); 185 | tasks_list = await this.api.tasks(http_client); 186 | config = await this.api.config(http_client); 187 | mine_sync = await this.api.mine_sync(http_client); 188 | get_daily_sync_info = await this.api.get_daily_sync_info(http_client); 189 | 190 | if ( 191 | _.isEmpty(profile_data) || 192 | profile_data?.status?.toLowerCase() !== "ok" 193 | ) { 194 | continue; 195 | } 196 | 197 | if (!profile_data?.initAccount || _.isEmpty(profile_data?.account)) { 198 | await this.api.init_account(http_client); 199 | await this.api.sponsor(http_client); 200 | continue; 201 | } 202 | 203 | if (profile_data?.account?.sponsor == "") { 204 | await this.api.sponsor(http_client); 205 | continue; 206 | } 207 | 208 | await sleep(1); 209 | 210 | if (profile_data?.clicker?.lastPassiveEarn > 0) { 211 | logger.info( 212 | `[${this.bot_name}] | ${this.session_name} | 💸 Last passive earn: +${profile_data?.clicker?.lastPassiveEarn} | Earn per hour: ${profile_data?.clicker?.earnPassivePerHour}` 213 | ); 214 | } 215 | 216 | // Daily reward 217 | if (settings.AUTO_CLAIM_REWARD && sleep_daily_reward <= currentTime) { 218 | const reward_data = await this.api.daily_reward(http_client); 219 | 220 | if ( 221 | typeof reward_data === "string" && 222 | reward_data.includes("not_subscribed") 223 | ) { 224 | logger.info( 225 | `[${this.bot_name}] | ${this.session_name} |⌛Join RockyRabit channel before daily reward can be claim. Skipping daily reward claim...` 226 | ); 227 | } else if ( 228 | typeof reward_data === "string" && 229 | reward_data.includes("claimed") 230 | ) { 231 | sleep_daily_reward = 232 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000; 233 | logger.info( 234 | `[${this.bot_name}] | ${this.session_name} | 🚶 Daily reward already claimed. Skipping...` 235 | ); 236 | } else if (reward_data?.status?.toLowerCase() === "ok") { 237 | profile_data = await this.#get_user_data(http_client); 238 | logger.info( 239 | `[${this.bot_name}] | ${this.session_name} | 🎉 Claimed daily reward successfully | Reward: ${reward_data?.task?.rewardCoins} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 240 | ); 241 | sleep_daily_reward = 242 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000; 243 | } 244 | } 245 | 246 | await sleep(1); 247 | 248 | //Send taps 249 | if (settings.RANDOM_TAPS_COUNT[0] > settings.RANDOM_TAPS_COUNT[1]) { 250 | logger.error( 251 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN must be less than RANDOM_TAPS_COUNT MAX. Example: RANDOM_TAPS_COUNT: [10, 20]` 252 | ); 253 | process.exit(1); 254 | } 255 | if ( 256 | !_.isInteger(settings.RANDOM_TAPS_COUNT[0]) || 257 | !_.isInteger(settings.RANDOM_TAPS_COUNT[1]) 258 | ) { 259 | logger.error( 260 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN and MAX must be integers/numbers. Example: RANDOM_TAPS_COUNT: [10, 20]` 261 | ); 262 | process.exit(1); 263 | } 264 | 265 | let taps_sent_count = 0; 266 | if (sleep_empty_energy <= currentTime) { 267 | while ( 268 | profile_data?.clicker?.availableTaps > 269 | settings.MIN_AVAILABLE_ENERGY && 270 | taps_sent_count < 10 271 | ) { 272 | await sleep(_.random(5, 15)); 273 | let taps = _.random( 274 | settings.RANDOM_TAPS_COUNT[0], 275 | settings.RANDOM_TAPS_COUNT[1] 276 | ); 277 | boosts_list = await this.api.get_boosts(http_client); 278 | if ( 279 | !moment(exceeded_turbo * 1000).isSame(new Date().getTime(), "day") 280 | ) { 281 | const turbo_data = this.#get_boost_by_id(boosts_list, "turbo"); 282 | 283 | const turbo_boost = await this.api.upgrade_boost(http_client, { 284 | boostId: turbo_data?.boostId, 285 | timezone: app.timezone, 286 | }); 287 | 288 | if (turbo_boost?.status?.toLowerCase() === "ok") { 289 | logger.info( 290 | `[${this.bot_name}] | ${this.session_name} | ⏩ Turbo boost activated.` 291 | ); 292 | await sleep(5); 293 | } else if ( 294 | typeof turbo_boost == "string" && 295 | turbo_boost.includes("exceeded") 296 | ) { 297 | exceeded_turbo = currentTime; 298 | } 299 | } 300 | 301 | const taps_can_send = 302 | profile_data?.clicker?.availableTaps / 303 | profile_data?.clicker?.earnPerTap; 304 | const count = 305 | taps > _.floor(taps_can_send) ? _.floor(taps_can_send) : taps; 306 | const taps_result = await this.api.taps(http_client, { count }); 307 | 308 | if (taps_result?.status?.toLowerCase() === "ok") { 309 | const balanceChange = 310 | taps_result?.clicker?.balance - profile_data?.clicker?.balance; 311 | profile_data = await this.#get_user_data(http_client); 312 | logger.info( 313 | `[${this.bot_name}] | ${this.session_name} | ✅ Taps sent successfully | Balance: ${profile_data?.clicker?.balance} (+${balanceChange}) | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 314 | ); 315 | } 316 | 317 | profile_data = await this.#get_user_data(http_client); 318 | boosts_list = await this.api.get_boosts(http_client); 319 | 320 | if ( 321 | profile_data?.clicker?.availableTaps <= 322 | settings.MIN_AVAILABLE_ENERGY 323 | ) { 324 | if (_.isEmpty(boosts_list)) { 325 | break; 326 | } 327 | const full_taps_data = this.#get_boost_by_id( 328 | boosts_list, 329 | "full-available-taps" 330 | ); 331 | if (_.isEmpty(full_taps_data)) { 332 | break; 333 | } 334 | 335 | if ( 336 | full_taps_data?.lastUpgradeAt + 3605 <= currentTime && 337 | settings.APPLY_DAILY_FULL_ENERGY && 338 | !moment(exceeded_energy * 1000).isSame( 339 | new Date().getTime(), 340 | "day" 341 | ) 342 | ) { 343 | const full_energy_boost = await this.api.upgrade_boost( 344 | http_client, 345 | { 346 | boostId: full_taps_data?.boostId, 347 | timezone: app.timezone, 348 | } 349 | ); 350 | 351 | if ( 352 | typeof full_energy_boost == "string" && 353 | full_energy_boost.includes("exceeded") 354 | ) { 355 | exceeded_energy = currentTime; 356 | break; 357 | } 358 | 359 | if (full_energy_boost?.status?.toLowerCase() === "ok") { 360 | profile_data = await this.#get_user_data(http_client); 361 | logger.info( 362 | `[${this.bot_name}] | ${this.session_name} | 🔋Full energy boost applied successfully` 363 | ); 364 | } 365 | } else { 366 | profile_data = await this.#get_user_data(http_client); 367 | sleep_empty_energy = currentTime + settings.SLEEP_EMPTY_ENERGY; 368 | 369 | logger.info( 370 | `[${this.bot_name}] | ${ 371 | this.session_name 372 | } | Not enough energy to send ${count} taps. Needed ${ 373 | count * profile_data?.clicker?.earnPerTap 374 | } energy to send taps | Available: ${ 375 | profile_data?.clicker?.availableTaps 376 | } | Sleeping ${settings.SLEEP_EMPTY_ENERGY}s` 377 | ); 378 | break; 379 | } 380 | } 381 | 382 | taps_sent_count++; 383 | } 384 | } 385 | 386 | await sleep(2); 387 | 388 | // Daily combos 389 | const combo_data = await this.api.get_combo_data(http_client); 390 | if (!_.isEmpty(combo_data)) { 391 | const expireAtForCards = 392 | new Date(combo_data?.expireAtForCards).getTime() / 1000; 393 | 394 | const expireAtForEaster = 395 | new Date(combo_data?.expireAtForEaster).getTime() / 1000; 396 | 397 | if ( 398 | settings.AUTO_PLAY_ENIGMA && 399 | !_.isEmpty(combo_data?.enigma) && 400 | !_.isEmpty(get_daily_sync_info) 401 | ) { 402 | const play_enigma_data = get_daily_sync_info?.enigma; 403 | 404 | if ( 405 | play_enigma_data?.completedAt < 1 && 406 | Array.isArray(combo_data?.enigma) && 407 | play_enigma_data?.passphrase?.includes(combo_data?.enigma[0]) 408 | ) { 409 | const play_enigma = await this.api.play_enigma(http_client, { 410 | passphrase: Array.isArray(combo_data?.enigma) 411 | ? combo_data.enigma.join(",") 412 | : combo_data.enigma, 413 | enigmaId: play_enigma_data?.enigmaId, 414 | }); 415 | 416 | if (play_enigma?.status?.toLowerCase() === "ok") { 417 | profile_data = await this.#get_user_data(http_client); 418 | logger.info( 419 | `[${this.bot_name}] | ${this.session_name} | 🎊 Enigma claimed successfully | Reward: ${play_enigma_data?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 420 | ); 421 | } 422 | } 423 | } 424 | 425 | if ( 426 | settings.AUTO_PLAY_COMBO && 427 | !_.isEmpty(combo_data?.cards) && 428 | !_.isEmpty(get_daily_sync_info) 429 | ) { 430 | const combo_info = get_daily_sync_info?.superSet; 431 | 432 | if (combo_info?.completedAt < 1 && expireAtForCards > currentTime) { 433 | const play_combo = await this.api.play_combo(http_client, { 434 | combos: Array.isArray(combo_data?.cards) 435 | ? combo_data?.cards.join(",") 436 | : combo_data?.cards, 437 | comboId: combo_info?.comboId, 438 | }); 439 | 440 | if (play_combo?.status?.toLowerCase() === "ok") { 441 | profile_data = await this.#get_user_data(http_client); 442 | logger.info( 443 | `[${this.bot_name}] | ${this.session_name} | 🎊 Daily combo claimed successfully | Reward: ${play_combo?.winner?.rabbitWinner} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 444 | ); 445 | } 446 | } 447 | } 448 | 449 | if ( 450 | settings.AUTO_CLAIM_EASTER_EGG && 451 | !_.isEmpty(combo_data?.easter) && 452 | !_.isEmpty(get_daily_sync_info?.easterEggs) 453 | ) { 454 | const easter_info = get_daily_sync_info?.easterEggs; 455 | 456 | if ( 457 | easter_info?.completedAt < 1 && 458 | expireAtForEaster > currentTime 459 | ) { 460 | const play_easter = await this.api.play_easter(http_client, { 461 | easter: combo_data?.easter, 462 | easterEggsId: easter_info?.easterEggsId, 463 | }); 464 | 465 | if (play_easter?.status?.toLowerCase() === "ok") { 466 | profile_data = await this.#get_user_data(http_client); 467 | logger.info( 468 | `[${this.bot_name}] | ${this.session_name} | 🎊 Easter Egg claimed successfully | Reward: ${easter_info?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
` 469 | ); 470 | } 471 | } 472 | } 473 | } 474 | 475 | await sleep(3); 476 | 477 | // Boost upgrade (earn-per-tap) 478 | const tap_boost_data = this.#get_boost_by_id( 479 | boosts_list, 480 | "earn-per-tap" 481 | ); 482 | if ( 483 | settings.AUTO_UPGRADE_TAP && 484 | !_.isEmpty(tap_boost_data) && 485 | settings.MAX_TAP_LEVEL > tap_boost_data?.level && 486 | tap_boost_data?.price <= profile_data?.clicker?.balance 487 | ) { 488 | const tap_boost = await this.api.upgrade_boost(http_client, { 489 | boostId: tap_boost_data?.boostId, 490 | timezone: app.timezone, 491 | }); 492 | 493 | if (tap_boost?.status?.toLowerCase() === "ok") { 494 | profile_data = await this.#get_user_data(http_client); 495 | logger.info( 496 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Tap upgraded successfully | Level: ${tap_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 497 | ); 498 | } 499 | } 500 | await sleep(3); 501 | 502 | // Boost upgrade (max-taps) 503 | const energy_boost_data = this.#get_boost_by_id( 504 | boosts_list, 505 | "max-taps" 506 | ); 507 | 508 | if ( 509 | settings.AUTO_UPGRADE_ENERGY_LIMIT && 510 | !_.isEmpty(energy_boost_data) && 511 | settings.MAX_ENERGY_LIMIT_LEVEL > energy_boost_data?.level && 512 | energy_boost_data?.price <= profile_data?.clicker?.balance 513 | ) { 514 | const energy_boost = await this.api.upgrade_boost(http_client, { 515 | boostId: energy_boost_data?.boostId, 516 | timezone: app.timezone, 517 | }); 518 | if (energy_boost?.status?.toLowerCase() === "ok") { 519 | profile_data = await this.#get_user_data(http_client); 520 | logger.info( 521 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Energy limit upgraded successfully | Level: ${energy_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 522 | ); 523 | } 524 | } 525 | 526 | await sleep(3); 527 | 528 | // Boost upgrade (hourly-income-limit) 529 | const hourly_limit_data = this.#get_boost_by_id( 530 | boosts_list, 531 | "hourly-income-limit" 532 | ); 533 | 534 | if ( 535 | settings.AUTO_HOURLY_LIMIT && 536 | !_.isEmpty(hourly_limit_data) && 537 | settings.MAX_HOURLY_LIMIT_LEVEL > hourly_limit_data?.level && 538 | hourly_limit_data?.price <= profile_data?.clicker?.balance 539 | ) { 540 | const hourly_limit = await this.api.upgrade_boost(http_client, { 541 | boostId: hourly_limit_data?.boostId, 542 | timezone: app.timezone, 543 | }); 544 | if (hourly_limit?.status?.toLowerCase() === "ok") { 545 | profile_data = await this.#get_user_data(http_client); 546 | logger.info( 547 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Hourly limit upgraded successfully | Level: ${hourly_limit_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 548 | ); 549 | } 550 | } 551 | 552 | if (settings.AUTO_COMPLETE_TASKS) { 553 | await sleep(2); 554 | 555 | if (!_.isEmpty(tasks_list) && !_.isEmpty(tasks_list.tasks)) { 556 | const uncompletedTasks = filterArray.getUncompletedTasks( 557 | tasks_list.tasks 558 | ); 559 | 560 | if (!_.isEmpty(uncompletedTasks)) { 561 | for (const task of uncompletedTasks) { 562 | const complete_task = await this.api.claim_task(http_client, { 563 | taskId: task?.id, 564 | timezone: app.timezone, 565 | }); 566 | if (complete_task?.status?.toLowerCase() === "ok") { 567 | logger.info( 568 | `[${this.bot_name}] | ${this.session_name} | ✔️ Task completed successfully | Task title: ${task?.name} | Reward: ${task?.rewardCoins}` 569 | ); 570 | } else { 571 | logger.error( 572 | `[${this.bot_name}] | ${this.session_name} | ✖️ Could not complete task | Task title: ${task?.name} | Reward: ${task?.rewardCoins}` 573 | ); 574 | } 575 | } 576 | } 577 | } 578 | } 579 | 580 | if (settings.AUTO_UPGRADE_CARD) { 581 | if ( 582 | _.isEmpty(config?.config) || 583 | _.isEmpty(config?.config?.upgrade) || 584 | _.isEmpty(mine_sync) 585 | ) { 586 | continue; 587 | } 588 | 589 | const leagues = Array.from( 590 | { length: 10 }, 591 | (_, i) => filterArray.getById(mine_sync, `league_${i + 1}`)[0] 592 | ); 593 | 594 | if (leagues.some((league) => _.isEmpty(league))) { 595 | continue; 596 | } 597 | 598 | const cards_fighter = filterArray.getCardsOnUpgradeTab( 599 | config?.config?.upgrade, 600 | "fighter", 601 | "upgrade" 602 | ); 603 | const cards_coach = filterArray.getCardsOnUpgradeTab( 604 | config?.config?.upgrade, 605 | "coach", 606 | "upgrade" 607 | ); 608 | 609 | if (_.isEmpty(cards_fighter) || _.isEmpty(cards_coach)) { 610 | continue; 611 | } 612 | 613 | for (let i = 0; i < leagues.length; i++) { 614 | const allPreviousLeaguesCompleted = 615 | i === 0 || 616 | leagues 617 | .slice(0, i) 618 | .every((league) => league?.isCompleted === true); 619 | 620 | if ( 621 | leagues[i]?.isCompleted === false && 622 | allPreviousLeaguesCompleted 623 | ) { 624 | const level = i + 1; 625 | const cards_fighter_level = filterArray.getCardsWithLevel( 626 | mine_sync, 627 | cards_fighter, 628 | level 629 | ); 630 | const cards_coach_level = filterArray.getCardsWithLevel( 631 | mine_sync, 632 | cards_coach, 633 | level 634 | ); 635 | 636 | if (!_.isEmpty(cards_fighter_level)) { 637 | await upgradeTabCardsBuying( 638 | cards_fighter_level, 639 | http_client, 640 | this.api, 641 | this.session_name, 642 | this.bot_name 643 | ); 644 | mine_sync = await this.api.mine_sync(http_client); 645 | continue; 646 | } else if (!_.isEmpty(cards_coach_level)) { 647 | await upgradeTabCardsBuying( 648 | cards_coach_level, 649 | http_client, 650 | this.api, 651 | this.session_name, 652 | this.bot_name 653 | ); 654 | mine_sync = await this.api.mine_sync(http_client); 655 | continue; 656 | } 657 | 658 | if (leagues[i]?.price <= profile_data?.clicker?.balance) { 659 | const upgrade_league = await this.api.upgrade_cards( 660 | http_client, 661 | { 662 | upgradeId: `league_${level}`, 663 | } 664 | ); 665 | 666 | if (upgrade_league?.status?.toLowerCase() === "ok") { 667 | profile_data = await this.#get_user_data(http_client); 668 | 669 | logger.info( 670 | `[${this.bot_name}] | ${this.session_name} | ⬆️ League_${level} upgraded successfully | Level: ${leagues[i]?.level} | Cost: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}` 671 | ); 672 | } 673 | } else { 674 | logger.info( 675 | `[${this.bot_name}] | ${this.session_name} | 👎 Not enough balance to upgrade league ${level} | Need: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}` 676 | ); 677 | continue; 678 | } 679 | } 680 | } 681 | 682 | await sleep(2); 683 | 684 | // get cards with no conditions 685 | const cards_wnc = filterArray.getEmptyConditions( 686 | config?.config?.upgrade 687 | ); 688 | 689 | await upgradeNoConditionCards( 690 | cards_wnc, 691 | this.api, 692 | http_client, 693 | this.session_name, 694 | this.bot_name 695 | ); 696 | } 697 | } catch (error) { 698 | //traceback(error); 699 | logger.error( 700 | `[${this.bot_name}] | ${this.session_name} | ❗️Unknown error: ${error}}` 701 | ); 702 | } finally { 703 | let ran_sleep; 704 | if (_isArray(settings.SLEEP_BETWEEN_TAP)) { 705 | if ( 706 | _.isInteger(settings.SLEEP_BETWEEN_TAP[0]) && 707 | _.isInteger(settings.SLEEP_BETWEEN_TAP[1]) 708 | ) { 709 | ran_sleep = _.random( 710 | settings.SLEEP_BETWEEN_TAP[0], 711 | settings.SLEEP_BETWEEN_TAP[1] 712 | ); 713 | } else { 714 | ran_sleep = _.random(450, 800); 715 | } 716 | } else if (_.isInteger(settings.SLEEP_BETWEEN_TAP)) { 717 | const ran_add = _.random(20, 50); 718 | ran_sleep = settings.SLEEP_BETWEEN_TAP + ran_add; 719 | } else { 720 | ran_sleep = _.random(450, 800); 721 | } 722 | 723 | logger.info( 724 | `[${this.bot_name}] | ${this.session_name} | Sleeping for ${ran_sleep} seconds...` 725 | ); 726 | await sleep(ran_sleep); 727 | } 728 | } 729 | } 730 | } 731 | module.exports = NonSessionTapper; 732 | -------------------------------------------------------------------------------- /bot/core/tapper.js: -------------------------------------------------------------------------------- 1 | const logger = require("../utils/logger"); 2 | const headers = require("./header"); 3 | const { Api } = require("telegram"); 4 | const settings = require("../config/config"); 5 | const app = require("../config/app"); 6 | const user_agents = require("../config/userAgents"); 7 | const fs = require("fs"); 8 | const sleep = require("../utils/sleep"); 9 | const ApiRequest = require("./api"); 10 | const parser = require("../utils/parser"); 11 | const _ = require("lodash"); 12 | const moment = require("moment"); 13 | const filterArray = require("../helpers/filterArray"); 14 | const upgradeTabCardsBuying = require("../scripts/upgradeTabCardsBuying"); 15 | const upgradeNoConditionCards = require("../scripts/upgradeNoConditionCards"); 16 | const path = require("path"); 17 | const _isArray = require("../utils/_isArray"); 18 | const fdy = require("fdy-scraping"); 19 | const FdyTmp = require("fdy-tmp"); 20 | 21 | class Tapper { 22 | constructor(tg_client) { 23 | this.bot_name = "rockyrabbit"; 24 | this.session_name = tg_client.session_name; 25 | this.tg_client = tg_client.tg_client; 26 | this.API_URL = app.apiUrl; 27 | this.session_user_agents = this.#load_session_data(); 28 | this.headers = { ...headers, "user-agent": this.#get_user_agent() }; 29 | this.api = new ApiRequest(this.session_name, this.bot_name); 30 | this.sleep_floodwait = 0; 31 | this.runOnce = false; 32 | this.bot = null; 33 | } 34 | 35 | #load_session_data() { 36 | try { 37 | const filePath = path.join(process.cwd(), "session_user_agents.json"); 38 | const data = fs.readFileSync(filePath, "utf8"); 39 | return JSON.parse(data); 40 | } catch (error) { 41 | if (error.code === "ENOENT") { 42 | return {}; 43 | } else { 44 | throw error; 45 | } 46 | } 47 | } 48 | 49 | #clean_tg_web_data(queryString) { 50 | let cleanedString = queryString.replace(/^tgWebAppData=/, ""); 51 | cleanedString = cleanedString.replace( 52 | /&tgWebAppVersion=.*?&tgWebAppPlatform=.*?(?:&tgWebAppBotInline=.*?)?$/, 53 | "" 54 | ); 55 | return cleanedString; 56 | } 57 | 58 | #get_random_user_agent() { 59 | const randomIndex = Math.floor(Math.random() * user_agents.length); 60 | return user_agents[randomIndex]; 61 | } 62 | 63 | #get_user_agent() { 64 | if (this.session_user_agents[this.session_name]) { 65 | return this.session_user_agents[this.session_name]; 66 | } 67 | 68 | logger.info( 69 | `[${this.bot_name}] | ${this.session_name} | Generating new user agent...` 70 | ); 71 | const newUserAgent = this.#get_random_user_agent(); 72 | this.session_user_agents[this.session_name] = newUserAgent; 73 | this.#save_session_data(this.session_user_agents); 74 | return newUserAgent; 75 | } 76 | 77 | #save_session_data(session_user_agents) { 78 | const filePath = path.join(process.cwd(), "session_user_agents.json"); 79 | fs.writeFileSync(filePath, JSON.stringify(session_user_agents, null, 2)); 80 | } 81 | 82 | #get_boost_by_id(data, boostId) { 83 | const boost = data.boostsList.find((boost) => boost.boostId === boostId); 84 | return boost ? boost : {}; 85 | } 86 | 87 | #get_platform(userAgent) { 88 | const platformPatterns = [ 89 | { pattern: /iPhone/i, platform: "ios" }, 90 | { pattern: /Android/i, platform: "android" }, 91 | { pattern: /iPad/i, platform: "ios" }, 92 | ]; 93 | 94 | for (const { pattern, platform } of platformPatterns) { 95 | if (pattern.test(userAgent)) { 96 | return platform; 97 | } 98 | } 99 | 100 | return "Unknown"; 101 | } 102 | 103 | async #get_tg_web_data() { 104 | try { 105 | const tmp = new FdyTmp({ 106 | fileName: `${this.bot_name}.fdy.tmp`, 107 | tmpPath: path.join(process.cwd(), "cache/queries"), 108 | }); 109 | if (tmp.hasJsonElement(this.session_name)) { 110 | const queryStringFromCache = tmp.getJson(this.session_name); 111 | if (!_.isEmpty(queryStringFromCache)) { 112 | this.headers["authorization"] = `tma ${queryStringFromCache}`; 113 | const va_hc = fdy.create({ 114 | headers: this.headers, 115 | }); 116 | 117 | const validate = await this.api.validate(va_hc); 118 | 119 | if (validate) { 120 | logger.info( 121 | `[${this.bot_name}] | ${this.session_name} | 🔄 Getting data from cache...` 122 | ); 123 | if (this.tg_client.connected) { 124 | await this.tg_client.disconnect(); 125 | await this.tg_client.destroy(); 126 | } 127 | await sleep(5); 128 | return queryStringFromCache; 129 | } else { 130 | tmp.deleteJsonElement(this.session_name); 131 | } 132 | } 133 | } 134 | await this.tg_client.connect(); 135 | await this.tg_client.start(); 136 | const platform = this.#get_platform(this.#get_user_agent()); 137 | 138 | if (!this.bot) { 139 | this.bot = await this.tg_client.getInputEntity(app.bot); 140 | } 141 | 142 | if (!this.runOnce) { 143 | logger.info( 144 | `[${this.bot_name}] | ${this.session_name} | 📡 Waiting for authorization...` 145 | ); 146 | const botHistory = await this.tg_client.invoke( 147 | new Api.messages.GetHistory({ 148 | peer: this.bot, 149 | limit: 10, 150 | }) 151 | ); 152 | if (botHistory.messages.length < 1) { 153 | await this.tg_client.invoke( 154 | new Api.messages.SendMessage({ 155 | message: "/start", 156 | silent: true, 157 | noWebpage: true, 158 | peer: this.bot, 159 | }) 160 | ); 161 | } 162 | } 163 | 164 | await sleep(5); 165 | 166 | const result = await this.tg_client.invoke( 167 | new Api.messages.RequestWebView({ 168 | peer: this.bot, 169 | bot: this.bot, 170 | platform, 171 | from_bot_menu: true, 172 | url: app.webviewUrl, 173 | }) 174 | ); 175 | 176 | const authUrl = result.url; 177 | const tgWebData = authUrl.split("#", 2)[1]; 178 | logger.info( 179 | `[${this.bot_name}] | ${this.session_name} | 💾 Storing data in cache...` 180 | ); 181 | 182 | await sleep(5); 183 | 184 | tmp 185 | .addJson( 186 | this.session_name, 187 | decodeURIComponent(this.#clean_tg_web_data(tgWebData)) 188 | ) 189 | .save(); 190 | return decodeURIComponent(this.#clean_tg_web_data(tgWebData)); 191 | } catch (error) { 192 | if (error.message.includes("AUTH_KEY_DUPLICATED")) { 193 | logger.error( 194 | `[${this.bot_name}] | ${this.session_name} | The same authorization key (session file) was used in more than one place simultaneously. You must delete your session file and create a new session` 195 | ); 196 | return null; 197 | } 198 | const regex = /A wait of (\d+) seconds/; 199 | if ( 200 | error.message.includes("FloodWaitError") || 201 | error.message.match(regex) 202 | ) { 203 | const match = error.message.match(regex); 204 | 205 | if (match) { 206 | this.sleep_floodwait = 207 | new Date().getTime() / 1000 + parseInt(match[1], 10) + 10; 208 | } else { 209 | this.sleep_floodwait = new Date().getTime() / 1000 + 50; 210 | } 211 | logger.error( 212 | `[${this.bot_name}] | ${ 213 | this.session_name 214 | } | Some flood error, waiting ${ 215 | this.sleep_floodwait - new Date().getTime() / 1000 216 | } seconds to try again...` 217 | ); 218 | } else { 219 | logger.error( 220 | `[${this.bot_name}] | ${this.session_name} | ❗️Unknown error during Authorization: ${error}` 221 | ); 222 | } 223 | return null; 224 | } finally { 225 | if (this.tg_client.connected) { 226 | await this.tg_client.disconnect(); 227 | await this.tg_client.destroy(); 228 | } 229 | this.runOnce = true; 230 | if (this.sleep_floodwait > new Date().getTime() / 1000) { 231 | await sleep(this.sleep_floodwait - new Date().getTime() / 1000); 232 | return await this.#get_tg_web_data(); 233 | } 234 | await sleep(3); 235 | } 236 | } 237 | 238 | async #check_proxy(http_client, proxy) { 239 | try { 240 | const response = await http_client.get("https://httpbin.org/ip"); 241 | const ip = response.data.origin; 242 | logger.info( 243 | `[${this.bot_name}] | ${this.session_name} | Proxy IP: ${ip}` 244 | ); 245 | } catch (error) { 246 | logger.error( 247 | `[${this.bot_name}] | ${this.session_name} | Error: Unable to resolve the proxy address. The proxy server at ${proxy?.ip}:${proxy?.port} could not be found. Please check the proxy address and your network connection.` 248 | ); 249 | logger.error( 250 | `[${this.bot_name}] | ${this.session_name} | No proxy will be used.` 251 | ); 252 | logger.error( 253 | `[${this.bot_name}] | ${this.session_name} | Error message: ${error?.message}` 254 | ); 255 | 256 | return false; 257 | } 258 | } 259 | 260 | async #get_user_data(http_client) { 261 | let profile_data = false; 262 | while (typeof profile_data === "boolean" && !profile_data) { 263 | profile_data = await this.api.get_user_data(http_client); 264 | if (profile_data === false) { 265 | logger.warning( 266 | `[${this.bot_name}] | ${this.session_name} | Unable to get user data. Retrying...` 267 | ); 268 | await sleep(5); 269 | continue; 270 | } 271 | 272 | if (_.isNull(profile_data) || _.isEmpty(profile_data)) { 273 | logger.warning( 274 | `[${this.bot_name}] | ${this.session_name} | Error while getting user data. Aborting...` 275 | ); 276 | break; 277 | } 278 | 279 | return profile_data; 280 | } 281 | return null; 282 | } 283 | 284 | async run(proxy) { 285 | let http_client; 286 | let access_token_created_time = 0; 287 | 288 | let profile_data, boosts_list; 289 | let sleep_daily_reward = 0; 290 | let tasks_list = {}; 291 | let config = {}; 292 | let get_daily_sync_info = {}; 293 | let mine_sync = []; 294 | let exceeded_energy = 0; 295 | let exceeded_turbo = 0; 296 | let sleep_empty_energy = 0; 297 | 298 | if (settings.USE_PROXY_FROM_FILE && proxy) { 299 | http_client = fdy.create({ 300 | headers: this.headers, 301 | proxy, 302 | }); 303 | const proxy_result = await this.#check_proxy(http_client, proxy); 304 | if (!proxy_result) { 305 | http_client = fdy.create({ 306 | headers: this.headers, 307 | }); 308 | } 309 | } else { 310 | http_client = fdy.create({ 311 | headers: this.headers, 312 | }); 313 | } 314 | 315 | while (true) { 316 | try { 317 | const currentTime = _.floor(Date.now() / 1000); 318 | if (currentTime - access_token_created_time >= 14400) { 319 | http_client.defaults.headers["sec-ch-ua-platform"] = 320 | this.#get_platform(this.#get_user_agent()); 321 | 322 | const tg_web_data = await this.#get_tg_web_data(); 323 | 324 | if ( 325 | _.isNull(tg_web_data) || 326 | _.isUndefined(tg_web_data) || 327 | !tg_web_data || 328 | _.isEmpty(tg_web_data) 329 | ) { 330 | await sleep(5); 331 | continue; 332 | } 333 | 334 | http_client.defaults.headers["authorization"] = `tma ${tg_web_data}`; 335 | 336 | access_token_created_time = currentTime; 337 | await sleep(5); 338 | } 339 | // Get profile data 340 | profile_data = await this.#get_user_data(http_client); 341 | boosts_list = await this.api.get_boosts(http_client); 342 | tasks_list = await this.api.tasks(http_client); 343 | config = await this.api.config(http_client); 344 | mine_sync = await this.api.mine_sync(http_client); 345 | get_daily_sync_info = await this.api.get_daily_sync_info(http_client); 346 | 347 | if ( 348 | _.isEmpty(profile_data) || 349 | profile_data?.status?.toLowerCase() !== "ok" 350 | ) { 351 | access_token_created_time = 0; 352 | await sleep(5); 353 | 354 | continue; 355 | } 356 | 357 | if (!profile_data?.initAccount || _.isEmpty(profile_data?.account)) { 358 | await this.api.init_account(http_client); 359 | await this.api.sponsor(http_client); 360 | continue; 361 | } 362 | 363 | if (profile_data?.account?.sponsor == "") { 364 | await this.api.sponsor(http_client); 365 | continue; 366 | } 367 | 368 | await sleep(2); 369 | 370 | if (profile_data?.clicker?.lastPassiveEarn > 0) { 371 | logger.info( 372 | `[${this.bot_name}] | ${this.session_name} | 💸 Last passive earn: +${profile_data?.clicker?.lastPassiveEarn} | Earn per hour: ${profile_data?.clicker?.earnPassivePerHour}` 373 | ); 374 | } 375 | 376 | // Daily reward 377 | if (settings.AUTO_CLAIM_REWARD && sleep_daily_reward <= currentTime) { 378 | const reward_data = await this.api.daily_reward(http_client); 379 | 380 | if ( 381 | typeof reward_data === "string" && 382 | reward_data.includes("not_subscribed") 383 | ) { 384 | logger.info( 385 | `[${this.bot_name}] | ${this.session_name} |⌛Joining RockyRabit channel before claiming daily reward...` 386 | ); 387 | await this.tg_client.invoke( 388 | new Api.channels.JoinChannel({ 389 | channel: await this.tg_client.getInputEntity( 390 | app.rockyRabitChannel 391 | ), 392 | }) 393 | ); 394 | continue; 395 | } else if ( 396 | typeof reward_data === "string" && 397 | reward_data.includes("claimed") 398 | ) { 399 | sleep_daily_reward = 400 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000; 401 | logger.info( 402 | `[${this.bot_name}] | ${this.session_name} | 🚶 Daily reward already claimed. Skipping...` 403 | ); 404 | } else if (reward_data?.status?.toLowerCase() === "ok") { 405 | profile_data = await this.#get_user_data(http_client); 406 | logger.info( 407 | `[${this.bot_name}] | ${this.session_name} | 🎉 Claimed daily reward successfully | Reward: ${reward_data?.task?.rewardCoins} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 408 | ); 409 | sleep_daily_reward = 410 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000; 411 | } 412 | } 413 | 414 | await sleep(1); 415 | 416 | //Send taps 417 | if (settings.RANDOM_TAPS_COUNT[0] > settings.RANDOM_TAPS_COUNT[1]) { 418 | logger.error( 419 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN must be less than RANDOM_TAPS_COUNT MAX. Example: RANDOM_TAPS_COUNT: [10, 20]` 420 | ); 421 | process.exit(1); 422 | } 423 | if ( 424 | !_.isInteger(settings.RANDOM_TAPS_COUNT[0]) || 425 | !_.isInteger(settings.RANDOM_TAPS_COUNT[1]) 426 | ) { 427 | logger.error( 428 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN and MAX must be integers/numbers. Example: RANDOM_TAPS_COUNT: [10, 20]` 429 | ); 430 | process.exit(1); 431 | } 432 | let taps_sent_count = 0; 433 | if (sleep_empty_energy <= currentTime) { 434 | while ( 435 | profile_data?.clicker?.availableTaps > 436 | settings.MIN_AVAILABLE_ENERGY && 437 | taps_sent_count < 10 438 | ) { 439 | await sleep(_.random(5, 15)); 440 | let taps = _.random( 441 | settings.RANDOM_TAPS_COUNT[0], 442 | settings.RANDOM_TAPS_COUNT[1] 443 | ); 444 | boosts_list = await this.api.get_boosts(http_client); 445 | if ( 446 | !moment(exceeded_turbo * 1000).isSame(new Date().getTime(), "day") 447 | ) { 448 | const turbo_data = this.#get_boost_by_id(boosts_list, "turbo"); 449 | 450 | const turbo_boost = await this.api.upgrade_boost(http_client, { 451 | boostId: turbo_data?.boostId, 452 | timezone: app.timezone, 453 | }); 454 | 455 | if (turbo_boost?.status?.toLowerCase() === "ok") { 456 | logger.info( 457 | `[${this.bot_name}] | ${this.session_name} | ⏩ Turbo boost activated.` 458 | ); 459 | await sleep(5); 460 | } else if ( 461 | typeof turbo_boost == "string" && 462 | turbo_boost.includes("exceeded") 463 | ) { 464 | exceeded_turbo = currentTime; 465 | } 466 | } 467 | 468 | const taps_can_send = 469 | profile_data?.clicker?.availableTaps / 470 | profile_data?.clicker?.earnPerTap; 471 | const count = 472 | taps > _.floor(taps_can_send) ? _.floor(taps_can_send) : taps; 473 | const taps_result = await this.api.taps(http_client, { count }); 474 | 475 | if (taps_result?.status?.toLowerCase() === "ok") { 476 | const balanceChange = 477 | taps_result?.clicker?.balance - profile_data?.clicker?.balance; 478 | profile_data = await this.#get_user_data(http_client); 479 | logger.info( 480 | `[${this.bot_name}] | ${this.session_name} | ✅ Taps sent successfully | Balance: ${profile_data?.clicker?.balance} (+${balanceChange}) | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 481 | ); 482 | } 483 | 484 | profile_data = await this.#get_user_data(http_client); 485 | boosts_list = await this.api.get_boosts(http_client); 486 | 487 | if ( 488 | profile_data?.clicker?.availableTaps <= 489 | settings.MIN_AVAILABLE_ENERGY 490 | ) { 491 | if (_.isEmpty(boosts_list)) { 492 | break; 493 | } 494 | const full_taps_data = this.#get_boost_by_id( 495 | boosts_list, 496 | "full-available-taps" 497 | ); 498 | if (_.isEmpty(full_taps_data)) { 499 | break; 500 | } 501 | 502 | if ( 503 | full_taps_data?.lastUpgradeAt + 3605 <= currentTime && 504 | settings.APPLY_DAILY_FULL_ENERGY && 505 | !moment(exceeded_energy * 1000).isSame( 506 | new Date().getTime(), 507 | "day" 508 | ) 509 | ) { 510 | const full_energy_boost = await this.api.upgrade_boost( 511 | http_client, 512 | { 513 | boostId: full_taps_data?.boostId, 514 | timezone: app.timezone, 515 | } 516 | ); 517 | 518 | if ( 519 | typeof full_energy_boost == "string" && 520 | full_energy_boost.includes("exceeded") 521 | ) { 522 | exceeded_energy = currentTime; 523 | break; 524 | } 525 | 526 | if (full_energy_boost?.status?.toLowerCase() === "ok") { 527 | profile_data = await this.#get_user_data(http_client); 528 | logger.info( 529 | `[${this.bot_name}] | ${this.session_name} | 🔋Full energy boost applied successfully` 530 | ); 531 | } 532 | } else { 533 | profile_data = await this.#get_user_data(http_client); 534 | sleep_empty_energy = currentTime + settings.SLEEP_EMPTY_ENERGY; 535 | 536 | logger.info( 537 | `[${this.bot_name}] | ${ 538 | this.session_name 539 | } | Not enough energy to send ${count} taps. Needed ${ 540 | count * profile_data?.clicker?.earnPerTap 541 | } energy to send taps | Available: ${ 542 | profile_data?.clicker?.availableTaps 543 | } | Sleeping ${settings.SLEEP_EMPTY_ENERGY}s` 544 | ); 545 | break; 546 | } 547 | } 548 | 549 | taps_sent_count++; 550 | } 551 | } 552 | 553 | await sleep(2); 554 | 555 | // Daily combos 556 | const combo_data = await this.api.get_combo_data(http_client); 557 | if (!_.isEmpty(combo_data)) { 558 | const expireAtForCards = 559 | new Date(combo_data?.expireAtForCards).getTime() / 1000; 560 | 561 | const expireAtForEaster = 562 | new Date(combo_data?.expireAtForEaster).getTime() / 1000; 563 | 564 | if ( 565 | settings.AUTO_PLAY_ENIGMA && 566 | !_.isEmpty(combo_data?.enigma) && 567 | !_.isEmpty(get_daily_sync_info) 568 | ) { 569 | const play_enigma_data = get_daily_sync_info?.enigma; 570 | 571 | if ( 572 | play_enigma_data?.completedAt < 1 && 573 | Array.isArray(combo_data?.enigma) && 574 | play_enigma_data?.passphrase?.includes(combo_data?.enigma[0]) 575 | ) { 576 | const play_enigma = await this.api.play_enigma(http_client, { 577 | passphrase: Array.isArray(combo_data?.enigma) 578 | ? combo_data.enigma.join(",") 579 | : combo_data.enigma, 580 | enigmaId: play_enigma_data?.enigmaId, 581 | }); 582 | 583 | if (play_enigma?.status?.toLowerCase() === "ok") { 584 | profile_data = await this.#get_user_data(http_client); 585 | logger.info( 586 | `[${this.bot_name}] | ${this.session_name} | 🎊 Enigma claimed successfully | Reward: ${play_enigma_data?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 587 | ); 588 | } 589 | } 590 | } 591 | 592 | if ( 593 | settings.AUTO_PLAY_COMBO && 594 | !_.isEmpty(combo_data?.cards) && 595 | !_.isEmpty(get_daily_sync_info) 596 | ) { 597 | const combo_info = get_daily_sync_info?.superSet; 598 | 599 | if (combo_info?.completedAt < 1 && expireAtForCards > currentTime) { 600 | const play_combo = await this.api.play_combo(http_client, { 601 | combos: Array.isArray(combo_data?.cards) 602 | ? combo_data?.cards.join(",") 603 | : combo_data?.cards, 604 | comboId: combo_info?.comboId, 605 | }); 606 | 607 | if (play_combo?.status?.toLowerCase() === "ok") { 608 | profile_data = await this.#get_user_data(http_client); 609 | logger.info( 610 | `[${this.bot_name}] | ${this.session_name} | 🎊 Daily combo claimed successfully | Reward: ${play_combo?.winner?.rabbitWinner} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 611 | ); 612 | } 613 | } 614 | } 615 | 616 | if ( 617 | settings.AUTO_CLAIM_EASTER_EGG && 618 | !_.isEmpty(combo_data?.easter) && 619 | !_.isEmpty(get_daily_sync_info?.easterEggs) 620 | ) { 621 | const easter_info = get_daily_sync_info?.easterEggs; 622 | 623 | if ( 624 | easter_info?.completedAt < 1 && 625 | expireAtForEaster > currentTime 626 | ) { 627 | const play_easter = await this.api.play_easter(http_client, { 628 | easter: combo_data?.easter, 629 | easterEggsId: easter_info?.easterEggsId, 630 | }); 631 | 632 | if (play_easter?.status?.toLowerCase() === "ok") { 633 | profile_data = await this.#get_user_data(http_client); 634 | logger.info( 635 | `[${this.bot_name}] | ${this.session_name} | 🎊 Easter Egg claimed successfully | Reward: ${easter_info?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}` 636 | ); 637 | } 638 | } 639 | } 640 | } 641 | 642 | await sleep(3); 643 | 644 | // Boost upgrade (earn-per-tap) 645 | const tap_boost_data = this.#get_boost_by_id( 646 | boosts_list, 647 | "earn-per-tap" 648 | ); 649 | if ( 650 | settings.AUTO_UPGRADE_TAP && 651 | !_.isEmpty(tap_boost_data) && 652 | settings.MAX_TAP_LEVEL > tap_boost_data?.level && 653 | tap_boost_data?.price <= profile_data?.clicker?.balance 654 | ) { 655 | const tap_boost = await this.api.upgrade_boost(http_client, { 656 | boostId: tap_boost_data?.boostId, 657 | timezone: app.timezone, 658 | }); 659 | 660 | if (tap_boost?.status?.toLowerCase() === "ok") { 661 | profile_data = await this.#get_user_data(http_client); 662 | logger.info( 663 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Tap upgraded successfully | Level: ${tap_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 664 | ); 665 | } 666 | } 667 | await sleep(3); 668 | 669 | // Boost upgrade (max-taps) 670 | const energy_boost_data = this.#get_boost_by_id( 671 | boosts_list, 672 | "max-taps" 673 | ); 674 | 675 | if ( 676 | settings.AUTO_UPGRADE_ENERGY_LIMIT && 677 | !_.isEmpty(energy_boost_data) && 678 | settings.MAX_ENERGY_LIMIT_LEVEL > energy_boost_data?.level && 679 | energy_boost_data?.price <= profile_data?.clicker?.balance 680 | ) { 681 | const energy_boost = await this.api.upgrade_boost(http_client, { 682 | boostId: energy_boost_data?.boostId, 683 | timezone: app.timezone, 684 | }); 685 | if (energy_boost?.status?.toLowerCase() === "ok") { 686 | profile_data = await this.#get_user_data(http_client); 687 | logger.info( 688 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Energy limit upgraded successfully | Level: ${energy_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 689 | ); 690 | } 691 | } 692 | 693 | await sleep(3); 694 | 695 | // Boost upgrade (hourly-income-limit) 696 | const hourly_limit_data = this.#get_boost_by_id( 697 | boosts_list, 698 | "hourly-income-limit" 699 | ); 700 | 701 | if ( 702 | settings.AUTO_HOURLY_LIMIT && 703 | !_.isEmpty(hourly_limit_data) && 704 | settings.MAX_HOURLY_LIMIT_LEVEL > hourly_limit_data?.level && 705 | hourly_limit_data?.price <= profile_data?.clicker?.balance 706 | ) { 707 | const hourly_limit = await this.api.upgrade_boost(http_client, { 708 | boostId: hourly_limit_data?.boostId, 709 | timezone: app.timezone, 710 | }); 711 | if (hourly_limit?.status?.toLowerCase() === "ok") { 712 | profile_data = await this.#get_user_data(http_client); 713 | logger.info( 714 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Hourly limit upgraded successfully | Level: ${hourly_limit_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance} | Available energy: ${profile_data?.clicker?.availableTaps}` 715 | ); 716 | } 717 | } 718 | 719 | if (settings.AUTO_COMPLETE_TASKS) { 720 | await sleep(2); 721 | 722 | if (!_.isEmpty(tasks_list) && !_.isEmpty(tasks_list.tasks)) { 723 | const uncompletedTasks = filterArray.getUncompletedTasks( 724 | tasks_list.tasks 725 | ); 726 | 727 | if (!_.isEmpty(uncompletedTasks)) { 728 | for (const task of uncompletedTasks) { 729 | const complete_task = await this.api.claim_task(http_client, { 730 | taskId: task?.id, 731 | timezone: app.timezone, 732 | }); 733 | if (complete_task?.status?.toLowerCase() === "ok") { 734 | logger.info( 735 | `[${this.bot_name}] | ${this.session_name} | ✔️ Task completed successfully | Task title: ${task?.name} | Reward: ${task?.rewardCoins}` 736 | ); 737 | } else { 738 | logger.error( 739 | `[${this.bot_name}] | ${this.session_name} | ✖️ Could not complete task | Task title: ${task?.name} | Reward: ${task?.rewardCoins}` 740 | ); 741 | } 742 | } 743 | } 744 | } 745 | } 746 | 747 | if (settings.AUTO_UPGRADE_CARD) { 748 | if ( 749 | _.isEmpty(config?.config) || 750 | _.isEmpty(config?.config?.upgrade) || 751 | _.isEmpty(mine_sync) 752 | ) { 753 | continue; 754 | } 755 | 756 | const leagues = Array.from( 757 | { length: 10 }, 758 | (_, i) => filterArray.getById(mine_sync, `league_${i + 1}`)[0] 759 | ); 760 | 761 | if (leagues.some((league) => _.isEmpty(league))) { 762 | continue; 763 | } 764 | 765 | const cards_fighter = filterArray.getCardsOnUpgradeTab( 766 | config?.config?.upgrade, 767 | "fighter", 768 | "upgrade" 769 | ); 770 | const cards_coach = filterArray.getCardsOnUpgradeTab( 771 | config?.config?.upgrade, 772 | "coach", 773 | "upgrade" 774 | ); 775 | 776 | if (_.isEmpty(cards_fighter) || _.isEmpty(cards_coach)) { 777 | continue; 778 | } 779 | 780 | for (let i = 0; i < leagues.length; i++) { 781 | const allPreviousLeaguesCompleted = 782 | i === 0 || 783 | leagues 784 | .slice(0, i) 785 | .every((league) => league?.isCompleted === true); 786 | 787 | if ( 788 | leagues[i]?.isCompleted === false && 789 | allPreviousLeaguesCompleted 790 | ) { 791 | const level = i + 1; 792 | const cards_fighter_level = filterArray.getCardsWithLevel( 793 | mine_sync, 794 | cards_fighter, 795 | level 796 | ); 797 | const cards_coach_level = filterArray.getCardsWithLevel( 798 | mine_sync, 799 | cards_coach, 800 | level 801 | ); 802 | 803 | if (!_.isEmpty(cards_fighter_level)) { 804 | await upgradeTabCardsBuying( 805 | cards_fighter_level, 806 | http_client, 807 | this.api, 808 | this.session_name, 809 | this.bot_name 810 | ); 811 | mine_sync = await this.api.mine_sync(http_client); 812 | continue; 813 | } else if (!_.isEmpty(cards_coach_level)) { 814 | await upgradeTabCardsBuying( 815 | cards_coach_level, 816 | http_client, 817 | this.api, 818 | this.session_name, 819 | this.bot_name 820 | ); 821 | mine_sync = await this.api.mine_sync(http_client); 822 | continue; 823 | } 824 | 825 | if (leagues[i]?.price <= profile_data?.clicker?.balance) { 826 | const upgrade_league = await this.api.upgrade_cards( 827 | http_client, 828 | { 829 | upgradeId: `league_${level}`, 830 | } 831 | ); 832 | 833 | if (upgrade_league?.status?.toLowerCase() === "ok") { 834 | profile_data = await this.#get_user_data(http_client); 835 | 836 | logger.info( 837 | `[${this.bot_name}] | ${this.session_name} | ⬆️ League_${level} upgraded successfully | Level: ${leagues[i]?.level} | Cost: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}` 838 | ); 839 | } 840 | } else { 841 | logger.info( 842 | `[${this.bot_name}] | ${this.session_name} | 👎 Not enough balance to upgrade league ${level} | Need: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}` 843 | ); 844 | continue; 845 | } 846 | } 847 | } 848 | 849 | await sleep(2); 850 | 851 | // get cards with no conditions 852 | const cards_wnc = filterArray.getEmptyConditions( 853 | config?.config?.upgrade 854 | ); 855 | 856 | await upgradeNoConditionCards( 857 | cards_wnc, 858 | this.api, 859 | http_client, 860 | this.session_name, 861 | this.bot_name 862 | ); 863 | } 864 | } catch (error) { 865 | // traceback(error); 866 | logger.error( 867 | `[${this.bot_name}] | ${this.session_name} | ❗️Unknown error: ${error}}` 868 | ); 869 | } finally { 870 | let ran_sleep; 871 | if (_isArray(settings.SLEEP_BETWEEN_TAP)) { 872 | if ( 873 | _.isInteger(settings.SLEEP_BETWEEN_TAP[0]) && 874 | _.isInteger(settings.SLEEP_BETWEEN_TAP[1]) 875 | ) { 876 | ran_sleep = _.random( 877 | settings.SLEEP_BETWEEN_TAP[0], 878 | settings.SLEEP_BETWEEN_TAP[1] 879 | ); 880 | } else { 881 | ran_sleep = _.random(450, 800); 882 | } 883 | } else if (_.isInteger(settings.SLEEP_BETWEEN_TAP)) { 884 | const ran_add = _.random(20, 50); 885 | ran_sleep = settings.SLEEP_BETWEEN_TAP + ran_add; 886 | } else { 887 | ran_sleep = _.random(450, 800); 888 | } 889 | 890 | logger.info( 891 | `[${this.bot_name}] | ${this.session_name} | Sleeping for ${ran_sleep} seconds...` 892 | ); 893 | await sleep(ran_sleep); 894 | } 895 | } 896 | } 897 | } 898 | module.exports = Tapper; 899 | --------------------------------------------------------------------------------