Compare commits

..
8 Commits
2 changed files with 98 additions and 70 deletions
+1
View File
@@ -2,3 +2,4 @@
# Hilangkan tanda pagar (#) untuk mengaktifkan baris akun tersebut # Hilangkan tanda pagar (#) untuk mengaktifkan baris akun tersebut
#[email protected]|password123 #[email protected]|password123
#[email protected]|password456 #[email protected]|password456
+97 -70
View File
@@ -28,17 +28,23 @@ if (accounts.length === 0) {
console.log(`Found ${accounts.length} account(s) to process.`); 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) // Parse --headless argument from CLI (e.g. node automation.js --headless true)
const headlessIndex = process.argv.indexOf('--headless'); const headlessIndex = process.argv.indexOf('--headless');
const isHeadless = headlessIndex !== -1 ? (process.argv[headlessIndex + 1] !== 'false') : false; const isHeadless = headlessIndex !== -1 ? (process.argv[headlessIndex + 1] !== 'false') : false;
async function run() { async function run() {
const { launch } = await import('cloakbrowser'); const { launch } = await import('cloakbrowser');
console.log(`Launching CloakBrowser (headless: ${isHeadless})...`);
const browser = await launch({
headless: isHeadless,
// Add other fingerprint options here if needed
});
for (let i = 0; i < accounts.length; i++) { for (let i = 0; i < accounts.length; i++) {
const account = accounts[i]; const account = accounts[i];
@@ -46,107 +52,127 @@ async function run() {
console.log(`[Account ${i + 1}/${accounts.length}] Processing: ${account.email}`); console.log(`[Account ${i + 1}/${accounts.length}] Processing: ${account.email}`);
console.log(`==================================================`); console.log(`==================================================`);
console.log(`Launching CloakBrowser with new fingerprint (headless: ${isHeadless})...`);
const browser = await launch({
headless: isHeadless,
humanize: true, // CloakBrowser internal humanization (curves, touches, RTC, WebGL)
});
// Create a clean isolated context for each account to prevent session leaks // Create a clean isolated context for each account to prevent session leaks
const context = await browser.newContext({ const context = await browser.newContext({
permissions: ['clipboard-read', 'clipboard-write'], permissions: ['clipboard-read', 'clipboard-write'],
viewport: null viewport: { width: 1920, height: 1080 } // Desktop view rendering
}); });
try { try {
// Primary page initialization console.log('Initializing browser page...');
const page1 = await context.newPage(); const page1 = await context.newPage();
console.log('Navigating to landing page: https://evolink.ai/ ...');
await page1.goto('https://evolink.ai/'); await page1.goto('https://evolink.ai/');
await sleepRandom(1500, 2500); // Natural user wait
// Click on a "Sign Up" console.log('Clicking "Sign Up" link...');
await page1.getByRole('link', { name: 'Sign Up' }).click(); await humanClick(page1.getByRole('link', { name: 'Sign Up' }));
await page1.waitForTimeout(1000); await sleepRandom(800, 1500);
// Start waiting for Google Login window/tab to open before clicking console.log('Setting up tab event listener...');
const page2Promise = context.waitForEvent('page'); const page2Promise = context.waitForEvent('page');
// Click on button "Sign up with Google" 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' }));
// Wait for the new tab to open console.log('Waiting for Google Login tab to open...');
const page2 = await page2Promise; const page2 = await page2Promise;
console.log('Google login tab opened. Logging in...'); console.log('Google login tab opened successfully.');
await sleepRandom(1000, 1800);
// Fill email console.log('Entering Google email: ' + account.email);
await page2.locator('#identifierId').waitFor({ state: 'visible', timeout: 5000 }); await page2.locator('#identifierId').waitFor({ state: 'visible', timeout: 5000 });
await page2.locator('#identifierId').click(); await humanClick(page2.locator('#identifierId'));
await page2.locator('#identifierId').fill(account.email);
// Click on button "Next" // Type letter-by-letter with variable speeds
await page2.getByRole('button', { name: 'Next' }).click(); await page2.locator('#identifierId').pressSequentially(account.email, {
await page2.waitForTimeout(2000); // Wait for password input to load delay: Math.floor(Math.random() * 40) + 60 // 60ms to 100ms per key
});
await sleepRandom(600, 1200);
// Fill password 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 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'));
// Click on button "Next" // Type password letter-by-letter
await page2.getByRole('button', { name: 'Next' }).click(); await page2.locator('div#password > div > div > div > input').pressSequentially(account.password, {
await page2.waitForTimeout(2000); delay: Math.floor(Math.random() * 40) + 70 // 70ms to 110ms per key
});
await sleepRandom(600, 1200);
// Click on button "I understand" (if Terms speedbump shows up) console.log('Submitting password...');
await humanClick(page2.getByRole('button', { name: 'Next' }));
await sleepRandom(3000, 4500);
console.log('Checking for Terms speedbump ("I understand")...');
try { try {
await page2.getByRole('button', { name: 'I understand' }).waitFor({ state: 'visible', timeout: 3000 }); await humanClick(page2.getByRole('button', { name: 'I understand' }), 3000);
await page2.getByRole('button', { name: 'I understand' }).click(); await sleepRandom(1000, 2000);
await page2.waitForTimeout(1000);
console.log('Clicked "I understand" button.'); console.log('Clicked "I understand" button.');
} catch (e) { } catch (e) {
console.log('Speedbump "I understand" not present, skipping...'); console.log('Speedbump "I understand" not present, skipping.');
} }
// Click on button "Continue" (OAuth consent page) console.log('Checking for Google OAuth Continue/Lanjutkan/Allow button...');
try { try {
const continueBtn = page2.getByRole('button', { name: /^(Sign in|Continue|Allow|Login|Masuk|Lanjutkan|Izinkan)$/i }); const continueBtn = page2.getByRole('button', { name: /^(Sign in|Continue|Allow|Login|Masuk|Lanjutkan|Izinkan)$/i });
await continueBtn.waitFor({ state: 'visible', timeout: 5000 }); await humanClick(continueBtn, 5000);
await continueBtn.click(); await sleepRandom(2000, 3500);
await page2.waitForTimeout(2000);
console.log('Clicked login/continue button.'); console.log('Clicked login/continue button.');
} catch (e) { } catch (e) {
console.log('Login/continue button not found or already bypassed.'); console.log('Login/continue button not found or already bypassed.');
} }
// Back on page1, wait for login state to reflect console.log('Waiting for landing page to reflect login status...');
await page1.waitForTimeout(3000); await sleepRandom(3500, 5000);
// Click on profile dropdown button (using the name-independent chevron selector) console.log('Clicking profile dropdown button...');
const profileBtn = page1.locator(".w-4.h-4.text-gray-400.transition-transform.duration-200").first(); const profileBtn = page1.locator(".w-4.h-4.text-gray-400.transition-transform.duration-200").first();
await profileBtn.waitFor({ state: 'visible', timeout: 7000 }); await humanClick(profileBtn, 7000);
await profileBtn.click(); await sleepRandom(800, 1500);
await page1.waitForTimeout(1000);
// Click on a "Dashboard" console.log('Clicking "Dashboard" link...');
await page1.getByRole('link', { name: 'Dashboard' }).click(); await humanClick(page1.getByRole('link', { name: 'Dashboard' }));
await page1.waitForTimeout(1000); await sleepRandom(2000, 3500);
// Click on a "API Keys" console.log('Clicking "API Keys" section...');
await page1.getByRole('link', { name: 'API Keys' }).click(); await humanClick(page1.getByRole('link', { name: 'API Keys' }));
await page1.waitForTimeout(1000); await sleepRandom(1500, 2500);
// Click on button "Create New Key" console.log('Clicking "Create New Key" button...');
await page1.getByRole('button', { name: 'Create New Key' }).click(); await humanClick(page1.getByRole('button', { name: 'Create New Key' }));
await page1.waitForTimeout(1000); await sleepRandom(800, 1500);
// Click on input console.log('Selecting key name field...');
await page1.getByRole('textbox', { name: 'e.g.: Production Key' }).click(); await humanClick(page1.getByRole('textbox', { name: 'e.g.: Production Key' }));
await page1.waitForTimeout(500); await sleepRandom(400, 800);
// Fill value in input 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);
// Click on button "Create Key" console.log('Submitting API key form...');
await page1.getByRole('button', { name: 'Create Key' }).click(); await humanClick(page1.getByRole('button', { name: 'Create Key' }));
await page1.waitForTimeout(2000); await sleepRandom(2000, 3500);
// Click copy/close button on modal console.log('Clicking copy button on modal...');
console.log('Clicking copy button...'); await humanClick(page1.locator('html > body > div:nth-of-type(6) > div > div > div:nth-of-type(2) > div > button'));
await page1.locator('html > body > div:nth-of-type(6) > div > div > div:nth-of-type(2) > div > button').click(); await sleepRandom(1200, 1800); // Wait for clipboard writing to complete
await page1.waitForTimeout(1000); // Wait for clipboard writing to complete
// Extract API key from clipboard and fallback to DOM console.log('Extracting generated API Key...');
let apiKey = await page1.evaluate(async () => { let apiKey = await page1.evaluate(async () => {
try { try {
return await navigator.clipboard.readText(); return await navigator.clipboard.readText();
@@ -156,7 +182,7 @@ async function run() {
}).catch(() => null); }).catch(() => null);
if (!apiKey || apiKey.trim().length === 0) { if (!apiKey || apiKey.trim().length === 0) {
// Fallback: search DOM inside the modal container console.log('Clipboard reading failed. Using DOM extraction fallback...');
apiKey = await page1.evaluate(() => { apiKey = await page1.evaluate(() => {
const modal = document.querySelector('body > div:nth-of-type(6)'); const modal = document.querySelector('body > div:nth-of-type(6)');
if (!modal) return null; if (!modal) return null;
@@ -167,7 +193,6 @@ async function run() {
const elements = Array.from(modal.querySelectorAll('span, div, code, p')); const elements = Array.from(modal.querySelectorAll('span, div, code, p'));
for (const el of elements) { for (const el of elements) {
const txt = el.innerText ? el.innerText.trim() : ''; const txt = el.innerText ? el.innerText.trim() : '';
// API Keys are usually longer alphanumeric strings with no spaces
if (txt.length > 20 && !txt.includes(' ') && /^[a-zA-Z0-9_\-\.]+$/.test(txt)) { if (txt.length > 20 && !txt.includes(' ') && /^[a-zA-Z0-9_\-\.]+$/.test(txt)) {
return txt; return txt;
} }
@@ -183,22 +208,24 @@ async function run() {
console.log('[Warning] Could not extract API Key from clipboard or modal DOM.'); console.log('[Warning] Could not extract API Key from clipboard or modal DOM.');
} }
// Click on button "Complete" console.log('Clicking "Complete" button to close modal...');
await page1.getByRole('button', { name: 'Complete' }).click(); await humanClick(page1.getByRole('button', { name: 'Complete' }));
await page1.waitForTimeout(1000); await sleepRandom(1500, 2500);
console.log(`[Account ${i + 1}/${accounts.length}] Successfully completed API Key creation.`); console.log(`[Account ${i + 1}/${accounts.length}] Successfully completed API Key creation.`);
} catch (err) { } catch (err) {
console.error(`[Account ${i + 1}/${accounts.length}] Failed with error:`, err.message || err); console.error(`[Account ${i + 1}/${accounts.length}] Failed with error:`, err.message || err);
} finally { } finally {
// Close context to clear session cookies for the next account // Close context and browser to finalize this session and generate a new fingerprint for the next loop
await context.close(); await context.close();
await browser.close();
console.log('Browser closed. Waiting a moment before processing next account...');
await sleepRandom(2000, 4000);
} }
} }
console.log('\nAll accounts processed.'); console.log('\nAll accounts processed.');
await browser.close();
} }
run().catch(console.error); run().catch(console.error);