diff --git a/Auto-Image.js b/Auto-Image.js index 3b12d07..fde2f4f 100644 --- a/Auto-Image.js +++ b/Auto-Image.js @@ -6,12 +6,13 @@ WHITE_THRESHOLD: 250, LOG_INTERVAL: 10, PAINTING_SPEED: { - MIN: 1, // Minimum 1 pixel per second - MAX: 1000, // Maximum 1000 pixels per second - DEFAULT: 5, // Default 5 pixels per second + MIN: 1, // Minimum 1 pixel batch size + MAX: 1000, // Maximum 1000 pixels batch size + DEFAULT: 5, // Default 5 pixels batch size }, - PAINTING_SPEED_ENABLED: false, + PAINTING_SPEED_ENABLED: false, // Off by default AUTO_CAPTCHA_ENABLED: true, // Turnstile generator enabled by default + TOKEN_SOURCE: "generator", // "generator", "manual", or "hybrid" - default to generator COOLDOWN_CHARGE_THRESHOLD: 1, // Default wait threshold OVERLAY: { OPACITY_DEFAULT: 0.6, @@ -1050,8 +1051,9 @@ lastPosition: { x: 0, y: 0 }, estimatedTime: 0, language: "en", - paintingSpeed: CONFIG.PAINTING_SPEED.DEFAULT, // pixels per second + paintingSpeed: CONFIG.PAINTING_SPEED.DEFAULT, // pixels batch size cooldownChargeThreshold: CONFIG.COOLDOWN_CHARGE_THRESHOLD, + tokenSource: CONFIG.TOKEN_SOURCE, // "generator" or "manual" overlayOpacity: CONFIG.OVERLAY.OPACITY_DEFAULT, blueMarbleEnabled: CONFIG.OVERLAY.BLUE_MARBLE_DEFAULT, ditheringEnabled: true, @@ -1635,7 +1637,7 @@ }); }, - // Create or reuse the turnstile container + // Create or reuse the turnstile container - completely hidden for token generation ensureTurnstileContainer() { if (!this._turnstileContainer || !document.body.contains(this._turnstileContainer)) { // Clean up old container if it exists @@ -1646,13 +1648,15 @@ this._turnstileContainer = document.createElement('div'); this._turnstileContainer.style.cssText = ` position: fixed !important; - left: -9999px !important; /* keep off-screen for invisible mode */ - top: -9999px !important; - width: 300px !important; - height: 65px !important; + left: -99999px !important; + top: -99999px !important; + width: 1px !important; + height: 1px !important; pointer-events: none !important; - opacity: 0 !important; /* do not use visibility:hidden to avoid engine quirks */ - z-index: -1 !important; + opacity: 0 !important; + visibility: hidden !important; + z-index: -99999 !important; + overflow: hidden !important; `; this._turnstileContainer.setAttribute('aria-hidden', 'true'); this._turnstileContainer.id = 'turnstile-widget-container'; @@ -1661,43 +1665,11 @@ return this._turnstileContainer; }, + // No interactive overlay container needed - pure background operation ensureTurnstileOverlayContainer() { - if (this._turnstileOverlay && document.body.contains(this._turnstileOverlay)) { - return this._turnstileOverlay; - } - const overlay = document.createElement('div'); - overlay.id = 'turnstile-overlay-container'; - overlay.style.cssText = ` - position: fixed; - right: 16px; - bottom: 16px; - width: 320px; - min-height: 80px; - background: rgba(0,0,0,0.7); - border: 1px solid rgba(255,255,255,0.2); - border-radius: 10px; - padding: 12px; - z-index: 100000; - backdrop-filter: blur(6px); - color: #fff; - box-shadow: 0 8px 24px rgba(0,0,0,0.4); - `; - const title = document.createElement('div'); - title.textContent = 'Cloudflare Turnstile — please complete the check if shown'; - title.style.cssText = 'font: 600 12px/1.3 \"Segoe UI\",sans-serif; margin-bottom: 8px; opacity: 0.9;'; - const widgetHost = document.createElement('div'); - widgetHost.id = 'turnstile-overlay-host'; - widgetHost.style.cssText = 'width: 100%; min-height: 70px;'; - const closeBtn = document.createElement('button'); - closeBtn.textContent = 'Hide'; - closeBtn.style.cssText = 'position:absolute; top:6px; right:6px; font-size:11px; background:transparent; color:#fff; border:1px solid rgba(255,255,255,0.2); border-radius:6px; padding:2px 6px; cursor:pointer;'; - closeBtn.addEventListener('click', () => overlay.remove()); - overlay.appendChild(title); - overlay.appendChild(widgetHost); - overlay.appendChild(closeBtn); - document.body.appendChild(overlay); - this._turnstileOverlay = overlay; - return overlay; + // Return null since we don't want any visible widgets + console.log('🚫 Interactive Turnstile overlay disabled - background mode only'); + return null; }, async executeTurnstile(sitekey, action = 'paint') { @@ -1734,85 +1706,65 @@ } const container = this.ensureTurnstileContainer(); container.innerHTML = ''; + + // Set a timeout to resolve with null if no token is received + const timeout = setTimeout(() => { + console.warn('⏰ Turnstile widget timeout - no token received'); + resolve(null); + }, 15000); + const widgetId = window.turnstile.render(container, { sitekey, action, - size: 'invisible', + size: 'compact', retry: 'auto', 'retry-interval': 8000, callback: (token) => { - console.log('✅ Invisible Turnstile callback'); + clearTimeout(timeout); + console.log('✅ Turnstile token received from hidden widget:', token ? 'Valid token' : 'Invalid token'); resolve(token); }, - 'error-callback': () => resolve(null), - 'timeout-callback': () => resolve(null), + 'error-callback': (error) => { + clearTimeout(timeout); + console.warn('❌ Turnstile error callback:', error); + resolve(null); + }, + 'timeout-callback': () => { + clearTimeout(timeout); + console.warn('⏰ Turnstile timeout callback'); + resolve(null); + }, }); + this._turnstileWidgetId = widgetId; this._lastSitekey = sitekey; - if (!widgetId) return resolve(null); - Promise.race([ - window.turnstile.execute(widgetId, { action }), - new Promise((_, reject) => setTimeout(() => reject(new Error('Invisible execute timeout')), 12000)) - ]).then(resolve).catch(() => resolve(null)); + + if (!widgetId) { + clearTimeout(timeout); + console.warn('❌ Failed to create Turnstile widget'); + resolve(null); + } } catch (e) { - console.warn('Invisible Turnstile failed:', e); + console.warn('❌ Invisible Turnstile failed:', e); resolve(null); } }); }, async createNewTurnstileWidgetInteractive(sitekey, action) { - return new Promise((resolve, reject) => { - try { - if (this._turnstileWidgetId && window.turnstile?.remove) { - try { window.turnstile.remove(this._turnstileWidgetId); } catch {} - } - - const overlay = this.ensureTurnstileOverlayContainer(); - const host = overlay.querySelector('#turnstile-overlay-host'); - host.innerHTML = ''; - - const timeoutId = setTimeout(() => { - console.warn('⏰ Interactive Turnstile timed out'); - resolve(null); - }, 120000); // give users up to 2 minutes - - const widgetId = window.turnstile.render(host, { - sitekey, - action, - size: 'normal', - retry: 'auto', - 'retry-interval': 8000, - callback: (token) => { - clearTimeout(timeoutId); - // Hide overlay after success - try { overlay.remove(); } catch {} - console.log('✅ Interactive Turnstile solved'); - resolve(token); - }, - 'error-callback': (error) => { - console.warn('🚨 Interactive Turnstile error:', error); - }, - 'timeout-callback': () => { - console.warn('⏰ Turnstile timeout callback (interactive)'); - }, - 'expired-callback': () => { - console.warn('⚠️ Interactive Turnstile token expired'); - } - }); - - this._turnstileWidgetId = widgetId; - this._lastSitekey = sitekey; - if (!widgetId) { - clearTimeout(timeoutId); - resolve(null); - return; - } - } catch (error) { - console.error('❌ Error creating interactive Turnstile widget:', error); - reject(error); - } - }); + // Since we want purely background token generation, attempt invisible again + // or fallback to manual pixel placement automation + console.log('🔄 Interactive widget requested - falling back to invisible or manual automation'); + + // Try invisible one more time + const invisibleToken = await this.createNewTurnstileWidgetInvisible(sitekey, action); + if (invisibleToken && invisibleToken.length > 20) { + return invisibleToken; + } + + // If invisible fails, return null to trigger manual automation fallback + console.log('⚠️ All Turnstile methods exhausted, manual fallback will be used'); + return null; }, async generatePaintToken(sitekey) { @@ -1832,13 +1784,10 @@ if (this._turnstileContainer && document.body.contains(this._turnstileContainer)) { this._turnstileContainer.remove(); } - if (this._turnstileOverlay && document.body.contains(this._turnstileOverlay)) { - this._turnstileOverlay.remove(); - } this._turnstileWidgetId = null; this._turnstileContainer = null; - this._turnstileOverlay = null; + this._turnstileOverlay = null; // Keep for compatibility but won't exist this._lastSitekey = null; }, @@ -2808,29 +2757,44 @@ } async function handleCaptcha() { const startTime = performance.now(); + + // Check user's token source preference + if (state.tokenSource === "manual") { + console.log("🎯 Manual token source selected - using pixel placement automation"); + return await handleCaptchaFallback(); + } + + // Generator mode (pure) or Hybrid mode - try generator first try { // Use optimized token generation with automatic sitekey detection const sitekey = Utils.detectSitekey(); console.log("🔑 Generating Turnstile token for sitekey:", sitekey); - console.log('🧭 UA:', navigator.userAgent, 'Platform:', navigator.platform); + console.log('🧭 UA:', navigator.userAgent, 'Platform:', navigator.platform); const token = await Utils.generatePaintToken(sitekey); + console.log(`🔍 Token received - Type: ${typeof token}, Value: ${token ? (token.length > 50 ? token.substring(0, 50) + '...' : token) : 'null/undefined'}, Length: ${token?.length || 0}`); + if (token && token.length > 20) { const duration = Math.round(performance.now() - startTime); console.log(`✅ Turnstile token generated successfully in ${duration}ms`); return token; } else { - throw new Error("Invalid or empty token received"); + throw new Error(`Invalid or empty token received - Type: ${typeof token}, Length: ${token?.length || 0}`); } } catch (error) { const duration = Math.round(performance.now() - startTime); console.error(`❌ Turnstile token generation failed after ${duration}ms:`, error); - // Fallback to original browser automation if Turnstile fails - console.log("🔄 Falling back to browser automation..."); - const fbToken = await handleCaptchaFallback(); - return fbToken; + // Fallback to manual pixel placement for hybrid mode + if (state.tokenSource === "hybrid") { + console.log("🔄 Hybrid mode: Generator failed, automatically switching to manual pixel placement..."); + const fbToken = await handleCaptchaFallback(); + return fbToken; + } else { + // Pure generator mode - don't fallback, just fail + throw error; + } } } @@ -4289,14 +4253,44 @@
+ Generator mode creates tokens automatically. Hybrid mode falls back to manual when generator fails. Manual mode only uses pixel placement. +
+