Spaces:
Paused
Paused
| const express = require('express'); | |
| const puppeteer = require('puppeteer-extra'); | |
| const StealthPlugin = require('puppeteer-extra-plugin-stealth'); | |
| const randomUseragent = require('random-useragent'); | |
| const axios = require('axios'); | |
| const fs = require('fs'); | |
| const FormData = require('form-data'); | |
| puppeteer.use(StealthPlugin()); | |
| const app = express(); | |
| app.use(express.json()); | |
| // Enhanced random delay function | |
| const randomDelay = (min = 100, max = 300) => | |
| new Promise(resolve => setTimeout(resolve, Math.random() * (max - min) + min)); | |
| // Realistic mouse movement simulation | |
| const humanMouseMove = async (page, selector) => { | |
| const element = await page.$(selector); | |
| const box = await element.boundingBox(); | |
| // Simulate realistic mouse path | |
| await page.mouse.move( | |
| box.x + Math.random() * box.width, | |
| box.y + Math.random() * box.height, | |
| { steps: Math.floor(Math.random() * 10) + 5 } | |
| ); | |
| await randomDelay(50, 150); | |
| }; | |
| // Human-like typing with realistic patterns | |
| const humanType = async (page, selector, text, options = {}) => { | |
| await page.focus(selector); | |
| await randomDelay(100, 300); | |
| for (let i = 0; i < text.length; i++) { | |
| const char = text[i]; | |
| await page.keyboard.type(char); | |
| // Realistic typing delays | |
| let delay = Math.random() * 120 + 50; | |
| // Longer pauses for special characters | |
| if (['.', '@', '_', '-'].includes(char)) { | |
| delay += Math.random() * 100; | |
| } | |
| // Occasional longer pauses (thinking) | |
| if (Math.random() < 0.1) { | |
| delay += Math.random() * 400 + 200; | |
| } | |
| await new Promise(resolve => setTimeout(resolve, delay)); | |
| } | |
| }; | |
| // Random scrolling to simulate human behavior | |
| const humanScroll = async (page) => { | |
| const scrolls = Math.floor(Math.random() * 3) + 1; | |
| for (let i = 0; i < scrolls; i++) { | |
| const scrollDistance = Math.random() * 500 + 100; | |
| const direction = Math.random() > 0.5 ? 1 : -1; | |
| await page.evaluate((distance, dir) => { | |
| window.scrollBy(0, distance * dir); | |
| }, scrollDistance, direction); | |
| await randomDelay(500, 1500); | |
| } | |
| // Scroll back to top | |
| await page.evaluate(() => window.scrollTo(0, 0)); | |
| await randomDelay(300, 800); | |
| }; | |
| // Simulate random mouse movements | |
| const simulateHumanActivity = async (page) => { | |
| // Random mouse movements | |
| for (let i = 0; i < Math.random() * 5 + 2; i++) { | |
| await page.mouse.move( | |
| Math.random() * 1920, | |
| Math.random() * 1080, | |
| { steps: Math.floor(Math.random() * 20) + 10 } | |
| ); | |
| await randomDelay(200, 800); | |
| } | |
| // Random clicks in empty areas | |
| if (Math.random() > 0.7) { | |
| await page.mouse.click(Math.random() * 200 + 100, Math.random() * 200 + 100); | |
| await randomDelay(100, 300); | |
| } | |
| }; | |
| async function uploadToCatbox(filePath) { | |
| const form = new FormData(); | |
| form.append('reqtype', 'fileupload'); | |
| form.append('fileToUpload', fs.createReadStream(filePath)); | |
| const response = await axios.post('https://catbox.moe/user/api.php', form, { | |
| headers: form.getHeaders(), | |
| }); | |
| return response.data; | |
| } | |
| app.post('/login', async (req, res) => { | |
| const { email, password } = req.body; | |
| if (!email || !password) { | |
| return res.status(400).json({ error: 'Missing email or password' }); | |
| } | |
| let browser; | |
| try { | |
| // Enhanced browser launch options | |
| browser = await puppeteer.launch({ | |
| headless: true, | |
| defaultViewport: null, | |
| args: [ | |
| '--no-sandbox', | |
| '--disable-setuid-sandbox', | |
| '--disable-blink-features=AutomationControlled', | |
| '--disable-dev-shm-usage', | |
| '--disable-infobars', | |
| '--disable-extensions', | |
| '--disable-plugins', | |
| '--disable-images', | |
| '--disable-javascript-harmony-shipping', | |
| '--disable-background-timer-throttling', | |
| '--disable-backgrounding-occluded-windows', | |
| '--disable-renderer-backgrounding', | |
| '--disable-features=TranslateUI', | |
| '--disable-ipc-flooding-protection', | |
| '--disable-hang-monitor', | |
| '--disable-popup-blocking', | |
| '--disable-prompt-on-repost', | |
| '--disable-sync', | |
| '--disable-domain-reliability', | |
| '--disable-component-extensions-with-background-pages', | |
| '--no-default-browser-check', | |
| '--no-first-run', | |
| '--no-pings', | |
| '--password-store=basic', | |
| '--use-mock-keychain', | |
| '--disable-background-networking', | |
| '--disable-default-apps', | |
| '--disable-translate', | |
| '--disable-device-discovery-notifications', | |
| '--window-size=1920,1080', | |
| '--window-position=0,0', | |
| '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36' | |
| ], | |
| ignoreDefaultArgs: ['--enable-automation'], | |
| ignoreHTTPSErrors: true, | |
| }); | |
| const page = await browser.newPage(); | |
| // Enhanced stealth configurations | |
| await page.evaluateOnNewDocument(() => { | |
| // Remove webdriver property | |
| Object.defineProperty(navigator, 'webdriver', { | |
| get: () => undefined, | |
| }); | |
| // Spoof navigator properties | |
| Object.defineProperty(navigator, 'languages', { | |
| get: () => ['en-US', 'en'], | |
| }); | |
| Object.defineProperty(navigator, 'plugins', { | |
| get: () => [ | |
| { | |
| 0: {type: "application/x-google-chrome-pdf", suffixes: "pdf", description: "Portable Document Format", enabledPlugin: "[object Plugin]"}, | |
| description: "Portable Document Format", | |
| filename: "internal-pdf-viewer", | |
| length: 1, | |
| name: "Chrome PDF Plugin" | |
| }, | |
| { | |
| 0: {type: "application/pdf", suffixes: "pdf", description: "", enabledPlugin: "[object Plugin]"}, | |
| description: "", | |
| filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai", | |
| length: 1, | |
| name: "Chrome PDF Viewer" | |
| } | |
| ], | |
| }); | |
| Object.defineProperty(navigator, 'platform', { | |
| get: () => 'Win32', | |
| }); | |
| Object.defineProperty(navigator, 'hardwareConcurrency', { | |
| get: () => 8, | |
| }); | |
| Object.defineProperty(navigator, 'deviceMemory', { | |
| get: () => 8, | |
| }); | |
| // Spoof screen properties | |
| Object.defineProperty(screen, 'width', { | |
| get: () => 1920, | |
| }); | |
| Object.defineProperty(screen, 'height', { | |
| get: () => 1080, | |
| }); | |
| Object.defineProperty(screen, 'colorDepth', { | |
| get: () => 24, | |
| }); | |
| Object.defineProperty(screen, 'pixelDepth', { | |
| get: () => 24, | |
| }); | |
| // Override permissions | |
| const originalQuery = window.navigator.permissions.query; | |
| window.navigator.permissions.query = (parameters) => ( | |
| parameters.name === 'notifications' ? | |
| Promise.resolve({ state: Notification.permission }) : | |
| originalQuery(parameters) | |
| ); | |
| // Spoof timezone | |
| Date.prototype.getTimezoneOffset = function() { | |
| return -300; // EST timezone | |
| }; | |
| // Remove automation indicators | |
| delete navigator.__proto__.webdriver; | |
| // Mock chrome runtime | |
| window.chrome = { | |
| runtime: { | |
| onConnect: undefined, | |
| onMessage: undefined, | |
| connect: undefined, | |
| sendMessage: undefined, | |
| }, | |
| }; | |
| // Spoof canvas fingerprinting | |
| const getContext = HTMLCanvasElement.prototype.getContext; | |
| HTMLCanvasElement.prototype.getContext = function(a, b) { | |
| const context = getContext.call(this, a, b); | |
| if (a === '2d') { | |
| const originalIsPointInPath = context.isPointInPath; | |
| context.isPointInPath = function() { | |
| return originalIsPointInPath.apply(this, arguments); | |
| }; | |
| } | |
| return context; | |
| }; | |
| // Spoof WebGL fingerprinting | |
| const getParameter = WebGLRenderingContext.prototype.getParameter; | |
| WebGLRenderingContext.prototype.getParameter = function(parameter) { | |
| if (parameter === 37445) { | |
| return 'Intel Open Source Technology Center'; | |
| } | |
| if (parameter === 37446) { | |
| return 'Mesa DRI Intel(R) Ivybridge Mobile '; | |
| } | |
| return getParameter.call(this, parameter); | |
| }; | |
| }); | |
| // Set realistic viewport and user agent | |
| const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'; | |
| await page.setUserAgent(userAgent); | |
| await page.setViewport({ | |
| width: 1920, | |
| height: 1080, | |
| deviceScaleFactor: 1, | |
| hasTouch: false, | |
| isLandscape: true, | |
| isMobile: false, | |
| }); | |
| // Enhanced HTTP headers | |
| await page.setExtraHTTPHeaders({ | |
| 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8', | |
| 'Accept-Language': 'en-US,en;q=0.9', | |
| 'Accept-Encoding': 'gzip, deflate, br', | |
| 'DNT': '1', | |
| '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', | |
| }); | |
| // Request interception for performance | |
| await page.setRequestInterception(true); | |
| page.on('request', (req) => { | |
| const type = req.resourceType(); | |
| if (['image', 'stylesheet', 'font', 'media'].includes(type)) { | |
| req.abort(); | |
| } else { | |
| req.continue(); | |
| } | |
| }); | |
| console.log('π Navigating to login page...'); | |
| await page.goto('https://sso.crunchyroll.com/login', { | |
| waitUntil: 'networkidle2', | |
| timeout: 60000, | |
| }); | |
| // Wait and simulate human behavior | |
| await randomDelay(2000, 4000); | |
| await simulateHumanActivity(page); | |
| await humanScroll(page); | |
| // Wait for form elements with better error handling | |
| try { | |
| await page.waitForSelector('input[name="email"]', { timeout: 30000 }); | |
| console.log('π§ Email input found'); | |
| } catch (error) { | |
| console.log('β Email input not found, trying alternative selectors'); | |
| await page.waitForSelector('input[type="email"], #email, [placeholder*="email" i]', { timeout: 30000 }); | |
| } | |
| // Simulate human-like interaction with email field | |
| await humanMouseMove(page, 'input[name="email"]'); | |
| await page.click('input[name="email"]'); | |
| await randomDelay(500, 1200); | |
| // Clear field first (in case there's placeholder text) | |
| await page.keyboard.down('Control'); | |
| await page.keyboard.press('a'); | |
| await page.keyboard.up('Control'); | |
| await page.keyboard.press('Backspace'); | |
| await randomDelay(200, 500); | |
| await humanType(page, 'input[name="email"]', email); | |
| console.log('β Email entered'); | |
| await randomDelay(800, 1500); | |
| // Similar approach for password | |
| try { | |
| await page.waitForSelector('input[name="password"]', { timeout: 10000 }); | |
| } catch (error) { | |
| await page.waitForSelector('input[type="password"], #password, [placeholder*="password" i]', { timeout: 30000 }); | |
| } | |
| await humanMouseMove(page, 'input[name="password"]'); | |
| await page.click('input[name="password"]'); | |
| await randomDelay(300, 800); | |
| await humanType(page, 'input[name="password"]', password); | |
| console.log('π Password entered'); | |
| // Random delay before clicking login | |
| await randomDelay(1000, 2500); | |
| await simulateHumanActivity(page); | |
| // Find and interact with login button | |
| let loginButton; | |
| try { | |
| await page.waitForSelector('button[data-t="login-button"]', { visible: true, timeout: 10000 }); | |
| loginButton = 'button[data-t="login-button"]'; | |
| } catch (error) { | |
| // Try alternative selectors | |
| const buttonSelectors = [ | |
| 'button[type="submit"]', | |
| 'input[type="submit"]', | |
| 'button:contains("Log in")', | |
| 'button:contains("Sign in")', | |
| '[role="button"]:contains("Log")', | |
| '.login-button', | |
| '#login-button' | |
| ]; | |
| for (const selector of buttonSelectors) { | |
| try { | |
| await page.waitForSelector(selector, { visible: true, timeout: 2000 }); | |
| loginButton = selector; | |
| break; | |
| } catch (e) { | |
| continue; | |
| } | |
| } | |
| } | |
| if (!loginButton) { | |
| throw new Error('Login button not found'); | |
| } | |
| // Screenshot before clicking login | |
| const beforePath = './before-login.png'; | |
| await page.screenshot({ path: beforePath, fullPage: true }); | |
| const beforeUrl = await uploadToCatbox(beforePath); | |
| console.log('π‘ Before login screenshot uploaded:', beforeUrl); | |
| // Human-like button interaction | |
| await humanMouseMove(page, loginButton); | |
| await randomDelay(200, 500); | |
| // Sometimes hover before clicking | |
| if (Math.random() > 0.5) { | |
| await page.hover(loginButton); | |
| await randomDelay(100, 300); | |
| } | |
| await page.click(loginButton); | |
| console.log('π Login button clicked'); | |
| // Wait for navigation or response | |
| try { | |
| await Promise.race([ | |
| page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 45000 }), | |
| page.waitForSelector('.error, [class*="error"], [id*="error"]', { timeout: 30000 }) | |
| .then(() => { throw new Error('Login error detected'); }), | |
| new Promise(resolve => setTimeout(resolve, 40000)) // Fallback timeout | |
| ]); | |
| } catch (navError) { | |
| console.log('β οΈ Navigation wait completed with potential issues'); | |
| } | |
| // Additional wait for any dynamic content | |
| await randomDelay(3000, 6000); | |
| // Screenshot after login attempt | |
| const afterPath = './after-login.png'; | |
| await page.screenshot({ path: afterPath, fullPage: true }); | |
| const afterUrl = await uploadToCatbox(afterPath); | |
| console.log('π’ After login screenshot uploaded:', afterUrl); | |
| const currentUrl = page.url(); | |
| const loginSuccess = !currentUrl.includes('/login') && !currentUrl.includes('sso.crunchyroll.com'); | |
| // Additional success indicators | |
| const hasAuthCookie = (await page.cookies()).some(cookie => | |
| cookie.name.toLowerCase().includes('auth') || | |
| cookie.name.toLowerCase().includes('session') || | |
| cookie.name.toLowerCase().includes('token') | |
| ); | |
| console.log(`π― Login Result: ${loginSuccess ? 'SUCCESS' : 'FAILED'}`); | |
| console.log(`π Current URL: ${currentUrl}`); | |
| console.log(`πͺ Auth cookies present: ${hasAuthCookie}`); | |
| res.json({ | |
| success: loginSuccess, | |
| currentUrl: currentUrl, | |
| userAgent: userAgent, | |
| hasAuthCookie: hasAuthCookie, | |
| screenshots: { | |
| before: beforeUrl, | |
| after: afterUrl | |
| }, | |
| timestamp: new Date().toISOString() | |
| }); | |
| } catch (err) { | |
| console.error('β Error during login:', err); | |
| res.status(500).json({ | |
| error: 'Login failed', | |
| details: err.message, | |
| timestamp: new Date().toISOString() | |
| }); | |
| } finally { | |
| if (browser) { | |
| await browser.close(); | |
| } | |
| } | |
| }); | |
| const PORT = process.env.PORT || 7860; | |
| app.listen(PORT, () => { | |
| console.log(`π Enhanced Anti-Detection Server running on port ${PORT}`); | |
| console.log(`π‘οΈ Stealth features enabled: Human typing, mouse movement, scrolling, fingerprint spoofing`); | |
| }); |