const { execSync } = require('child_process'); const fs = require('node:fs'); const os = require('os'); const { publicIpv4 } = require('public-ip'); const host = os.hostname(); const args = process.argv.slice(2); async function consoleLog(message, type) { if (type === 'info') { console.log(`\x1b[34m${message}\x1b[0m`); } else if (type === 'error') { console.log(`\x1b[31m${message}\x1b[0m`); } else { console.log(`\x1b[37m${message}\x1b[0m`); } if (process.env.MCR_BOT_WEBHOOK) { const webhook = process.env.MCR_BOT_WEBHOOK; const botUsername = `m${process.env.MCR_BOT_WEBHOOK_NAME}`; const payload = { content: message, username: botUsername, }; try { await fetch(webhook, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }); } catch (error) { console.log('Error sending webhook message:', error.message); } } } async function checkUpdate() { try { execSync('git fetch'); const currentHead = execSync('git rev-parse HEAD').toString().trim(); const remoteHead = execSync('git rev-parse "@{u}"').toString().trim(); if (currentHead !== remoteHead) { consoleLog('Updates available! Please run the updater script.', 'info'); } } catch (error) { consoleLog('Failed to check for updates.', 'error'); } } async function vpnConnect(vpnName) { if (!vpnName) return consoleLog('Please provide the VPN name as an argument.', 'error'); consoleLog(`[${host}] Disconnecting from VPNs`, 'info'); await vpnDisconnect(); const maxAttempts = process.env.RETRIES; for (let attempt = 1; attempt <= maxAttempts; attempt++) { await execSync(`nmcli connection up "${vpnName}"`); const status = await execSync('nmcli connection show --active').toString().includes(vpnName); if (!status) { consoleLog(`[${host}] Failed to connect to VPN: ${vpnName}. Retrying (attempt ${attempt} of ${maxAttempts})...`, 'error'); await sleep(1000); } else { await consoleLog(`[${host}] VPN connection successfully established to ${vpnName} (IP: ${await publicIpv4()}).`, 'info'); return 0; } } consoleLog(`[${host}] Maximum number of connection attempts reached. Failed to connect to VPN: ${vpnName}`, 'error'); await vpnDisconnect(); return 1; } function vpnDisconnect() { const vpnConnection = execSync('nmcli connection show --active | awk \'/vpn/ {print $1}\'').toString().trim(); if (!vpnConnection) { consoleLog(`[${host}] Successfully disconnected from all VPNs.`, 'info'); return 0; } try { execSync(`nmcli connection down "${vpnConnection}"`); const status = execSync('nmcli connection show --active | awk \'/vpn/ {print $1}\'').toString().trim(); if (!status) { consoleLog(`[${host}] Successfully disconnected from all VPNs.`, 'info'); return 0; } else { consoleLog(`[${host}] Failed to disconnect from all VPNs.`, 'error'); return 1; } } catch (error) { consoleLog(`[${host}] Failed to disconnect from all VPNs.`, 'error'); return 1; } } async function startBot(accountName) { const accountPath = `./accounts/${accountName}.json`; if (fs.existsSync(accountPath)) { let commandSuffix = `--discord ${process.env.WEBHOOK}`; if (process.env.PRINT_CONSOLE_LOGS === '1') { commandSuffix += ' --print-to-webhook'; } if (process.env.BOT_BROWSER) { commandSuffix += ' --browser ' + process.env.BOT_BROWSER; } let commandPrefix = `python ./Microsoft-Rewards-bot/ms_rewards_farmer.py --accounts-file ../accounts/${accountName}.json --dont-check-for-updates --shuffle --session --superfast --on-finish exit --no-webdriver-manager --skip-unusual`; consoleLog(`[${host}] Script started for ${accountName}`); if (isRootUser()) { console.log('The user is root.'); const containerEnv = fs.readFileSync('/proc/1/environ', 'utf8'); const isLXCContainer = containerEnv.includes('container=lxc') || containerEnv.includes('container=lxc-libvirt'); if (isLXCContainer) { commandPrefix += ' --virtual-display'; } } try { execSync(`timeout 150m bash -c "${commandPrefix} ${commandSuffix}; exit"`, { stdio: 'inherit', shell: '/bin/bash' }); } catch (error) { consoleLog(`[${host}] Failed to start bot for ${accountName}.`, 'error'); } } else { consoleLog(`[${host}] File ${accountPath} does not exist, skipping starting bot for this VPN!`, 'error'); } } function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } function isRootUser() { return process.getuid && process.getuid() === 0; } async function main() { await checkUpdate(); const vpns = execSync('nmcli connection show | awk \'/vpn/ {print $1}\'').toString().trim().split('\n'); if (fs.existsSync('.env')) { require('dotenv').config({ path: '.env' }); } else { consoleLog(`[${host}] Config file not found.`, 'error'); process.exit(1); } if (!process.env.WEBHOOK) { consoleLog(`[${host}] Webhook not set! Updates won't be sent to it.`); } else { if (!process.env.MCR_BOT_WEBHOOK) { process.env.MCR_BOT_WEBHOOK = process.env.WEBHOOK; } consoleLog(`[${host}] Webhook set!`); consoleLog(`[${host}] Starting mcr-bot on host: ${host}`, 'info'); } for (const vpn of vpns) { consoleLog(`[${host}] Switching to VPN: [${vpn}]`, 'info'); const con = await vpnConnect(vpn); if (con) continue; await startBot(vpn); } return 0; } async function uniqueRun(vpn) { await checkUpdate(); if (fs.existsSync('.env')) { require('dotenv').config({ path: '.env' }); } else { consoleLog(`[${host}] Config file not found.`, 'error'); process.exit(1); } if (!process.env.WEBHOOK) { consoleLog(`[${host}] Webhook not set! Updates won't be sent to it.`); } else { if (!process.env.MCR_BOT_WEBHOOK) { process.env.MCR_BOT_WEBHOOK = process.env.WEBHOOK; } consoleLog(`[${host}] Webhook set!`); consoleLog(`[${host}] Starting mcr-bot on host: ${host}`, 'info'); } consoleLog(`[${host}] Switching to VPN: [${vpn}]`, 'info'); const con = await vpnConnect(vpn); if (con) return 1; await startBot(vpn); return 0; } (async () => { for (let i = 0; i < args.length; i++) { if (args[i].startsWith('--')) { if (args[i] === '--accounts' && i + 1 < args.length) { const accounts = args[i + 1]; await uniqueRun(accounts); break; } else if (args[i] === '--all') { const n = true; while (n) { try { await main(); await sleep(1000); } catch (error) { consoleLog('An error occurred:\n' + error.message, 'error'); } } } } } })();