UNPKG

zixineabra

Version:

A Telegram utility bot for managing sessions, logging in accounts, and retrieving WebView data.

845 lines (779 loc) 25 kB
const axios = require("axios"); const fs = require("fs"); const path = require("path"); const colors = require("colors"); const readline = require("readline"); const { DateTime } = require("luxon"); const { Mutex } = require("async-mutex"); const { Worker, isMainThread, parentPort, workerData, } = require("worker_threads"); const fakeUserAgent = require("fake-useragent"); const log = require("loglevel"); const prefix = require("loglevel-plugin-prefix"); const printBanner = require("./banner/galkurta-banner.js"); printBanner(); const consoleMutex = new Mutex(); prefix.reg(log); prefix.apply(log, { format(level, name, timestamp) { return `${timestamp} [${level}]`; }, }); colors.setTheme({ debug: "cyan", info: "blue", warn: "yellow", error: "red", }); const LOG_LEVELS = { DEBUG: "debug", INFO: "info", SUCCESS: "info", WARNING: "warn", ERROR: "error", }; class GameBot { constructor(threadNumber) { this.threadNumber = threadNumber; this.queryId = null; this.token = null; this.userInfo = null; this.currentGameId = null; this.username = null; this.userAgent = this.getRandomUserAgent(); this.excludedTasksFile = path.join(__dirname, "excludedTasks.json"); this.logger = log.getLogger(`Thread-${threadNumber}`); this.logger.setLevel("trace"); this.excludedTasks = this.loadExcludedTasks(); } getRandomUserAgent() { return fakeUserAgent(); } loadExcludedTasks() { if (fs.existsSync(this.excludedTasksFile)) { const data = fs.readFileSync(this.excludedTasksFile, "utf8"); return JSON.parse(data); } return []; } async randomDelay() { const delay = Math.floor(Math.random() * (5000 - 3000 + 1)) + 3000; return new Promise((resolve) => setTimeout(resolve, delay)); } async log(msg, level = "INFO", additionalInfo = "") { const logLevel = LOG_LEVELS[level] || LOG_LEVELS.INFO; let coloredLevel; switch (level) { case "SUCCESS": coloredLevel = level.green; break; case "ERROR": coloredLevel = level.red; break; case "WARNING": coloredLevel = level.yellow; break; case "DEBUG": coloredLevel = level.cyan; break; default: coloredLevel = level.blue; } const timestamp = new Date().toLocaleTimeString(); const usernameDisplay = this.username ? this.username.padEnd(12) : "".padEnd(12); const logMessage = `${timestamp} | ${coloredLevel.padEnd( 7 )} | ${this.threadNumber .toString() .padStart(2, "0")} | ${usernameDisplay} | ${msg} ${additionalInfo}`; await consoleMutex.runExclusive(() => { this.logger[logLevel](logMessage); }); await this.randomDelay(); } headers(token = null) { const headers = { Accept: "application/json, text/plain, */*", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.6", "Content-Type": "application/json", Origin: "https://major.glados.app/reward", Referer: "https://major.glados.app/", "Sec-Ch-Ua": '"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"', "Sec-Ch-Ua-Mobile": "?0", "Sec-Ch-Ua-Platform": '"Windows"', "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Site": "same-origin", "User-Agent": this.userAgent, }; if (token) { headers["Authorization"] = `Bearer ${token}`; } return headers; } async getNewToken() { const url = "https://user-domain.blum.codes/api/v1/auth/provider/PROVIDER_TELEGRAM_MINI_APP"; const data = JSON.stringify({ query: this.queryId, referralToken: "" }); for (let attempt = 1; attempt <= 3; attempt++) { try { await this.randomDelay(); const response = await axios.post(url, data, { headers: await this.headers(), }); if (response.status === 200) { this.token = response.data.token.refresh; await this.log("Login successful", "SUCCESS"); return this.token; } else { await this.log(JSON.stringify(response.data), "WARNING"); await this.log( `Failed to get token, retrying attempt ${attempt}`, "WARNING" ); } } catch (error) { if (error.response && error.response.status) { await this.log( `Failed to get token, retrying attempt ${attempt}: Request failed with status ${error.response.status}`, "ERROR" ); } else { await this.log( `Failed to get token, retrying attempt ${attempt}: ${error.message}`, "ERROR" ); } await this.log(error.toString(), "DEBUG"); } } await this.log("Failed to get token after 3 attempts.", "ERROR"); return null; } async getUserInfo() { try { await this.randomDelay(); const response = await axios.get( "https://user-domain.blum.codes/api/v1/user/me", { headers: await this.headers(this.token) } ); if (response.status === 200) { this.userInfo = response.data; this.username = this.userInfo.username; return this.userInfo; } else { const result = response.data; if (result.message === "Token is invalid") { await this.log("Invalid token, getting new token...", "WARNING"); const newToken = await this.getNewToken(); if (newToken) { await this.log("Got new token, retrying...", "INFO"); return this.getUserInfo(); } else { await this.log("Failed to get new token.", "ERROR"); return null; } } else { await this.log("Unable to get user info", "ERROR"); return null; } } } catch (error) { await this.log(`Unable to get user info: ${error.message}`, "ERROR"); return null; } } async getBalance() { try { await this.randomDelay(); const response = await axios.get( "https://game-domain.blum.codes/api/v1/user/balance", { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log(`Unable to get balance info: ${error.message}`, "ERROR"); return null; } } async getTasks() { try { await this.randomDelay(); const response = await axios.get( "https://earn-domain.blum.codes/api/v1/tasks", { headers: await this.headers(this.token) } ); if (response.status === 200) { return response.data; } else { await this.log("Unable to get task list", "ERROR"); return []; } } catch (error) { await this.log(`Unable to get task list: ${error.message}`, "ERROR"); return []; } } async postValidateTask(gameId, keyAnswer) { const urlStart = `https://earn-domain.blum.codes/api/v1/tasks/${gameId}/start`; const urlValidate = `https://earn-domain.blum.codes/api/v1/tasks/${gameId}/validate`; const data = { keyword: `${keyAnswer}` }; try { await this.randomDelay(); const startResponse = await axios.post( urlStart, {}, { headers: await this.headers(this.token) } ); if (startResponse.status === 200) { try { await this.randomDelay(); const validateResponse = await axios.post(urlValidate, data, { headers: await this.headers(this.token), }); if(validateResponse.status == 200) { await this.log(`Success Task ${gameId} and answer ${keyAnswer}`,"SUCCESS"); } return validateResponse.data; } catch (error) { return null; } } else { try { await this.randomDelay(); const validateResponse = await axios.post(urlValidate, data, { headers: await this.headers(this.token), }); if(validateResponse.status == 200) { await this.log(`Success Task ${gameId} and answer ${keyAnswer}`,"SUCCESS"); } return validateResponse.data; } catch (validateError) { return null; } } } catch (error) { try { await this.randomDelay(); const validateResponse = await axios.post(urlValidate, data, { headers: await this.headers(this.token), }); if(validateResponse.status == 200) { await this.log(`Success Task ${gameId} and answer ${keyAnswer}`,"SUCCESS"); } return validateResponse.data; } catch (validateError) { return null; } } } async taskNoAnswer(gameId) { const urlStart = `https://earn-domain.blum.codes/api/v1/tasks/${gameId}/start`; try { await this.randomDelay(); const validateClaim = await axios.post( urlStart, {}, { headers: await this.headers(this.token) } ); await this.log(`Success Task ${gameId}`, "SUCCESS"); return validateClaim.data; } catch (error) { const errorMessage = `Unable to validate task: ${error.message}`; await this.log(errorMessage, "ERROR"); if (error.response) { await this.log( `Validate response error: ${JSON.stringify(error.response.data)}`, "ERROR" ); } return null; } } async claimTaskAll(gameId) { const urlClaim = `https://earn-domain.blum.codes/api/v1/tasks/${gameId}/claim`; try { await this.randomDelay(); const validateClaim = await axios.post( urlClaim, {}, { headers: await this.headers(this.token) } ); if(validateClaim.status == 200) { await this.log(`Success Task ${gameId} claim`, "SUCCESS"); } return validateClaim.data; } catch (error) { const errorMessage = `Unable to validate task: ${error.message}`; await this.log(errorMessage, "ERROR"); if (error.response) { await this.log( `Validate response error: ${JSON.stringify(error.response.data)}`, "ERROR" ); } return null; } } async getConfigTaskAnswer() { const answerKeyword = `https://raw.githubusercontent.com/bimakhr/blum-answer/refs/heads/main/answer.json` try { await this.randomDelay(); const getResponse = await axios.get(answerKeyword); if (getResponse.status === 200) { const data = getResponse.data; if (Array.isArray(data)) { return data; } else { return []; } } else { return []; } } catch(error) { return []; } } async startTask(taskId) { try { await this.randomDelay(); const response = await axios.post( `https://game-domain.blum.codes/api/v1/tasks/${taskId}/start`, {}, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { return null; } } async claimTask(taskId) { try { await this.randomDelay(); const response = await axios.post( `https://game-domain.blum.codes/api/v1/tasks/${taskId}/claim`, {}, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { return null; } } async playGame() { const data = JSON.stringify({ game: "example_game" }); try { await this.randomDelay(); const response = await axios.post( "https://game-domain.blum.codes/api/v1/game/play", data, { headers: await this.headers(this.token) } ); if (response.status === 200) { this.currentGameId = response.data.gameId; return response.data; } else { await this.log("Unable to play game", "ERROR"); return null; } } catch (error) { await this.log(`Unable to play game: ${error.message}`, "ERROR"); return null; } } async claimGame(points) { if (!this.currentGameId) { await this.log("No current gameId to claim.", "WARNING"); return null; } const data = JSON.stringify({ gameId: this.currentGameId, points: points }); try { await this.randomDelay(); const response = await axios.post( "https://game-domain.blum.codes/api/v1/game/claim", data, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log(`Unable to claim game reward: ${error.message}`, "ERROR"); await this.log(error.toString(), "DEBUG"); return null; } } async claimBalance() { try { await this.randomDelay(); const response = await axios.post( "https://game-domain.blum.codes/api/v1/farming/claim", {}, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log(`Unable to claim balance: ${error.message}`, "ERROR"); return null; } } async startFarming() { const data = JSON.stringify({ action: "start_farming" }); try { await this.randomDelay(); const response = await axios.post( "https://game-domain.blum.codes/api/v1/farming/start", data, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log(`Unable to start farming: ${error.message}`, "ERROR"); return null; } } async checkBalanceFriend() { try { await this.randomDelay(); const response = await axios.get( `https://user-domain.blum.codes/api/v1/friends/balance`, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log( `Unable to check friend balance: ${error.message}`, "ERROR" ); return null; } } async claimBalanceFriend() { try { await this.randomDelay(); const response = await axios.post( `https://user-domain.blum.codes/api/v1/friends/claim`, {}, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log(`Unable to claim friend balance`, "ERROR"); return null; } } async checkDailyReward() { try { await this.randomDelay(); const response = await axios.post( "https://game-domain.blum.codes/api/v1/daily-reward?offset=-420", {}, { headers: await this.headers(this.token) } ); return response.data; } catch (error) { await this.log( `You have already checked in or unable to check in daily`, "ERROR" ); return null; } } async Countdown(seconds) { for (let i = Math.floor(seconds); i >= 0; i--) { await consoleMutex.runExclusive(() => { readline.cursorTo(process.stdout, 0); process.stdout.write(`Waiting ${i} seconds to continue...`); }); await new Promise((resolve) => setTimeout(resolve, 1000)); } await consoleMutex.runExclusive(() => { readline.cursorTo(process.stdout, 0); readline.clearLine(process.stdout, 0); }); } async taskValidate(gameId, keyword) { const url = `https://earn-domain.blum.codes/api/v1/tasks/${gameId}/validate`; const payload = { keyword }; try { await this.randomDelay(); const response = await axios.post(url, payload, { headers: await this.headers(this.token), }); if (response.status === 200) { await this.log("done vaidate", `SUCCESS ${gameId}`); return true; } } catch (error) { return false; } } async joinTribe(tribeId) { const url = `https:///tribe-domain.blum.codes/api/v1/tribe/${tribeId}/join`; try { await this.randomDelay(); const response = await axios.post( url, {}, { headers: await this.headers(this.token) } ); if (response.status === 200) { await this.log("You have successfully joined the tribe", "SUCCESS"); return true; } } catch (error) { if ( error.response && error.response.data && error.response.data.message === "USER_ALREADY_IN_TRIBE" ) { await this.log("You have already joined a tribe", "INFO"); } else { await this.log(`Unable to join tribe: ${error.message}`, "ERROR"); } return false; } } formatNextClaimTime(farming) { if (!farming) return "N/A"; const endTime = DateTime.fromMillis(farming.endTime); return endTime.toFormat("dd/MM/yyyy HH:mm:ss"); } async processAccount(queryId) { this.queryId = queryId; let isCompleted = false; const token = await this.getNewToken(); if (!token) { await this.log("Unable to get token, skipping this account", "ERROR"); return null; } const userInfo = await this.getUserInfo(); if (userInfo === null) { await this.log("Unable to get user info, skipping this account", "ERROR"); return null; } const balanceInfo = await this.getBalance(); if (balanceInfo) { await this.log( `${balanceInfo.availableBalance}`, "SUCCESS", `|Next farming ${this.formatNextClaimTime(balanceInfo.farming)}` ); const tribeId = "6f953956-30d8-48dc-a968-e8a2e562c900"; await this.joinTribe(tribeId); if (!balanceInfo.farming) { const farmingResult = await this.startFarming(); if (farmingResult) { await this.log("Successfully started farming", "SUCCESS"); } } else { const endTime = DateTime.fromMillis(balanceInfo.farming.endTime); const currentTime = DateTime.now(); if (currentTime > endTime) { const claimBalanceResult = await this.claimBalance(); if (claimBalanceResult) { await this.log("Successfully claimed farm", "SUCCESS"); } const farmingResult = await this.startFarming(); if (farmingResult) { await this.log("Successfully started farming", "SUCCESS"); } } else { const timeLeft = endTime.diff(currentTime).toFormat("hh:mm:ss"); await this.log(`Next farming ${timeLeft}`, "INFO"); } } } else { await this.log("Unable to get balance info", "ERROR"); } // Always perform tasks without asking const taskListResponse = await this.getTasks(); if (Array.isArray(taskListResponse) && taskListResponse.length > 0) { const configTask = await this.getConfigTaskAnswer(); if (Array.isArray(configTask) && configTask.length > 0) { for (const taskAns of configTask) { const startResult = await this.postValidateTask(taskAns.id, taskAns.answer); if (startResult) { await this.log("startResult", "INFO"); await this.claimTaskAll(taskAns.id); } } } else { await this.log("No tasks to process or data is not an array", "WARNING"); } let allTasks = taskListResponse.flatMap((section) => section.tasks || []); allTasks = allTasks.filter( (task) => !this.excludedTasks.includes(task.id) ); for (const task of allTasks) { if (task.status === "NOT_STARTED") { const startResult = await this.startTask(task.id); if (startResult) { const claimResult = await this.claimTask(task.id); if (claimResult && claimResult.status === "FINISHED") { await this.log(`Completed task ${task.title}`, "SUCCESS"); } else { await this.log(`Failed to claim task: ${task.title}`, "WARNING"); } } } } } else { await this.log( "Unable to get task list or task list is empty", "WARNING" ); } const dailyRewardResult = await this.checkDailyReward(); if (dailyRewardResult) { await this.log("Claimed daily reward", "SUCCESS"); } const friendBalanceInfo = await this.checkBalanceFriend(); if (friendBalanceInfo) { await this.log( `Friend balance: ${friendBalanceInfo.amountForClaim}`, "INFO" ); if (friendBalanceInfo.amountForClaim > 0) { const claimFriendBalanceResult = await this.claimBalanceFriend(); if (claimFriendBalanceResult) { await this.log("Successfully claimed friend balance", "SUCCESS"); } } else { await this.log("No friend balance to claim", "INFO"); } } else { await this.log("Unable to check friend balance", "ERROR"); } if (balanceInfo && balanceInfo.playPasses > 0) { for (let j = 0; j < balanceInfo.playPasses; j++) { await this.log(`Playing Game: ${j + 1}`, "INFO"); let playAttempts = 0; const maxAttempts = 10; while (playAttempts < maxAttempts) { try { const playResult = await this.playGame(); if (playResult) { await this.Countdown(30); const randomNumber = Math.floor(Math.random() * (200 - 150 + 1)) + 150; const claimGameResult = await this.claimGame(randomNumber); if (claimGameResult) { await this.log( `Successfully claimed game ${ j + 1 } reward with ${randomNumber} points`, "SUCCESS" ); } break; } } catch (error) { playAttempts++; await this.log( `Unable to play game ${j + 1}, attempt ${playAttempts}: ${ error.message }`, "ERROR" ); if (playAttempts < maxAttempts) { await this.log(`Retrying...`, "INFO"); await this.Countdown(5); } else { await this.log( `Failed after ${maxAttempts} attempts, skipping this game`, "ERROR" ); } } } } } else { await this.log("No game passes available", "INFO"); } await this.log(`Finished processing account ${this.username}`, "SUCCESS"); return balanceInfo?.farming?.endTime; } static async askQuestion(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => rl.question(query, (ans) => { rl.close(); resolve(ans); }) ); } } if (isMainThread) { async function main() { const dataFile = path.join(__dirname, "../data/blumCryptobot.txt"); const queryIds = fs .readFileSync(dataFile, "utf8") .replace(/\r/g, "") .split("\n") .filter(Boolean); const threadCountInput = await GameBot.askQuestion( `Enter the number of threads to use (1-${queryIds.length}): ` ); const threadCount = Math.min( Math.max(parseInt(threadCountInput) || 1, 1), queryIds.length ); console.log(`Using ${threadCount} threads for processing.`.yellow); async function runWorker(queryId, threadNumber) { return new Promise((resolve, reject) => { const worker = new Worker(__filename, { workerData: { queryId, threadNumber }, }); worker.on("message", resolve); worker.on("error", reject); worker.on("exit", (code) => { if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`)); }); }); } async function processInBatches() { for (let i = 0; i < queryIds.length; i += threadCount) { const batch = queryIds.slice(i, i + threadCount); await Promise.all( batch.map((queryId, index) => runWorker(queryId, i + index + 1)) ); } } while (true) { console.log("Starting a new round of processing...".green); await processInBatches(); console.log( "All accounts processed. Starting next round immediately.".green ); } } main().catch(console.error); } else { // This code will run in worker threads (async () => { const bot = new GameBot(workerData.threadNumber); const nextClaimTime = await bot.processAccount(workerData.queryId); if (nextClaimTime) { const now = DateTime.now(); const waitTime = DateTime.fromMillis(nextClaimTime).diff(now); if (waitTime.milliseconds > 0) { await bot.log(`Next claim in ${waitTime.toFormat("hh:mm:ss")}`, "INFO"); await new Promise((resolve) => setTimeout(resolve, waitTime.milliseconds) ); } } parentPort.postMessage("done"); })(); }