const fs = require('fs'); const path = require('path'); // Read accounts from akun.txt const akunPath = path.join(__dirname, 'akun.txt'); if (!fs.existsSync(akunPath)) { console.error('Error: akun.txt not found! Please create it first.'); process.exit(1); } const content = fs.readFileSync(akunPath, 'utf-8'); const accounts = content.split('\n') .map(line => line.trim()) .filter(line => line && !line.startsWith('#') && line.includes('|')) .map(line => { const parts = line.split('|'); return { email: parts[0].trim(), password: parts[1].trim(), profileName: parts[2] ? parts[2].trim() : null // Optional profile name }; }); if (accounts.length === 0) { console.log('No active accounts found in akun.txt.'); process.exit(0); } console.log(`Found ${accounts.length} account(s) to process.`); // Helper for random delay const sleepRandom = (min, max) => new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * (max - min + 1) + min))); // Human-like click (waits for element, hovers, pauses, then clicks) async function humanClick(locator, timeout = 10000) { await locator.waitFor({ state: 'visible', timeout }); await locator.hover(); await sleepRandom(250, 600); // Natural mouse hover reaction time await locator.click(); } // Parse --headless argument from CLI (e.g. node automation.js --headless true) const headlessIndex = process.argv.indexOf('--headless'); const isHeadless = headlessIndex !== -1 ? (process.argv[headlessIndex + 1] !== 'false') : false; async function run() { const { launch } = await import('cloakbrowser'); console.log(`Launching CloakBrowser (headless: ${isHeadless})...`); const browser = await launch({ headless: isHeadless, humanize: true, // CloakBrowser internal humanization (curves, touches, RTC, WebGL) }); for (let i = 0; i < accounts.length; i++) { const account = accounts[i]; console.log(`\n==================================================`); console.log(`[Account ${i + 1}/${accounts.length}] Processing: ${account.email}`); console.log(`==================================================`); // Create a clean isolated context for each account to prevent session leaks const context = await browser.newContext({ permissions: ['clipboard-read', 'clipboard-write'], viewport: { width: 1920, height: 1080 } // Desktop view rendering }); try { console.log('Initializing browser page...'); const page1 = await context.newPage(); console.log('Navigating to landing page: https://evolink.ai/ ...'); await page1.goto('https://evolink.ai/'); await sleepRandom(1500, 2500); // Natural user wait console.log('Clicking "Sign Up" link...'); await humanClick(page1.getByRole('link', { name: 'Sign Up' })); await sleepRandom(800, 1500); console.log('Setting up tab event listener...'); const page2Promise = context.waitForEvent('page'); console.log('Clicking "Sign up with Google" button...'); await humanClick(page1.getByRole('button', { name: 'Sign up with Google' })); console.log('Waiting for Google Login tab to open...'); const page2 = await page2Promise; console.log('Google login tab opened successfully.'); await sleepRandom(1000, 1800); console.log('Entering Google email: ' + account.email); await page2.locator('#identifierId').waitFor({ state: 'visible', timeout: 5000 }); await humanClick(page2.locator('#identifierId')); // Type letter-by-letter with variable speeds await page2.locator('#identifierId').pressSequentially(account.email, { delay: Math.floor(Math.random() * 40) + 60 // 60ms to 100ms per key }); await sleepRandom(600, 1200); console.log('Submitting email...'); await humanClick(page2.getByRole('button', { name: 'Next' })); await sleepRandom(2500, 3500); // Natural loading wait console.log('Entering Google password...'); await page2.locator('div#password > div > div > div > input').waitFor({ state: 'visible', timeout: 5000 }); await humanClick(page2.locator('div#password > div > div > div > input')); // Type password letter-by-letter await page2.locator('div#password > div > div > div > input').pressSequentially(account.password, { delay: Math.floor(Math.random() * 40) + 70 // 70ms to 110ms per key }); await sleepRandom(600, 1200); console.log('Submitting password...'); await humanClick(page2.getByRole('button', { name: 'Next' })); await sleepRandom(3000, 4500); console.log('Checking for Terms speedbump ("I understand")...'); try { await humanClick(page2.getByRole('button', { name: 'I understand' }), 3000); await sleepRandom(1000, 2000); console.log('Clicked "I understand" button.'); } catch (e) { console.log('Speedbump "I understand" not present, skipping.'); } console.log('Checking for Google OAuth Continue/Lanjutkan/Allow button...'); try { const continueBtn = page2.getByRole('button', { name: /^(Sign in|Continue|Allow|Login|Masuk|Lanjutkan|Izinkan)$/i }); await humanClick(continueBtn, 5000); await sleepRandom(2000, 3500); console.log('Clicked login/continue button.'); } catch (e) { console.log('Login/continue button not found or already bypassed.'); } console.log('Waiting for landing page to reflect login status...'); await sleepRandom(3500, 5000); console.log('Clicking profile dropdown button...'); const profileBtn = page1.locator(".w-4.h-4.text-gray-400.transition-transform.duration-200").first(); await humanClick(profileBtn, 7000); await sleepRandom(800, 1500); console.log('Clicking "Dashboard" link...'); await humanClick(page1.getByRole('link', { name: 'Dashboard' })); await sleepRandom(2000, 3500); console.log('Clicking "API Keys" section...'); await humanClick(page1.getByRole('link', { name: 'API Keys' })); await sleepRandom(1500, 2500); console.log('Clicking "Create New Key" button...'); await humanClick(page1.getByRole('button', { name: 'Create New Key' })); await sleepRandom(800, 1500); console.log('Selecting key name field...'); await humanClick(page1.getByRole('textbox', { name: 'e.g.: Production Key' })); await sleepRandom(400, 800); console.log('Entering API key name...'); await page1.getByRole('textbox', { name: 'e.g.: Production Key' }).pressSequentially('my api key', { delay: Math.floor(Math.random() * 40) + 80 // 80ms to 120ms per key }); await sleepRandom(600, 1200); console.log('Submitting API key form...'); await humanClick(page1.getByRole('button', { name: 'Create Key' })); await sleepRandom(2000, 3500); console.log('Clicking copy button on modal...'); await humanClick(page1.locator('html > body > div:nth-of-type(6) > div > div > div:nth-of-type(2) > div > button')); await sleepRandom(1200, 1800); // Wait for clipboard writing to complete console.log('Extracting generated API Key...'); let apiKey = await page1.evaluate(async () => { try { return await navigator.clipboard.readText(); } catch (e) { return null; } }).catch(() => null); if (!apiKey || apiKey.trim().length === 0) { console.log('Clipboard reading failed. Using DOM extraction fallback...'); apiKey = await page1.evaluate(() => { const modal = document.querySelector('body > div:nth-of-type(6)'); if (!modal) return null; const input = modal.querySelector('input, textarea'); if (input && input.value) return input.value.trim(); const elements = Array.from(modal.querySelectorAll('span, div, code, p')); for (const el of elements) { const txt = el.innerText ? el.innerText.trim() : ''; if (txt.length > 20 && !txt.includes(' ') && /^[a-zA-Z0-9_\-\.]+$/.test(txt)) { return txt; } } return null; }).catch(() => null); } if (apiKey) { console.log(`[Success] Extracted API Key: ${apiKey}`); fs.appendFileSync(path.join(__dirname, 'api_keys.txt'), `${account.email}|${apiKey}\n`); } else { console.log('[Warning] Could not extract API Key from clipboard or modal DOM.'); } console.log('Clicking "Complete" button to close modal...'); await humanClick(page1.getByRole('button', { name: 'Complete' })); await sleepRandom(1500, 2500); console.log(`[Account ${i + 1}/${accounts.length}] Successfully completed API Key creation.`); } catch (err) { console.error(`[Account ${i + 1}/${accounts.length}] Failed with error:`, err.message || err); } finally { // Close context to clear session cookies for the next account await context.close(); } } console.log('\nAll accounts processed.'); await browser.close(); } run().catch(console.error);