diff --git a/docker-compose.yml b/docker-compose.yml index f8e1c85..f8d797b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,5 @@ # start with `docker compose up` services: - flaresolverr: - container_name: flaresolverr - image: flaresolverr/flaresolverr:latest - ports: - - "8191:8191" - environment: - - LOG_LEVEL=info - - LOG_HTML=false - - CAPTCHA_SOLVER=none - restart: unless-stopped - networks: - - fgc-network - free-games-claimer: container_name: fgc # is printed in front of every output line image: ghcr.io/vogler/free-games-claimer # otherwise image name will be free-games-claimer-free-games-claimer @@ -28,15 +15,6 @@ services: # - EMAIL=foo@bar.org # - NOTIFY='tgram://...' - EG_MODE=new - - FLARESOLVERR_URL=http://flaresolverr:8191/v1 - networks: - - fgc-network - depends_on: - - flaresolverr - -networks: - fgc-network: - driver: bridge volumes: fgc: diff --git a/epic-claimer-new.js b/epic-claimer-new.js index 1dfd612..04b8d33 100644 --- a/epic-claimer-new.js +++ b/epic-claimer-new.js @@ -16,7 +16,6 @@ import { cfg } from './src/config.js'; import { EPIC_CLIENT_ID, GRAPHQL_ENDPOINT, FREE_GAMES_PROMOTIONS_ENDPOINT, STORE_HOMEPAGE_EN, EPIC_PURCHASE_ENDPOINT, ID_LOGIN_ENDPOINT } from './src/constants.js'; import { setPuppeteerCookies } from './src/cookie.js'; import { getAccountAuth, setAccountAuth } from './src/device-auths.js'; -import { solveCloudflare, isCloudflareChallenge, waitForCloudflareSolved } from './src/cloudflare.js'; // Fetch Free Games from API using page.evaluate (browser context) const fetchFreeGamesAPI = async page => { @@ -170,63 +169,6 @@ const ensureLoggedIn = async (page, context) => { return await cfFrame.count() > 0 || await cfText.count() > 0; }; - const solveCloudflareChallenge = async () => { - try { - console.log('🔍 Detecting Cloudflare challenge...'); - - // Check if FlareSolverr is available - const flaresolverrUrl = cfg.flaresolverr_url || 'http://localhost:8191/v1'; - const healthResponse = await fetch(`${flaresolverrUrl}/health`, { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, - }); - - if (!healthResponse.ok) { - console.warn('⚠️ FlareSolverr not available at', flaresolverrUrl); - return false; - } - - // Send request to FlareSolverr - const response = await fetch(`${flaresolverrUrl}/request`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - cmd: 'request.get', - url: URL_CLAIM, - maxTimeout: 60000, - session: 'epic-games', - }), - }); - - const data = await response.json(); - - if (data.status !== 'ok') { - console.warn('FlareSolverr failed:', data.message); - return false; - } - - const solution = data.solution; - - // Apply cookies to the browser context - const cookies = solution.cookies.map(cookie => ({ - name: cookie.name, - value: cookie.value, - domain: cookie.domain, - path: cookie.path || '/', - secure: cookie.secure, - httpOnly: cookie.httpOnly, - })); - - await context.addCookies(cookies); - - console.log('✅ Cloudflare challenge solved by FlareSolverr'); - return true; - } catch (error) { - console.error('FlareSolverr error:', error.message); - return false; - } - }; - let loginAttempts = 0; const MAX_LOGIN_ATTEMPTS = 3; @@ -239,12 +181,7 @@ const ensureLoggedIn = async (page, context) => { await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' }); if (await isChallenge()) { - console.warn('Cloudflare challenge detected. Attempting to solve with FlareSolverr...'); - const solved = await solveCloudflareChallenge(); - if (solved) { - await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' }); - continue; - } + console.warn('Cloudflare challenge detected. Solve the captcha in the browser (no automation).'); await notify('epic-games (new): Cloudflare challenge, please solve manually in browser.'); await page.waitForTimeout(cfg.login_timeout); continue; diff --git a/src/cloudflare.js b/src/cloudflare.js deleted file mode 100644 index 6c3983c..0000000 --- a/src/cloudflare.js +++ /dev/null @@ -1,137 +0,0 @@ -import { existsSync, readFileSync, writeFileSync } from 'node:fs'; -import { cfg } from './config.js'; - -const FLARESOLVERR_URL = process.env.FLARESOLVERR_URL || 'http://localhost:8191/v1'; - -/** - * Check if FlareSolverr is available - */ -export const checkFlareSolverr = async () => { - try { - const response = await fetch(`${FLARESOLVERR_URL}/health`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }); - return response.ok; - } catch { - return false; - } -}; - -/** - * Solve Cloudflare challenge using FlareSolverr - * @param {Object} page - Playwright page object - * @param {string} url - The URL to visit - * @returns {Promise} - Solution object with cookies and user agent - */ -export const solveCloudflare = async (page, url) => { - try { - console.log('🔍 Detecting Cloudflare challenge...'); - - // Check if FlareSolverr is available - if (!await checkFlareSolverr()) { - console.warn('⚠️ FlareSolverr not available at', FLARESOLVERR_URL); - return null; - } - - // Send request to FlareSolverr - const response = await fetch(`${FLARESOLVERR_URL}/request`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - cmd: 'request.get', - url: url, - maxTimeout: 60000, - session: 'epic-games', - }), - }); - - const data = await response.json(); - - if (data.status !== 'ok') { - console.warn('FlareSolverr failed:', data.message); - return null; - } - - const solution = data.solution; - - // Apply cookies to the browser context - const cookies = solution.cookies.map(cookie => ({ - name: cookie.name, - value: cookie.value, - domain: cookie.domain, - path: cookie.path || '/', - secure: cookie.secure, - httpOnly: cookie.httpOnly, - })); - - // Get the browser context from the page - const context = page.context(); - await context.addCookies(cookies); - - console.log('✅ Cloudflare challenge solved by FlareSolverr'); - - return { - cookies, - userAgent: solution.userAgent, - html: solution.html, - }; - } catch (error) { - console.error('FlareSolverr error:', error.message); - return null; - } -}; - -/** - * Check if Cloudflare challenge is present on the page - * @param {Object} page - Playwright page object - * @returns {Promise} - True if Cloudflare challenge is detected - */ -export const isCloudflareChallenge = async page => { - try { - // Check for Cloudflare iframe - const cfFrame = page.locator('iframe[title*="Cloudflare"], iframe[src*="challenges"]'); - if (await cfFrame.count() > 0) { - return true; - } - - // Check for Cloudflare text - const cfText = page.locator('text=Verify you are human, text=Checking your browser'); - if (await cfText.count() > 0) { - return true; - } - - // Check for specific Cloudflare URLs - const url = page.url(); - if (url.includes('cloudflare') || url.includes('challenges')) { - return true; - } - - return false; - } catch { - return false; - } -}; - -/** - * Wait for Cloudflare challenge to be solved - * @param {Object} page - Playwright page object - * @param {number} timeout - Timeout in milliseconds - * @returns {Promise} - True if challenge is solved - */ -export const waitForCloudflareSolved = async (page, timeout = 60000) => { - const startTime = Date.now(); - - while (Date.now() - startTime < timeout) { - if (!await isCloudflareChallenge(page)) { - return true; - } - await new Promise(resolve => setTimeout(resolve, 1000)); - } - - return false; -}; diff --git a/src/config.js b/src/config.js index 89b6e04..7702984 100644 --- a/src/config.js +++ b/src/config.js @@ -35,8 +35,6 @@ export const cfg = { eg_password: process.env.EG_PASSWORD || process.env.PASSWORD, eg_otpkey: process.env.EG_OTPKEY, eg_parentalpin: process.env.EG_PARENTALPIN, - // Cloudflare bypass - flaresolverr_url: process.env.FLARESOLVERR_URL || 'http://localhost:8191/v1', // auth prime-gaming pg_email: process.env.PG_EMAIL || process.env.EMAIL, pg_password: process.env.PG_PASSWORD || process.env.PASSWORD,