Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support geetest #47

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 85 additions & 5 deletions helpers/captcha.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const rp = require('request-promise');

const apiKey = process.env.API_KEY_2CAPTCHA;

async function submitCaptcha(googleKey, pageUrl) {
async function submitReCAPTCHAV2(googleKey, pageUrl) {
try {
const options = {
uri: `http://2captcha.com/in.php?key=${apiKey}&method=userrecaptcha&googlekey=${googleKey}&pageurl=${pageUrl}&json=1`,
Expand All @@ -21,6 +21,27 @@ async function submitCaptcha(googleKey, pageUrl) {
}
}

async function submitGeeTest(gt, challenge, api_server, pageUrl) {
try {
const options = {
uri: `
http://2captcha.com/in.php?key=${apiKey}&method=geetest&gt=${gt}&challenge=${challenge}&api_server=${api_server}&pageurl=${pageUrl}&json=1
`,
method: 'POST'
};

const response = await rp(options);
const responseJson = JSON.parse(response);
if (responseJson.status) {
return responseJson;
}

throw new Error(responseJson.error_text);
} catch (err) {
throw err;
}
}

async function getCaptchaResult(captchaId) {
try {
const options = {
Expand All @@ -40,7 +61,7 @@ async function getCaptchaResult(captchaId) {
}
}

exports.solveCaptcha = async ({
exports.solveReCAPTCHAV2 = async ({
taskLogger, page, captchaSelector, captchaIframeSelector
}) => {
try {
Expand All @@ -66,7 +87,7 @@ exports.solveCaptcha = async ({
}, { captchaSelector, captchaIframeSelector });
taskLogger.info(`Extracted googleKey ${googleKey}`);

const captcha = await submitCaptcha(googleKey, context.url());
const captcha = await submitReCAPTCHAV2(googleKey, context.url());
const captchaId = captcha.request;
taskLogger.info(`Submitted captcha to 2captcha, got id ${captchaId}`);

Expand All @@ -75,13 +96,14 @@ exports.solveCaptcha = async ({
while (!solved) {
try {
const result = await getCaptchaResult(captchaId);
if (result && result.request) {
if (result && result.request && result.status !== 0) {
captchaAnswer = result.request;
solved = true;
}
} catch (err) {
await page.waitForTimeout(1000);
// no-op
}
await page.waitForTimeout(1000);
}

if (captchaAnswer) {
Expand Down Expand Up @@ -144,3 +166,61 @@ exports.solveCaptcha = async ({
throw err;
}
};

exports.solveGeeTest = async ({ taskLogger, page, captchaIframeSelector }) => {
try {
taskLogger.info('Detected captcha, solving');

if (!apiKey) {
throw new Error('You must set an API_KEY_2CAPTCHA in your .env file.');
}

let context = page;
if (captchaIframeSelector) {
const frameHandle = await page.$(captchaIframeSelector);
context = await frameHandle.contentFrame();
}

const iframeUrl = context.url();
taskLogger.info(`Geetest iframe URL: ${iframeUrl}`);
const pageHtml = await rp(iframeUrl);
const [api_server, gt, challenge] = pageHtml
.split('initGeetest({').pop().split('}, handlerEmbed')[0]
.split(/:|,/)
.filter((e, i) => i % 2 !== 0)
.map((val) => val.trim().replace(/'/g, ''));
taskLogger.info(`Extracted gt ${gt}, challenge ${challenge}, api_server ${api_server}, pageurl=${page.url()}`);

const captcha = await submitGeeTest(gt, challenge, api_server, page.url());
const captchaId = captcha.request;
taskLogger.info(`Submitted captcha to 2captcha, got id ${captchaId}`);

let solved = false;
let captchaAnswer;
while (!solved) {
try {
const result = await getCaptchaResult(captchaId);
if (result && result.request && result.status !== 0) {
captchaAnswer = result.request;
solved = true;
}
} catch (err) {
// no-op
}
await page.waitForTimeout(1000);
}

if (captchaAnswer) {
taskLogger.info(`Got captcha result ${JSON.stringify(captchaAnswer)} from 2captcha, submitting`);

await context.evaluate((captchaAnswerObj) => {
window.geetestResponse = captchaAnswerObj;
window.captchaCallback();
}, captchaAnswer);
}
const submissionSucccess = true;
return submissionSucccess;
} catch (err) {
throw err;
}
};
40 changes: 22 additions & 18 deletions sites/footsites.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { solveCaptcha } = require('../helpers/captcha');
const { solveGeeTest } = require('../helpers/captcha');
const { sendEmail } = require('../helpers/email');
const { getCardDetailsByFriendlyName } = require('../helpers/credit-cards');

Expand Down Expand Up @@ -253,7 +253,7 @@ async function checkout({
async function closeModal({ taskLogger, page }) {
try {
const modalSelector = 'div#bluecoreActionScreen';
await page.waitForSelector(modalSelector, { visible: true });
await page.waitForSelector(modalSelector, { visible: true, timeout: 0 });
const modal = await page.$(modalSelector);
taskLogger.info('Closing modal');
await modal.evaluate(() => {
Expand Down Expand Up @@ -364,53 +364,57 @@ exports.guestCheckout = async ({
const atcButtonSelector = 'button.Button.Button.ProductDetails-form__action';
await page.waitForSelector(atcButtonSelector, { timeout: 0 });
await page.click(atcButtonSelector);
taskLogger.info('Clicked ATC button');
await page.waitForTimeout(2000);

const captchaIframeSelector = 'iframe#dataDomeCaptcha';
const captchaSelector = 'div.g-recaptcha';
const cartSelector = 'span.CartCount-badge';

await Promise.race([
(async () => {
try {
hasCaptcha = await page.waitForSelector(captchaIframeSelector, { timeout: 10 * 1000 });
hasCaptcha = await page.waitForSelector(captchaIframeSelector);
} catch (err) {
// no-op if timeout occurs
}
})(),
(async () => {
try {
await page.waitForSelector(cartSelector, { timeout: 5 * 1000 });
await page.waitForSelector(cartSelector);
} catch (err) {
taskLogger.info('Retrying clicking ATC button');
await page.click(atcButtonSelector);
await page.waitForTimeout(2000);
if (!hasCaptcha) {
taskLogger.info('Retrying clicking ATC button');
await page.click(atcButtonSelector);
await page.waitForTimeout(2000);
}
}

taskLogger.info('Checking if ATC was successful');
const cartCount = await page.evaluate((cartTextSelector) => {
const elem = document.querySelector(cartTextSelector);
return (elem && elem.innerText) || '0';
}, cartSelector);
if (!hasCaptcha) {
taskLogger.info('Checking if ATC was successful');
const cartCount = await page.evaluate((cartTextSelector) => {
const elem = document.querySelector(cartTextSelector);
return (elem && elem.innerText) || '0';
}, cartSelector);

if (parseInt(cartCount) === 1) {
isInCart = true;
if (parseInt(cartCount) === 1) {
isInCart = true;
}
}
})()
]);

if (hasCaptcha) {
if (autoSolveCaptchas) {
const solved = await solveCaptcha({
taskLogger, page, captchaSelector, captchaIframeSelector
const solved = await solveGeeTest({
taskLogger, page, captchaIframeSelector
});
if (solved) hasCaptcha = false;
} else {
taskLogger.info('Detected captcha for manual solving');
const recipient = notificationEmailAddress;
const subject = 'Checkout task unsuccessful';
const text = `The checkout task for ${url} size ${size} has a captcha. Please open the browser and complete it within 5 minutes.`;
await sendEmail(recipient, subject, text);
await sendEmail({ recipient, subject, text });
taskLogger.info(text);

try {
Expand Down
4 changes: 2 additions & 2 deletions sites/shopify.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { solveCaptcha } = require('../helpers/captcha');
const { solveReCAPTCHAV2 } = require('../helpers/captcha');
const { sendEmail } = require('../helpers/email');
const { getCardDetailsByFriendlyName } = require('../helpers/credit-cards');

Expand Down Expand Up @@ -120,7 +120,7 @@ async function checkout({

if (hasCaptcha) {
if (autoSolveCaptchas) {
const solved = await solveCaptcha({
const solved = await solveReCAPTCHAV2({
taskLogger, page, captchaSelector
});
if (solved) hasCaptcha = false;
Expand Down
4 changes: 2 additions & 2 deletions sites/supremenewyork.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { solveCaptcha } = require('../helpers/captcha');
const { solveReCAPTCHAV2 } = require('../helpers/captcha');
const { sendEmail } = require('../helpers/email');
const { getCardDetailsByFriendlyName } = require('../helpers/credit-cards');

Expand Down Expand Up @@ -157,7 +157,7 @@ async function checkout({

if (hasCaptcha) {
if (autoSolveCaptchas) {
const solved = await solveCaptcha({
const solved = await solveReCAPTCHAV2({
taskLogger, page, captchaSelector
});
if (solved) hasCaptcha = false;
Expand Down