From 9271f1b52aeed0a6eebcc86493840ad7bd2c20e2 Mon Sep 17 00:00:00 2001 From: adrapier03 Date: Wed, 8 Jul 2026 00:16:22 +0700 Subject: [PATCH] feat: implement advanced humanization (variable typing speed, hovers, random delays) --- automation.js | 100 +++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/automation.js b/automation.js index 996ed13..493c686 100644 --- a/automation.js +++ b/automation.js @@ -1,3 +1,4 @@ +const { launch } = require('cloakbrowser'); const fs = require('fs'); const path = require('path'); @@ -28,16 +29,26 @@ if (accounts.length === 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, // Simulasi gerakan mouse & ketikan keyboard manusia + humanize: true, // CloakBrowser internal humanization (curves, touches, RTC, WebGL) }); for (let i = 0; i < accounts.length; i++) { @@ -49,7 +60,7 @@ async function run() { // 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 } + viewport: { width: 1920, height: 1080 } // Desktop view rendering }); try { @@ -58,43 +69,55 @@ async function run() { 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 page1.getByRole('link', { name: 'Sign Up' }).click(); - await page1.waitForTimeout(1000); + 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 page1.getByRole('button', { name: 'Sign up with Google' }).click(); + 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 page2.locator('#identifierId').click(); - await page2.locator('#identifierId').fill(account.email); + 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 page2.getByRole('button', { name: 'Next' }).click(); - await page2.waitForTimeout(2000); // Wait for password input to load + 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 page2.locator('div#password > div > div > div > input').fill(account.password); + 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 page2.getByRole('button', { name: 'Next' }).click(); - await page2.waitForTimeout(2000); + await humanClick(page2.getByRole('button', { name: 'Next' })); + await sleepRandom(3000, 4500); console.log('Checking for Terms speedbump ("I understand")...'); try { - await page2.getByRole('button', { name: 'I understand' }).waitFor({ state: 'visible', timeout: 3000 }); - await page2.getByRole('button', { name: 'I understand' }).click(); - await page2.waitForTimeout(1000); + 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.'); @@ -103,49 +126,50 @@ async function run() { 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 continueBtn.waitFor({ state: 'visible', timeout: 5000 }); - await continueBtn.click(); - await page2.waitForTimeout(2000); + 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 page1.waitForTimeout(3000); + 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 profileBtn.waitFor({ state: 'visible', timeout: 7000 }); - await profileBtn.click(); - await page1.waitForTimeout(1000); + await humanClick(profileBtn, 7000); + await sleepRandom(800, 1500); console.log('Clicking "Dashboard" link...'); - await page1.getByRole('link', { name: 'Dashboard' }).click(); - await page1.waitForTimeout(1000); + await humanClick(page1.getByRole('link', { name: 'Dashboard' })); + await sleepRandom(2000, 3500); console.log('Clicking "API Keys" section...'); - await page1.getByRole('link', { name: 'API Keys' }).click(); - await page1.waitForTimeout(1000); + await humanClick(page1.getByRole('link', { name: 'API Keys' })); + await sleepRandom(1500, 2500); console.log('Clicking "Create New Key" button...'); - await page1.getByRole('button', { name: 'Create New Key' }).click(); - await page1.waitForTimeout(1000); + await humanClick(page1.getByRole('button', { name: 'Create New Key' })); + await sleepRandom(800, 1500); console.log('Selecting key name field...'); - await page1.getByRole('textbox', { name: 'e.g.: Production Key' }).click(); - await page1.waitForTimeout(500); + 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' }).fill('my api key'); + 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 page1.getByRole('button', { name: 'Create Key' }).click(); - await page1.waitForTimeout(2000); + await humanClick(page1.getByRole('button', { name: 'Create Key' })); + await sleepRandom(2000, 3500); console.log('Clicking copy button on modal...'); - await page1.locator('html > body > div:nth-of-type(6) > div > div > div:nth-of-type(2) > div > button').click(); - await page1.waitForTimeout(1000); // Wait for clipboard writing to complete + 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 () => { @@ -184,8 +208,8 @@ async function run() { } console.log('Clicking "Complete" button to close modal...'); - await page1.getByRole('button', { name: 'Complete' }).click(); - await page1.waitForTimeout(1000); + await humanClick(page1.getByRole('button', { name: 'Complete' })); + await sleepRandom(1500, 2500); console.log(`[Account ${i + 1}/${accounts.length}] Successfully completed API Key creation.`);