diff --git a/index.js b/index.js index 50100e4..36c7b5b 100644 --- a/index.js +++ b/index.js @@ -290,9 +290,11 @@ function onChallenge (options, response, body) { let timeout = parseInt(options.cloudflareTimeout); let match; - match = body.match(/name="s" value="(.+?)"/); + match = body.match(/name="(.+?)" value="(.+?)"/); + if (match) { - payload.s = match[1]; + const hiddenInputName = match[1]; + payload[hiddenInputName] = match[2]; } match = body.match(/name="jschl_vc" value="(\w+)"/); @@ -354,14 +356,25 @@ function onChallenge (options, response, body) { options.headers = Object.assign({}, options.headers); // Use the original uri as the referer and to construct the answer uri. options.headers.Referer = uri.href; - options.uri = uri.protocol + '//' + uri.host + '/cdn-cgi/l/chk_jschl'; + // Check is form to be submitted via GET or POST + match = body.match(/id="challenge-form" action="(.+?)" method="(.+?)"/); + if (match && match[2] && match[2] === 'POST') { + options.uri = uri.protocol + '//' + uri.host + match[1]; + // Pass the payload using body form + options.form = payload; + options.method = 'POST'; + } else { + // Whatever is there, fallback to GET + options.uri = uri.protocol + '//' + uri.host + '/cdn-cgi/l/chk_jschl'; + // Pass the payload using query string + options.qs = payload; + } + // Decrement the number of challenges to solve. + options.challengesToSolve -= 1; // baseUrl can't be used in conjunction with an absolute uri if (options.baseUrl !== undefined) { options.baseUrl = undefined; } - // Set the query string and decrement the number of challenges to solve. - options.qs = payload; - options.challengesToSolve -= 1; // Make request with answer after delay. timeout -= Date.now() - response.responseStartTime; diff --git a/test/fixtures/js_challenge_28_11_2019.html b/test/fixtures/js_challenge_28_11_2019.html new file mode 100644 index 0000000..917480f --- /dev/null +++ b/test/fixtures/js_challenge_28_11_2019.html @@ -0,0 +1,103 @@ + + + + + + + + + Just a moment... + + + + + + + + + + + + +
+
+ + + +
+ + + + +
+ + + +
+ + +
+ DDoS protection by Cloudflare +
+ Ray ID: 53cb1af29bc6c2d6 +
+
+ + \ No newline at end of file diff --git a/test/test-index.js b/test/test-index.js index 0dc8999..6556e2e 100644 --- a/test/test-index.js +++ b/test/test-index.js @@ -329,6 +329,42 @@ describe('Cloudscraper', function () { }); }); + it('should resolve challenge (version as on 28.11.2019) and then return page', function (done) { + helper.router + .get('/test', function (req, res) { + res.sendChallenge('js_challenge_28_11_2019.html'); + }) + .post('/', function (req, res) { + res.send(requestedPage); + }); + + const expectedParams = helper.extendParams({ + uri: helper.resolve('/?__cf_chl_jschl_tk__=xxxxx'), + method: 'POST', + form: { + r: '9dbc5c7ec65cb42893f2fd063ca80a2185ad6b6b-1574931141', + jschl_vc: '44a73ed828ddcd806a342f7c289cc438', + jschl_answer: String(20.2553376255 + helper.uri.hostname.length), + pass: '1574931145.541-UbeyT63kjo' + }, + headers: { + Referer: uri + }, + challengesToSolve: 2 + }); + + const promise = cloudscraper.get(uri, function (error, response, body) { + expect(error).to.be.null; + + expect(Request).to.be.calledTwice; + expect(Request.firstCall).to.be.calledWithExactly(helper.defaultParams); + expect(Request.secondCall).to.be.calledWithExactly(expectedParams); + + expect(body).to.be.equal(requestedPage); + expect(promise).to.eventually.equal(requestedPage).and.notify(done); + }); + }); + it('should resolve 2 consequent challenges', function (done) { // Cloudflare is enabled for site. It returns a page with JS challenge let additionalChallenge = true;