Compare commits
2
Commits
5af0488e66
...
d187ce6e2e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d187ce6e2e | ||
|
|
d6e45c701e |
+28
-28
@@ -49,56 +49,58 @@ async function run() {
|
|||||||
// 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 }
|
||||||
});
|
});
|
||||||
|
|
||||||
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/');
|
||||||
|
|
||||||
// Click on a "Sign Up"
|
console.log('Clicking "Sign Up" link...');
|
||||||
await page1.getByRole('link', { name: 'Sign Up' }).click();
|
await page1.getByRole('link', { name: 'Sign Up' }).click();
|
||||||
await page1.waitForTimeout(1000);
|
await page1.waitForTimeout(1000);
|
||||||
|
|
||||||
// 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 page1.getByRole('button', { name: 'Sign up with Google' }).click();
|
||||||
|
|
||||||
// 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.');
|
||||||
|
|
||||||
// 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 page2.locator('#identifierId').click();
|
||||||
await page2.locator('#identifierId').fill(account.email);
|
await page2.locator('#identifierId').fill(account.email);
|
||||||
|
|
||||||
// Click on button "Next"
|
console.log('Submitting email...');
|
||||||
await page2.getByRole('button', { name: 'Next' }).click();
|
await page2.getByRole('button', { name: 'Next' }).click();
|
||||||
await page2.waitForTimeout(2000); // Wait for password input to load
|
await page2.waitForTimeout(2000); // Wait for password input to load
|
||||||
|
|
||||||
// Fill 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 page2.locator('div#password > div > div > div > input').fill(account.password);
|
||||||
|
|
||||||
// Click on button "Next"
|
console.log('Submitting password...');
|
||||||
await page2.getByRole('button', { name: 'Next' }).click();
|
await page2.getByRole('button', { name: 'Next' }).click();
|
||||||
await page2.waitForTimeout(2000);
|
await page2.waitForTimeout(2000);
|
||||||
|
|
||||||
// Click on button "I understand" (if Terms speedbump shows up)
|
console.log('Checking for Terms speedbump ("I understand")...');
|
||||||
try {
|
try {
|
||||||
await page2.getByRole('button', { name: 'I understand' }).waitFor({ state: 'visible', timeout: 3000 });
|
await page2.getByRole('button', { name: 'I understand' }).waitFor({ state: 'visible', timeout: 3000 });
|
||||||
await page2.getByRole('button', { name: 'I understand' }).click();
|
await page2.getByRole('button', { name: 'I understand' }).click();
|
||||||
await page2.waitForTimeout(1000);
|
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 continueBtn.waitFor({ state: 'visible', timeout: 5000 });
|
||||||
@@ -109,44 +111,43 @@ async function run() {
|
|||||||
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 page1.waitForTimeout(3000);
|
||||||
|
|
||||||
// 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 profileBtn.waitFor({ state: 'visible', timeout: 7000 });
|
||||||
await profileBtn.click();
|
await profileBtn.click();
|
||||||
await page1.waitForTimeout(1000);
|
await page1.waitForTimeout(1000);
|
||||||
|
|
||||||
// Click on a "Dashboard"
|
console.log('Clicking "Dashboard" link...');
|
||||||
await page1.getByRole('link', { name: 'Dashboard' }).click();
|
await page1.getByRole('link', { name: 'Dashboard' }).click();
|
||||||
await page1.waitForTimeout(1000);
|
await page1.waitForTimeout(1000);
|
||||||
|
|
||||||
// Click on a "API Keys"
|
console.log('Clicking "API Keys" section...');
|
||||||
await page1.getByRole('link', { name: 'API Keys' }).click();
|
await page1.getByRole('link', { name: 'API Keys' }).click();
|
||||||
await page1.waitForTimeout(1000);
|
await page1.waitForTimeout(1000);
|
||||||
|
|
||||||
// Click on button "Create New Key"
|
console.log('Clicking "Create New Key" button...');
|
||||||
await page1.getByRole('button', { name: 'Create New Key' }).click();
|
await page1.getByRole('button', { name: 'Create New Key' }).click();
|
||||||
await page1.waitForTimeout(1000);
|
await page1.waitForTimeout(1000);
|
||||||
|
|
||||||
// Click on input
|
console.log('Selecting key name field...');
|
||||||
await page1.getByRole('textbox', { name: 'e.g.: Production Key' }).click();
|
await page1.getByRole('textbox', { name: 'e.g.: Production Key' }).click();
|
||||||
await page1.waitForTimeout(500);
|
await page1.waitForTimeout(500);
|
||||||
|
|
||||||
// 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' }).fill('my api key');
|
||||||
|
|
||||||
// Click on button "Create Key"
|
console.log('Submitting API key form...');
|
||||||
await page1.getByRole('button', { name: 'Create Key' }).click();
|
await page1.getByRole('button', { name: 'Create Key' }).click();
|
||||||
await page1.waitForTimeout(2000);
|
await page1.waitForTimeout(2000);
|
||||||
|
|
||||||
// Click copy/close button on modal
|
console.log('Clicking copy button on modal...');
|
||||||
console.log('Clicking copy button...');
|
|
||||||
await page1.locator('html > body > div:nth-of-type(6) > div > div > div:nth-of-type(2) > div > button').click();
|
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 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 +157,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 +168,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,7 +183,7 @@ 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 page1.getByRole('button', { name: 'Complete' }).click();
|
||||||
await page1.waitForTimeout(1000);
|
await page1.waitForTimeout(1000);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user