diff --git a/main.captcha.js b/main.captcha.js index a698df8c..56a62176 100644 --- a/main.captcha.js +++ b/main.captcha.js @@ -3,6 +3,7 @@ if (!existsSync('auth.json')) { console.error('Missing auth.json! Run `npm login` to login and create this file by closing the opened browser.'); } +// npm i playwright playwright-extra@next @extra/recaptcha@next const { chromium } = require('playwright-extra') // add recaptcha plugin and provide it your 2captcha token (= their apiKey) diff --git a/main.stealth.js b/main.stealth.js new file mode 100644 index 00000000..0c2a3d50 --- /dev/null +++ b/main.stealth.js @@ -0,0 +1,66 @@ +const { existsSync } = require('fs'); +if (!existsSync('auth.json')) { + console.error('Missing auth.json! Run `npm login` to login and create this file by closing the opened browser.'); +} + +const { chromium } = require('playwright'); + +(async () => { + const browser = await chromium.launch({ + channel: 'chrome', + headless: false, + }); + // https://github.com/berstend/puppeteer-extra/issues/454#issuecomment-917437212 + const originalUserAgent = await (await (await browser.newContext()).newPage()).evaluate(() => { return navigator.userAgent }); + console.log(originalUserAgent); + const context = await browser.newContext({ + storageState: 'auth.json', + viewport: { width: 1280, height: 1280 }, + userAgent: originalUserAgent.replace("Headless", ""), + }); + const enabledEvasions = [ + 'chrome.app', + 'chrome.csi', + 'chrome.loadTimes', + 'chrome.runtime', + 'iframe.contentWindow', + 'media.codecs', + 'navigator.hardwareConcurrency', + 'navigator.languages', + 'navigator.permissions', + 'navigator.plugins', + 'navigator.webdriver', + 'sourceurl', + // 'user-agent-override', // doesn't work since playwright has no page.browser() + 'webgl.vendor', + 'window.outerdimensions' + ]; + const evasions = enabledEvasions.map(e => new require(`puppeteer-extra-plugin-stealth/evasions/${e}`)); + const stealth = { + callbacks: [], + async evaluateOnNewDocument(...args) { + this.callbacks.push({ cb: args[0], a: args[1] }) + } + } + evasions.forEach(e => e().onPageCreated(stealth)); + for (let evasion of stealth.callbacks) { + await context.addInitScript(evasion.cb, evasion.a); + } + + const page = await context.newPage(); + await page.goto('https://www.epicgames.com/store/en-US/free-games'); + // await expect(page.locator('a[role="button"]:has-text("Sign In")')).toHaveCount(0); + await page.click('button:has-text("Accept All Cookies")'); // to not waste screen space in --debug + await page.click('[data-testid="offer-card-image-landscape"]'); + // TODO check if already claimed + await page.click('[data-testid="purchase-cta-button"]'); + await page.click('button:has-text("Continue")'); + // it then creates an iframe for the rest + // await page.frame({ url: /.*store\/purchase.*/ }).click('button:has-text("Place Order")'); // not found because it does not wait for iframe + const iframe = page.frameLocator('.webPurchaseContainer iframe') + await iframe.locator('button:has-text("Place Order")').click(); + await iframe.locator('button:has-text("I Agree")').click(); + await page.pause(); + await context.close(); + await browser.close(); +})(); diff --git a/package-lock.json b/package-lock.json index c50f71bc..a8d893e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "@playwright/test": "^1.17.1", "dotenv": "^10.0.0", "playwright": "^1.17.1", - "playwright-extra": "^4.2.1-next.616" + "playwright-extra": "^4.2.1-next.616", + "puppeteer-extra-plugin-stealth": "^2.9.0" } }, "node_modules/@babel/code-frame": { @@ -1601,6 +1602,20 @@ "dev": true, "peer": true }, + "node_modules/fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2161,6 +2176,18 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -2712,6 +2739,49 @@ "puppeteer-extra": "*" } }, + "node_modules/puppeteer-extra-plugin-stealth": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.9.0.tgz", + "integrity": "sha512-erZ9lkIcOkfYmLPP2jv2AiqvNBFhQJinWJhcm40pqSjwJTsZXHsTARUyRCsBYEEBvNIs3Wz3E0zVlTRc4IJ6Hg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "puppeteer-extra-plugin": "^3.2.0", + "puppeteer-extra-plugin-user-preferences": "^2.3.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/puppeteer-extra-plugin-user-data-dir": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.3.1.tgz", + "integrity": "sha512-yhaYMaNFdfQ1LbA94ZElW1zU8rh+MFmO+GZA0gtQ8BXc+UZ6aRrWS9flIZvlXDzk+ZsXhCbTEohEwZ8lEDLRVA==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^10.0.0", + "puppeteer-extra-plugin": "^3.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/puppeteer-extra-plugin-user-preferences": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.3.1.tgz", + "integrity": "sha512-t/FyGQj2aqtHOROqL02z+k2kNQe0cjT0Hd9pG5FJ7x0JXx1722PhOuK7FeJLQMJ+BLl2YvCUgaWSC8Zohjts5A==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "deepmerge": "^4.2.2", + "puppeteer-extra-plugin": "^3.2.0", + "puppeteer-extra-plugin-user-data-dir": "^2.3.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/puppeteer/node_modules/debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", @@ -3066,6 +3136,15 @@ "through": "^2.3.8" } }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4334,6 +4413,17 @@ "dev": true, "peer": true }, + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4736,6 +4826,16 @@ "minimist": "^1.2.5" } }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -5181,6 +5281,40 @@ "merge-deep": "^3.0.1" } }, + "puppeteer-extra-plugin-stealth": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.9.0.tgz", + "integrity": "sha512-erZ9lkIcOkfYmLPP2jv2AiqvNBFhQJinWJhcm40pqSjwJTsZXHsTARUyRCsBYEEBvNIs3Wz3E0zVlTRc4IJ6Hg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "puppeteer-extra-plugin": "^3.2.0", + "puppeteer-extra-plugin-user-preferences": "^2.3.1" + } + }, + "puppeteer-extra-plugin-user-data-dir": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.3.1.tgz", + "integrity": "sha512-yhaYMaNFdfQ1LbA94ZElW1zU8rh+MFmO+GZA0gtQ8BXc+UZ6aRrWS9flIZvlXDzk+ZsXhCbTEohEwZ8lEDLRVA==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "fs-extra": "^10.0.0", + "puppeteer-extra-plugin": "^3.2.0" + } + }, + "puppeteer-extra-plugin-user-preferences": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.3.1.tgz", + "integrity": "sha512-t/FyGQj2aqtHOROqL02z+k2kNQe0cjT0Hd9pG5FJ7x0JXx1722PhOuK7FeJLQMJ+BLl2YvCUgaWSC8Zohjts5A==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "deepmerge": "^4.2.2", + "puppeteer-extra-plugin": "^3.2.0", + "puppeteer-extra-plugin-user-data-dir": "^2.3.1" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -5421,6 +5555,12 @@ "through": "^2.3.8" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 12f75ea8..a746e7ec 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,15 @@ "codegen": "npx playwright codegen --load-storage=auth.json https://www.epicgames.com/store/en-US/free-games", "start": "npx playwright test --timeout 10000", "debug": "npx playwright test --debug", - "captcha": "node main.captcha" + "captcha": "node main.captcha", + "stealth": "node main.stealth" }, "devDependencies": { "@extra/recaptcha": "^4.2.1-next.616", "@playwright/test": "^1.17.1", "dotenv": "^10.0.0", "playwright": "^1.17.1", - "playwright-extra": "^4.2.1-next.616" + "playwright-extra": "^4.2.1-next.616", + "puppeteer-extra-plugin-stealth": "^2.9.0" } }