Compare commits
6
Commits
d187ce6e2e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c92c2c8ad | ||
|
|
744033351f | ||
|
|
01d09ccbc4 | ||
|
|
89c9350d7e | ||
|
|
9271f1b52a | ||
|
|
680fc0bd15 |
@@ -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
|
||||||
|
|
||||||
|
|||||||
+70
-43
@@ -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,10 +52,16 @@ 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: { width: 1920, height: 1080 }
|
viewport: { width: 1920, height: 1080 } // Desktop view rendering
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -58,43 +70,55 @@ async function run() {
|
|||||||
|
|
||||||
console.log('Navigating to landing page: https://evolink.ai/ ...');
|
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
|
||||||
|
|
||||||
console.log('Clicking "Sign Up" link...');
|
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);
|
||||||
|
|
||||||
console.log('Setting up tab event listener...');
|
console.log('Setting up tab event listener...');
|
||||||
const page2Promise = context.waitForEvent('page');
|
const page2Promise = context.waitForEvent('page');
|
||||||
|
|
||||||
console.log('Clicking "Sign up with Google" button...');
|
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...');
|
console.log('Waiting for Google Login tab to open...');
|
||||||
const page2 = await page2Promise;
|
const page2 = await page2Promise;
|
||||||
console.log('Google login tab opened successfully.');
|
console.log('Google login tab opened successfully.');
|
||||||
|
await sleepRandom(1000, 1800);
|
||||||
|
|
||||||
console.log('Entering Google email: ' + account.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);
|
|
||||||
|
// 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...');
|
console.log('Submitting email...');
|
||||||
await page2.getByRole('button', { name: 'Next' }).click();
|
await humanClick(page2.getByRole('button', { name: 'Next' }));
|
||||||
await page2.waitForTimeout(2000); // Wait for password input to load
|
await sleepRandom(2500, 3500); // Natural loading wait
|
||||||
|
|
||||||
console.log('Entering Google password...');
|
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'));
|
||||||
|
|
||||||
|
// 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...');
|
console.log('Submitting password...');
|
||||||
await page2.getByRole('button', { name: 'Next' }).click();
|
await humanClick(page2.getByRole('button', { name: 'Next' }));
|
||||||
await page2.waitForTimeout(2000);
|
await sleepRandom(3000, 4500);
|
||||||
|
|
||||||
console.log('Checking for Terms speedbump ("I understand")...');
|
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.');
|
||||||
@@ -103,49 +127,50 @@ async function run() {
|
|||||||
console.log('Checking for Google OAuth Continue/Lanjutkan/Allow button...');
|
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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Waiting for landing page to reflect login status...');
|
console.log('Waiting for landing page to reflect login status...');
|
||||||
await page1.waitForTimeout(3000);
|
await sleepRandom(3500, 5000);
|
||||||
|
|
||||||
console.log('Clicking profile dropdown button...');
|
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);
|
|
||||||
|
|
||||||
console.log('Clicking "Dashboard" link...');
|
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);
|
||||||
|
|
||||||
console.log('Clicking "API Keys" section...');
|
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);
|
||||||
|
|
||||||
console.log('Clicking "Create New Key" button...');
|
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);
|
||||||
|
|
||||||
console.log('Selecting key name field...');
|
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);
|
||||||
|
|
||||||
console.log('Entering API key name...');
|
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...');
|
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);
|
||||||
|
|
||||||
console.log('Clicking copy button on modal...');
|
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 humanClick(page1.locator('html > body > div:nth-of-type(6) > div > div > div:nth-of-type(2) > div > button'));
|
||||||
await page1.waitForTimeout(1000); // Wait for clipboard writing to complete
|
await sleepRandom(1200, 1800); // Wait for clipboard writing to complete
|
||||||
|
|
||||||
console.log('Extracting generated API Key...');
|
console.log('Extracting generated API Key...');
|
||||||
let apiKey = await page1.evaluate(async () => {
|
let apiKey = await page1.evaluate(async () => {
|
||||||
@@ -184,21 +209,23 @@ async function run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('Clicking "Complete" button to close modal...');
|
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);
|
||||||
Reference in New Issue
Block a user