feat(lookup): handle Cloudflare DDoS protection (#1434)

Resolves #1297
This commit is contained in:
neatchee
2020-12-17 08:49:43 -08:00
committed by GitHub
parent 2b5588bd46
commit f86a8259f3
2 changed files with 79 additions and 11 deletions
+12
View File
@@ -95,6 +95,18 @@ export const Print = {
return `${buildProductString(link, store)} :: CAPTCHA`;
},
cloudflare(link: Link, store: Store, color?: boolean): string {
if (color) {
return (
'✖ ' +
buildProductString(link, store, true) +
' :: ' +
chalk.yellow('CLOUDFLARE, WAITING')
);
}
return `${buildProductString(link, store)} :: CLOUDFLARE, WAITING`;
},
inStock(link: Link, store: Store, color?: boolean, sms?: boolean): string {
const productString = `${buildProductString(link, store)} :: IN STOCK`;
+67 -11
View File
@@ -275,19 +275,16 @@ async function lookupCard(
waitUntil: givenWaitFor
});
if (!response) {
logger.debug(Print.noResponse(link, store, true));
}
const successStatusCodes = store.successStatusCodes ?? [[0, 399]];
const statusCode = response?.status() ?? 0;
if (!isStatusCodeInRange(statusCode, successStatusCodes)) {
if (statusCode === 429) {
logger.warn(Print.rateLimit(link, store, true));
} else {
logger.warn(Print.badStatusCode(link, store, statusCode, true));
}
const statusCode = await handleResponse(
browser,
store,
page,
link,
response
);
if (!isStatusCodeInRange(statusCode, successStatusCodes)) {
return statusCode;
}
@@ -325,6 +322,65 @@ async function lookupCard(
return statusCode;
}
async function handleResponse(
browser: Browser,
store: Store,
page: Page,
link: Link,
response?: Response | null
) {
if (!response) {
logger.debug(Print.noResponse(link, store, true));
}
const successStatusCodes = store.successStatusCodes ?? [[0, 399]];
let statusCode = response?.status() ?? 0;
if (!isStatusCodeInRange(statusCode, successStatusCodes)) {
if (statusCode === 429) {
logger.warn(Print.rateLimit(link, store, true));
} else if (statusCode === 503) {
if (await checkIsCloudflare(store, page, link)) {
const response: Response | null = await page.waitForNavigation({
waitUntil: 'networkidle0'
});
statusCode = await handleResponse(
browser,
store,
page,
link,
response
);
} else {
logger.warn(Print.badStatusCode(link, store, statusCode, true));
}
} else {
logger.warn(Print.badStatusCode(link, store, statusCode, true));
}
}
return statusCode;
}
async function checkIsCloudflare(store: Store, page: Page, link: Link) {
const baseOptions: Selector = {
requireVisible: true,
selector: 'body',
type: 'textContent'
};
const cloudflareLabel = {
container: 'div[class="attribution"] a[rel="noopener noreferrer"]',
text: ['Cloudflare']
};
if (await pageIncludesLabels(page, cloudflareLabel, baseOptions)) {
logger.warn(Print.cloudflare(link, store, true));
return true;
}
return false;
}
async function lookupCardInStock(store: Store, page: Page, link: Link) {
const baseOptions: Selector = {
requireVisible: false,