feat[cloudflare]: integrate FlareSolverr for automated Cloudflare challenge resolution
- Add Cloudflare bypass functionality using FlareSolverr service - Configure FlareSolverr Docker service with environment options - Add flaresolverr_url config option with default localhost fallback - Replace manual Cloudflare challenge notification with automated solving attempt - Create new cloudflare.js module with health check, challenge detection, and solution application
This commit is contained in:
parent
1ddcf1d8af
commit
e0c97f8d7c
4 changed files with 214 additions and 1 deletions
|
|
@ -16,6 +16,7 @@ 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 => {
|
||||
|
|
@ -169,6 +170,63 @@ 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;
|
||||
|
||||
|
|
@ -181,7 +239,12 @@ const ensureLoggedIn = async (page, context) => {
|
|||
await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' });
|
||||
|
||||
if (await isChallenge()) {
|
||||
console.warn('Cloudflare challenge detected. Solve the captcha in the browser (no automation).');
|
||||
console.warn('Cloudflare challenge detected. Attempting to solve with FlareSolverr...');
|
||||
const solved = await solveCloudflareChallenge();
|
||||
if (solved) {
|
||||
await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' });
|
||||
continue;
|
||||
}
|
||||
await notify('epic-games (new): Cloudflare challenge, please solve manually in browser.');
|
||||
await page.waitForTimeout(cfg.login_timeout);
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue