hitz / app.js
Reaperxxxx's picture
Update app.js
18bdb07 verified
Raw
History Blame Contribute Delete
38 kB
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const RecaptchaPlugin = require('puppeteer-extra-plugin-recaptcha');
const FormData = require('form-data');
const fs = require('fs');
const path = require('path');
// Use stealth plugin to avoid detection
puppeteer.use(StealthPlugin());
// Add recaptcha plugin (requires 2captcha API key for actual solving, but helps with detection)
puppeteer.use(
RecaptchaPlugin({
visualFeedback: true, // Show when solving captcha
throwOnError: false // Don't throw errors, just try to continue
})
);
// Helper function to wait
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// Random delay to appear more human-like
const randomWait = (min, max) => wait(Math.floor(Math.random() * (max - min + 1)) + min);
// Check if we should wait for manual Cloudflare solving
const MANUAL_CLOUDFLARE = process.env.MANUAL_CLOUDFLARE === 'true';
const CLOUDFLARE_WAIT = parseInt(process.env.CLOUDFLARE_WAIT || '30000');
if (MANUAL_CLOUDFLARE) {
console.log('⚠️ MANUAL_CLOUDFLARE mode enabled - will wait up to', CLOUDFLARE_WAIT / 1000, 'seconds for manual solving');
}
// Function to upload image to uploadnx.zone.id
async function uploadToServer(filePath) {
return new Promise((resolve, reject) => {
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
const options = {
method: 'POST',
hostname: 'uploadnx.zone.id',
path: '/api/upload',
headers: form.getHeaders()
};
const https = require('https');
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => {
data += chunk;
});
res.on('end', () => {
if (res.statusCode === 200) {
try {
const response = JSON.parse(data);
resolve(response.short_url);
} catch (e) {
reject(new Error('Invalid JSON response'));
}
} else {
reject(new Error(`Upload failed with status code: ${res.statusCode}`));
}
});
});
req.on('error', reject);
form.pipe(req);
});
}
// Load cookies from JSON file
function loadCookies(cookieFilePath) {
try {
if (fs.existsSync(cookieFilePath)) {
const cookieData = JSON.parse(fs.readFileSync(cookieFilePath, 'utf8'));
console.log(`βœ“ Loaded cookies from: ${cookieFilePath}`);
console.log(` - ${cookieData.cookies.length} cookies found`);
console.log(` - ${Object.keys(cookieData.localStorage || {}).length} localStorage items`);
console.log(` - ${Object.keys(cookieData.sessionStorage || {}).length} sessionStorage items`);
return cookieData;
} else {
console.log(`⚠️ Cookie file not found: ${cookieFilePath}`);
console.log(' Running without cookies...');
return null;
}
} catch (error) {
console.error(`❌ Error loading cookies: ${error.message}`);
return null;
}
}
(async () => {
// Look for cookie file in multiple locations
const possibleCookieFiles = [
path.join(__dirname, 'cookies.json'),
path.join(__dirname, 'betking-cookies.json'),
'/mnt/user-data/uploads/cookies.json'
];
let cookieData = null;
for (const cookieFile of possibleCookieFiles) {
cookieData = loadCookies(cookieFile);
if (cookieData) break;
}
const browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-blink-features=AutomationControlled',
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--no-first-run',
'--no-zygote',
'--disable-gpu',
'--disable-notifications',
'--disable-popup-blocking',
// EXTREME ANTI-DETECTION
'--disable-features=IsolateOrigins',
'--disable-site-isolation-trials',
'--disable-features=BlockInsecurePrivateNetworkRequests',
'--disable-blink-features=AutomationControlled',
'--excludeSwitches=enable-automation',
'--disable-infobars',
'--window-size=390,844',
'--user-agent=' + (cookieData?.userAgent || 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1'),
// Bypass bot detection
'--disable-blink-features=AutomationControlled',
'--disable-features=VizDisplayCompositor',
'--enable-features=NetworkService,NetworkServiceInProcess',
'--disable-breakpad',
'--disable-component-update',
'--disable-domain-reliability',
'--disable-sync',
'--disable-client-side-phishing-detection',
'--disable-features=site-per-process',
'--enable-features=NetworkServiceInProcess',
// Additional anti-Cloudflare flags
'--disable-features=IsolateOrigins,site-per-process,SitePerProcess',
'--disable-web-security',
'--allow-running-insecure-content',
'--disable-features=VizDisplayCompositor',
'--disable-ipc-flooding-protection',
'--disable-hang-monitor',
'--disable-prompt-on-repost',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--force-color-profile=srgb',
'--disable-features=TranslateUI',
'--disable-features=Translate'
],
ignoreHTTPSErrors: true,
defaultViewport: null,
ignoreDefaultArgs: ['--enable-automation', '--enable-blink-features=IdleDetection']
});
const page = await browser.newPage();
// EXTREME: Additional page configurations
await page.setBypassCSP(true);
// Set extra permissions to look more like real browser
const context = browser.defaultBrowserContext();
await context.overridePermissions('https://m.betking.com', [
'geolocation',
'notifications'
]);
try {
// Enable JavaScript
await page.setJavaScriptEnabled(true);
// Use user agent from cookie file if available
const userAgent = cookieData?.userAgent || 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1';
await page.setUserAgent(userAgent);
console.log(`βœ“ Using User Agent: ${userAgent}`);
// Set realistic mobile viewport to match cookies
await page.setViewport({
width: 390,
height: 844,
isMobile: true,
hasTouch: true,
deviceScaleFactor: 3
});
// Set additional headers
const headers = {
'Accept-Language': 'en-US,en;q=0.9,en-NG;q=0.8',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
'Cache-Control': 'max-age=0'
};
await page.setExtraHTTPHeaders(headers);
// EXTREME: Enable request interception to modify headers on the fly
await page.setRequestInterception(true);
page.on('request', (request) => {
const overrides = {
headers: {
...request.headers(),
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Safari";v="16.6"',
'sec-ch-ua-mobile': '?1',
'sec-ch-ua-platform': '"iOS"',
'DNT': '1',
'Referer': 'https://m.betking.com/',
'Origin': 'https://m.betking.com'
}
};
request.continue(overrides);
});
console.log('βœ“ Request interception enabled with custom headers');
// CRITICAL: Set cookies BEFORE navigating
if (cookieData && cookieData.cookies) {
console.log('\nπŸͺ Pre-loading cookies...');
// First, navigate to the domain to establish context
try {
// Try login page directly for cookie context
await page.goto('https://m.betking.com/en-ng/my-accounts/login', {
waitUntil: 'domcontentloaded',
timeout: 15000
});
console.log('βœ“ Login page loaded for cookie context');
// Wait a bit for any Cloudflare JS to run
await wait(3000);
} catch (baseError) {
console.log('⚠️ Initial login page load issue, trying base domain...');
try {
await page.goto('https://m.betking.com/', {
waitUntil: 'domcontentloaded',
timeout: 15000
});
console.log('βœ“ Base domain loaded');
await wait(3000);
} catch (fallbackError) {
console.log('⚠️ Base domain also failed, setting domain manually...');
await page.evaluateOnNewDocument(() => {
document.domain = 'betking.com';
});
}
}
// Now set all cookies
console.log('Setting cookies...');
let cookiesSet = 0;
for (const cookie of cookieData.cookies) {
try {
await page.setCookie(cookie);
cookiesSet++;
} catch (error) {
// Silently skip problematic cookies
}
}
console.log(`βœ“ ${cookiesSet}/${cookieData.cookies.length} cookies set successfully`);
}
// Override WebDriver and other bot detection properties
await page.evaluateOnNewDocument(() => {
// Remove webdriver property
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
// Override permissions
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
// Add Chrome object
window.chrome = {
runtime: {},
loadTimes: function() {},
csi: function() {},
app: {}
};
// Override plugins with realistic values
Object.defineProperty(navigator, 'plugins', {
get: () => [
{
0: {type: "application/x-google-chrome-pdf", suffixes: "pdf", description: "Portable Document Format"},
description: "Portable Document Format",
filename: "internal-pdf-viewer",
length: 1,
name: "Chrome PDF Plugin"
}
]
});
// Override languages
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en']
});
// Remove automation indicators
delete navigator.__proto__.webdriver;
// Mock realistic hardware concurrency
Object.defineProperty(navigator, 'hardwareConcurrency', {
get: () => 4
});
// Mock realistic device memory
Object.defineProperty(navigator, 'deviceMemory', {
get: () => 8
});
// Override platform
Object.defineProperty(navigator, 'platform', {
get: () => 'iPhone'
});
// Override vendor
Object.defineProperty(navigator, 'vendor', {
get: () => 'Apple Computer, Inc.'
});
// Mock realistic touch points
Object.defineProperty(navigator, 'maxTouchPoints', {
get: () => 5
});
// Override toString to avoid detection
const originalToString = Function.prototype.toString;
Function.prototype.toString = function() {
if (this === navigator.permissions.query) {
return 'function query() { [native code] }';
}
return originalToString.call(this);
};
// Remove Headless Chrome detection
Object.defineProperty(navigator, 'webdriver', {
get: () => false
});
// Mock battery
navigator.getBattery = () => Promise.resolve({
charging: true,
chargingTime: 0,
dischargingTime: Infinity,
level: 1
});
// Override screen properties
Object.defineProperty(screen, 'availHeight', {
get: () => 844
});
Object.defineProperty(screen, 'availWidth', {
get: () => 390
});
Object.defineProperty(screen, 'height', {
get: () => 844
});
Object.defineProperty(screen, 'width', {
get: () => 390
});
// Canvas fingerprint spoofing
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function(type) {
const shift = {
'r': Math.floor(Math.random() * 10) - 5,
'g': Math.floor(Math.random() * 10) - 5,
'b': Math.floor(Math.random() * 10) - 5,
'a': Math.floor(Math.random() * 10) - 5
};
const context = this.getContext('2d');
if (context) {
const imageData = context.getImageData(0, 0, this.width, this.height);
for (let i = 0; i < imageData.data.length; i += 4) {
imageData.data[i + 0] = imageData.data[i + 0] + shift.r;
imageData.data[i + 1] = imageData.data[i + 1] + shift.g;
imageData.data[i + 2] = imageData.data[i + 2] + shift.b;
imageData.data[i + 3] = imageData.data[i + 3] + shift.a;
}
context.putImageData(imageData, 0, 0);
}
return originalToDataURL.apply(this, arguments);
};
// WebGL fingerprint spoofing
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(parameter) {
if (parameter === 37445) {
return 'Apple GPU';
}
if (parameter === 37446) {
return 'Apple Inc.';
}
return getParameter.call(this, parameter);
};
// Audio context fingerprint spoofing
const audioContext = window.AudioContext || window.webkitAudioContext;
if (audioContext) {
const OriginalAudioContext = audioContext;
window.AudioContext = function() {
const context = new OriginalAudioContext();
const originalCreateOscillator = context.createOscillator;
context.createOscillator = function() {
const oscillator = originalCreateOscillator.call(context);
const originalStart = oscillator.start;
oscillator.start = function(when) {
return originalStart.call(oscillator, when + Math.random() * 0.0001);
};
return oscillator;
};
return context;
};
}
// Remove automation from window
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
// Override Performance API to prevent timing attacks
const originalGetEntries = Performance.prototype.getEntries;
Performance.prototype.getEntries = function() {
const entries = originalGetEntries.call(this);
return entries.filter(entry => !entry.name.includes('devtools'));
};
// Override Date to add small random variations
const originalDate = Date;
Date = class extends originalDate {
constructor(...args) {
if (args.length === 0) {
super();
const offset = Math.floor(Math.random() * 10);
return new originalDate(this.getTime() + offset);
}
return new originalDate(...args);
}
};
Date.prototype = originalDate.prototype;
Date.now = function() {
return originalDate.now() + Math.floor(Math.random() * 10);
};
// Spoof notification permission
Object.defineProperty(Notification, 'permission', {
get: () => 'default'
});
// Mock realistic connection
Object.defineProperty(navigator, 'connection', {
get: () => ({
effectiveType: '4g',
rtt: 50,
downlink: 10,
saveData: false
})
});
// Override outerHeight/Width to match viewport
Object.defineProperty(window, 'outerWidth', {
get: () => 390
});
Object.defineProperty(window, 'outerHeight', {
get: () => 844
});
});
console.log('\n🌐 Navigating to the page...');
await randomWait(500, 1500);
// Navigate directly to login page
const targetUrl = 'https://m.betking.com/en-ng/my-accounts/login?urlAfterLogin=/en-ng';
console.log(`Target: ${targetUrl}`);
let response;
try {
response = await page.goto(targetUrl, {
waitUntil: ['domcontentloaded', 'networkidle2'],
timeout: 45000
});
} catch (error) {
console.log(`⚠️ Navigation warning: ${error.message}`);
console.log('Attempting to continue anyway...');
}
if (response) {
const statusCode = response.status();
console.log(`Response status: ${statusCode}`);
if (statusCode === 403) {
console.log('⚠️ Received 403 Forbidden error.');
console.log('Checking for Cloudflare challenge...');
// Check if it's a Cloudflare challenge page
const isCloudflare = await page.evaluate(() => {
const body = document.body.innerText;
const title = document.title;
return (
body.includes('Cloudflare') ||
body.includes('Just a moment') ||
body.includes('Checking your browser') ||
title.includes('Just a moment') ||
document.querySelector('#challenge-form') !== null ||
document.querySelector('.cf-browser-verification') !== null
);
});
if (isCloudflare) {
console.log('πŸ” Cloudflare challenge detected!');
console.log('⏳ Attempting to solve automatically...');
// Try to click the Cloudflare Turnstile checkbox
try {
// Wait for checkbox to be clickable
await page.waitForSelector('input[type="checkbox"]', { timeout: 5000, visible: true })
.catch(() => console.log('No visible checkbox found, trying iframe...'));
// Check for iframe (Cloudflare Turnstile uses iframe)
const frames = page.frames();
console.log(`Found ${frames.length} frames, checking for Cloudflare challenge...`);
let clicked = false;
for (const frame of frames) {
try {
// Try to find and click checkbox in iframe
const checkbox = await frame.$('input[type="checkbox"]');
if (checkbox) {
console.log('βœ“ Found checkbox in iframe, clicking...');
await checkbox.click();
clicked = true;
console.log('βœ“ Checkbox clicked!');
break;
}
// Try Turnstile specific selector
const turnstile = await frame.$('.cf-turnstile');
if (turnstile) {
console.log('βœ“ Found Turnstile widget, clicking...');
await turnstile.click();
clicked = true;
console.log('βœ“ Turnstile clicked!');
break;
}
// Try clicking the challenge box area
const challengeBox = await frame.$('#challenge-stage');
if (challengeBox) {
console.log('βœ“ Found challenge box, clicking...');
await challengeBox.click();
clicked = true;
console.log('βœ“ Challenge box clicked!');
break;
}
} catch (frameError) {
// Continue to next frame
}
}
if (!clicked) {
console.log('⚠️ Could not find clickable element, trying main page...');
// Try clicking on main page
const mainCheckbox = await page.$('input[type="checkbox"]').catch(() => null);
if (mainCheckbox) {
await mainCheckbox.click();
console.log('βœ“ Main page checkbox clicked!');
}
}
} catch (clickError) {
console.log('⚠️ Auto-click failed:', clickError.message);
}
// Simulate human-like mouse movements
try {
await wait(500);
await page.mouse.move(100, 100);
await wait(100);
await page.mouse.move(200, 200);
await wait(150);
await page.mouse.move(150, 300);
console.log('βœ“ Mouse movements simulated');
} catch (mouseError) {
console.log('Mouse simulation skipped');
}
const waitSeconds = CLOUDFLARE_WAIT / 1000;
console.log(`⏳ Waiting for Cloudflare to verify (up to ${waitSeconds} seconds)...`);
if (MANUAL_CLOUDFLARE) {
console.log('πŸ’‘ You can manually solve the challenge in the browser window!');
}
// Wait for Cloudflare challenge to complete
try {
await page.waitForFunction(
() => {
// Check if we've passed the challenge
const body = document.body.innerText;
const title = document.title;
return (
!body.includes('Just a moment') &&
!body.includes('Checking your browser') &&
!body.includes('Verify you are human') &&
!title.includes('Just a moment') &&
document.querySelector('#challenge-form') === null &&
document.querySelector('.cf-browser-verification') === null
);
},
{ timeout: CLOUDFLARE_WAIT, polling: 500 }
);
console.log('βœ“ Cloudflare challenge passed!');
// Take screenshot after passing challenge
await wait(2000);
await page.screenshot({ path: './after-cloudflare.png', fullPage: true });
console.log('Screenshot after Cloudflare: after-cloudflare.png');
} catch (cfError) {
console.log('⚠️ Cloudflare challenge timeout - may need manual intervention');
console.log('Taking screenshot of challenge page...');
await page.screenshot({ path: './cloudflare-challenge.png', fullPage: true });
console.log('Screenshot saved to cloudflare-challenge.png');
// Try to continue anyway
console.log('Attempting to continue despite challenge...');
}
} else {
console.log('Trying alternative approaches...');
// Wait and try reloading
await wait(2000);
try {
await page.reload({ waitUntil: ['domcontentloaded', 'networkidle2'], timeout: 30000 });
console.log('βœ“ Page reloaded with cookies');
} catch (reloadError) {
console.log('Reload had issues, but continuing...');
}
}
} else if (statusCode >= 400) {
console.log(`⚠️ Received error status: ${statusCode}`);
} else {
console.log('βœ“ Page loaded successfully');
}
} else {
console.log('⚠️ No response received, but page may have loaded');
}
// Set localStorage and sessionStorage if available
if (cookieData) {
if (cookieData.localStorage && Object.keys(cookieData.localStorage).length > 0) {
console.log('\nπŸ’Ύ Setting localStorage...');
try {
await page.evaluate((storage) => {
for (const [key, value] of Object.entries(storage)) {
try {
localStorage.setItem(key, value);
} catch (e) {
// Skip problematic items
}
}
}, cookieData.localStorage);
console.log('βœ“ localStorage set successfully');
} catch (error) {
console.log('⚠️ Could not set localStorage:', error.message);
}
}
if (cookieData.sessionStorage && Object.keys(cookieData.sessionStorage).length > 0) {
console.log('\nπŸ’Ύ Setting sessionStorage...');
try {
await page.evaluate((storage) => {
for (const [key, value] of Object.entries(storage)) {
try {
sessionStorage.setItem(key, value);
} catch (e) {
// Skip problematic items
}
}
}, cookieData.sessionStorage);
console.log('βœ“ sessionStorage set successfully');
} catch (error) {
console.log('⚠️ Could not set sessionStorage:', error.message);
}
}
// One more reload to ensure everything is applied
console.log('\nπŸ”„ Final reload to apply all data...');
try {
await page.reload({ waitUntil: ['domcontentloaded'], timeout: 30000 });
console.log('βœ“ Page reloaded');
} catch (reloadError) {
console.log('⚠️ Reload warning:', reloadError.message);
console.log('Continuing anyway...');
}
}
console.log('\n⏳ Waiting 10 seconds...');
await wait(10000);
// Take initial screenshot
console.log('\nπŸ“Έ Taking initial screenshot...');
await page.screenshot({
path: './betking-initial.png',
fullPage: true
});
console.log('\nπŸ” Checking if we bypassed 403 - looking for login input...');
// Check for username input field
let loginInputFound = false;
let bypass403Success = false;
try {
const usernameInput = await page.$('#username');
if (usernameInput) {
loginInputFound = true;
bypass403Success = true;
console.log('βœ… SUCCESS! Found username input - 403 bypass worked!');
console.log('βœ“ We are on the real login page!');
// Check if input is visible
const isVisible = await usernameInput.isIntersectingViewport();
console.log(`Username input is visible: ${isVisible}`);
// Get input attributes for confirmation
const inputInfo = await page.evaluate(() => {
const input = document.querySelector('#username');
if (input) {
return {
id: input.id,
type: input.type,
name: input.name,
placeholder: input.placeholder,
class: input.className
};
}
return null;
});
if (inputInfo) {
console.log('πŸ“‹ Input field details:');
console.log(JSON.stringify(inputInfo, null, 2));
}
// Check for other login elements
const otherElements = await page.evaluate(() => {
return {
passwordField: !!document.querySelector('#password') || !!document.querySelector('input[type="password"]'),
loginButton: !!document.querySelector('button[type="submit"]'),
totalInputs: document.querySelectorAll('input').length,
totalButtons: document.querySelectorAll('button').length,
pageTitle: document.title,
hasLoginForm: !!document.querySelector('form')
};
});
console.log('πŸ“Š Page structure analysis:');
console.log(` - Password field found: ${otherElements.passwordField}`);
console.log(` - Login button found: ${otherElements.loginButton}`);
console.log(` - Total inputs: ${otherElements.totalInputs}`);
console.log(` - Total buttons: ${otherElements.totalButtons}`);
console.log(` - Page title: ${otherElements.pageTitle}`);
console.log(` - Has form: ${otherElements.hasLoginForm}`);
} else {
console.log('❌ Username input NOT found - still blocked or wrong page');
}
} catch (error) {
console.log(`⚠️ Error checking for input: ${error.message}`);
}
// Also check if we're still on Cloudflare page
const stillOnCloudflare = await page.evaluate(() => {
const body = document.body.innerText;
const title = document.title;
return (
body.includes('Just a moment') ||
body.includes('Checking your browser') ||
body.includes('Verify you are human') ||
title.includes('Just a moment') ||
body.includes('Cloudflare')
);
});
if (stillOnCloudflare) {
console.log('⚠️ Still on Cloudflare challenge page');
} else if (!loginInputFound) {
console.log('⚠️ Not on Cloudflare, but also not on login page - checking what page we\'re on...');
const pageInfo = await page.evaluate(() => {
return {
url: window.location.href,
title: document.title,
bodyText: document.body.innerText.substring(0, 500),
h1: document.querySelector('h1')?.innerText,
errorMessage: document.querySelector('.error-message')?.innerText ||
document.querySelector('[class*="error"]')?.innerText
};
});
console.log('πŸ“„ Current page info:');
console.log(` - URL: ${pageInfo.url}`);
console.log(` - Title: ${pageInfo.title}`);
console.log(` - H1: ${pageInfo.h1}`);
if (pageInfo.errorMessage) {
console.log(` - Error message: ${pageInfo.errorMessage}`);
}
}
console.log('\nπŸ“Έ Taking final screenshot...');
if (bypass403Success) {
console.log('πŸŽ‰ STATUS: 403 BYPASS SUCCESSFUL - Login page reached!');
} else {
console.log('❌ STATUS: 403 bypass failed or still on challenge page');
}
await page.screenshot({
path: './betking-final.png',
fullPage: true
});
console.log('βœ“ Screenshot saved to betking-final.png');
// Upload screenshot to server
console.log('\nπŸ“€ Uploading screenshot to server...');
try {
const uploadUrl = await uploadToServer('./betking-final.png');
console.log('βœ“ Upload successful!');
console.log('\nπŸ”— Download link:');
console.log(uploadUrl);
console.log('\nπŸ“‹ Direct link (copy this):');
console.log(uploadUrl);
} catch (uploadError) {
console.error('❌ Failed to upload to server:', uploadError.message);
console.log('Screenshot is still saved locally at: ./betking-final.png');
}
} catch (error) {
console.error('\n❌ Error occurred:', error.message);
console.error('Stack trace:', error.stack);
try {
// Check if page is still open before trying to screenshot
if (!page.isClosed()) {
await page.screenshot({
path: './betking-error.png',
fullPage: true
});
console.log('Error screenshot saved to betking-error.png');
} else {
console.log('Page was closed, cannot take error screenshot');
}
} catch (screenshotError) {
console.error('Could not take error screenshot:', screenshotError.message);
}
} finally {
try {
if (browser) {
await browser.close();
console.log('\nβœ… Browser closed');
}
} catch (closeError) {
console.log('Browser already closed');
}
}
})();