Closed ConorEB closed 5 years ago
Hi @ConorEB,
The error has nothing to do with Cloudscraper. It's a rest API error so if you were to simulate the exact same request with your browser, you'd get the same response. If there was an error with cloudscraper, you'd see a stacktrace unless things REALLY went bad.
The error doesn't have anything to do with Cloudflare either.
If the response was from Cloudflare, there would be a Server: cloudflare
header. The response type is JSON, in this scenario, Cloudflare wouldn't respond like that.
'Content-Type': 'application/json;charset=utf-8',
I don't know if you're misusing the server's rest API or if the server is just buggy but there's nothing we or Cloudflare can do to fix this. You'll need to determine what the problem is on your own.
Cheers
Still having issues, tried a request-promise request and it failed but regular request-js works. Is there a way that I can just get the cookies to pass to request-js? Or use request-js instead of the promise version.
Yes and yes.
But first would you mind editing your issue?
What works with request but doesn't work with Cloudscraper?
Done! Github is not making all of my code formatted correctly so sorry about that :/
I'm just guessing but if it worked with request but not request-promise then the problem you're experiencing most likely bulls down to the response status code not being 2xx. The reason this makes sense is because request-promise doesn't do anything different from request, it uses request, same options, etc.
Maybe try simple: false
so request-promise doesn't complain?
I'll take a more in-depth look a little later. Until then, you can try to use request instead of request-promise:
// The callback argument is required when using `request` as the requester.
const cloudscraper = require('cloudscraper').defaults({ requester: require('request') });
Thanks for the help! FYI: When I try using request like that that this error pops up: throw new TypeError('Expected a callback function, got ' + ^
TypeError: Expected a callback function, got undefined instead.
@ConorEB
I've checked the code. The only difference between request
and request-promise
is the latter throws a StatusCodeError
for non-2xx responses (500 in this case). The only difference between request or request-promise
and Cloudscraper is the response is Cloudflare's IUAM JS challenge response when not using Cloudscraper. When using Cloudscraper, the challenge is solved for you and the rest API error which is a user error is seen.
TypeError: Expected a callback function, got undefined instead.
You have to use a callback as I stated when I provided the example code. My apologies but this isn't a problem with any of the libraries or Cloudflare. You need to figure out how to use the site's API properly.
Good luck
Hey, last thing before I go off on my own. I noticed that it seems to be sending a GET even though I said POST
Request { _events: [Object], _eventsCount: 4, _maxListeners: undefined, requester: [Function], headers: [Object], cloudflareMaxTimeout: 30000, followAllRedirects: true, challengesToSolve: 2, decodeEmails: false, gzip: true, agentOptions: [Object], method: 'GET', url: [Url], realEncoding: 'utf8', encoding: null, callback: [Function], uri: [Url], readable: true, writable: true, explicitMethod: true, _qs: [Querystring], _auth: [Auth], _oauth: [OAuth], _multipart: [Multipart], _redirect: [Redirect], _tunnel: [Tunnel], _rp_resolve: [Function], _rp_reject: [Function], _rp_promise: [Promise], _rp_callbackOrig: [Function], _rp_options: [Object], setHeader: [Function], hasHeader: [Function], getHeader: [Function], removeHeader: [Function], localAddress: undefined, pool: [Object], dests: [], __isRequestRequest: true, _callback: [Function: RP$callback], proxy: null, tunnel: true, setHost: true, originalCookieHeader: undefined, _jar: [RequestJar], port: 443, host: 'raffle.bstn.com', path: '/api/register', httpModule: [Object], agentClass: [Function], agent: [Agent], cloudscraper: true, href: 'https://raffle.bstn.com/api/register', ntick: true, response: [Circular], originalHost: 'raffle.bstn.com', originalHostHeaderName: 'Host', _started: true, req: [ClientRequest], responseContent: [Circular], _destdata: true, _ended: true }, toJSON: [Function: responseToJSON], caseless: Caseless { dict: [Object] }
The first request in your snippet is a POST request. The second request in your snippet defaults to a GET request because the method was not explicit. I can tell that's the second request because the JSON: true
(which is a typo) isn't set on the request object. It should be json: true
btw.
Try correcting some of the the typos:
// cloudscraper.debig = true;
cloudscraper.debug = true; // <-- So you can see the debug information
cloudscraper.get({ url, json: true })
Fixed the typos and json:true. I verified that it has to do with GET/POST because I copied the cookies over to postman and it gave the same error when using GET. I am defining both cloudscraper.post(options) and method:"POST" in both requests so I am confused when you say my second request defaults to GET. Thanks for the help by the way... I see that this is totally my fault and just wanted to let you know that what you are doing is amazing and to keep it up :).
Thanks,
Cloudscraper never specifies or changes the request method unless you're using the reCAPTCHA helper API and you're not using that. The underlying request library might change the request method to get in the case of 3xx redirects but I forget. In any case, I can tell you that none of these libraries are playing tricks on you. If you use the verb methods e.q. request.get
or cloudscraper.post
the method will be overridden to GET
or POST
respectively. So if you use the verb methods, the method
option will be ignored.
It's easy to see what requests are being made: cloudscraper.debug = true
I hope you get everything working!
The data that I showed you above was from cloudscraper.debug = true. Which is why I was confused why I was getting a GET instead of POST even though I defined
` var options = { method: 'POST', url: 'https://raffle.bstn.com/api/register', headers: { 'origin': 'raffle.bstn.com', 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'accept': 'application/json, text/javascript, /; q=0.01', 'referer': 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-', 'authority': 'raffle.bstn.com', 'x-requested-with': 'XMLHttpRequest' }, body: body, json: true };
cloudscraper.post(options).then(console.log, console.error)`
Here is my entire code snippet, you can tell me if I am defining anything incorrectly. I will also include the debug details.
var cloudscraper = require('cloudscraper');
cloudscraper.debug = true
submitRaffle();
async function submitRaffle() {
var body = await hidingBody (it works)
var options = await {
method: 'PUT',
url: 'https://raffle.bstn.com/api/register',
headers: {
'origin': 'raffle.bstn.com',
'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'accept': 'application/json, text/javascript, */*; q=0.01',
'referer': 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-',
'authority': 'raffle.bstn.com',
'x-requested-with': 'XMLHttpRequest'
},
body: body,
json: true
};
await cloudscraper(options).then(console.log, console.error)
}```
@ConorEB
I stand corrected, you are specifying POST for both requests. The reason you're seeing the GET is because of redirects where request
appears to be changing the method to GET. That behavior is to be expected with redirects.
REQUEST redirect /api/register
REQUEST redirect to /api/register
The solution:
const cloudscraper = require('cloudscraper');
const xhrHeaders = Object.assign({}, cloudscraper.defaultParams.headers, {
'X-Requested-With': 'XMLHttpRequest'
})
cloudscraper.debug = true;
const options = {
url: 'https://raffle.bstn.com/api/register',
headers: xhrHeaders,
json: true,
formData: {
foo: 'bar'
}
};
cloudscraper.get({ simple: false, url: 'https://raffle.bstn.com/api/register' }).then(() => {
// Now that we have the cf_clearance cookie
return cloudscraper.post(options).then(console.log);
}).catch(console.error);
Hey, I think we are almost there but still getting some errors... can we chat in https://tlk.io/cloudflare to make it easier?
I really appreciate all of the help by the way, I just need to drive it home :)
The followOriginalHttpMethod
option is supported by requests and thus by Cloudscraper as well.
followRedirect
- follow HTTP 3xx responses as redirects (default: true
). This property can also be implemented as function which gets response
object as a single argument and should return true
if redirects should continue or false
otherwise.followAllRedirects
- follow non-GET HTTP 3xx responses as redirects (default: false
)followOriginalHttpMethod
- by default we redirect to HTTP method GET. you can enable this property to redirect to the original HTTP method (default: false
)maxRedirects
- the maximum number of redirects to follow (default: 10
)removeRefererHeader
- removes the referer header when a redirect happens (default: false
). Note: if true, referer header set in the initial request is preserved during redirect chain.Note: The followAllRedirects
defaults to true
when using Cloudscraper.
Hey thanks that seems to do the trick (sorry for the late reply). The site or cloudflare seemed to have flagged my IP so I am working on getting good proxies to use. Do you have any recommendations as to why cloudflare seems to detect my server every time I try to run the script on it? Not sure if it has to do with specific ciphers or my IP. Anyways let me know, I will be here 🙂
Sent with GitHawk
@pro-src
Sorry for the tag, just hoping you saw this
Hey @ConorEB,
You can rule out the IP issue by tunneling your local traffic through your remote server. I recommend using Chromium (Google Chrome) for a very clear test since it uses BoringSSL. If you experience the same problem in Chromium when tunneling, it's an IP issue.
If it's not an IP issue or you're hoping for an easier way to determine the cause, here's a couple of things that you may try:
node -p process.versions
.If you need to know which ciphers are being sent, you can use https://www.howsmyssl.com/a/check
const cloudscraper = require('cloudscraper')
cloudscraper.get({ uri: 'https://www.howsmyssl.com/a/check', json: true }).then(console.log)
The TLS inspection conducted by Cloudflare goes beyond checking which cipher suite is advertised by the client and excluding ciphers might not help. AFAIK, Cloudflare's TLS checks only flag insecure TLS connections, meaning things like SHA1 being in the signature algorithms will result in a CAPTCHA.
You can reach me on IRC.
Hello! I am trying to bypass a site called BSTN. They recently implemented Cloudflare and I have decided to use your library to bypass it. You can tell if you visit the link: https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian- that they have Cloudflare enabled. I tried GET requests using cloud scraper to their raffle page and that worked fine however the POST endpoint: https://raffle.bstn.com/api/register returns the error:
My code for the post request is:
My version of Cloudscraper is 4.1.4 This error occurs on every request using a normal cloudflare request. The way I got it to work locally is:
Code snippet
```js var cloudscraper = require('cloudscraper'); var request = require("request"); var rp = require('request-promise'); cloudScraper.debig = true cloudScraper(); function cloudScraper() { var options = { method: 'POST', url: 'https://raffle.bstn.com/api/register', headers: { 'cache-control': 'no-cache', Connection: 'keep-alive', 'Accept-Language': 'en-US,en;q=0.5', Accept: 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0' }, body: '{"additional":{"instagram":"hdbfff"},"title":"male","email":"test@gmail.com","firstName":"Fake","lastName":"Name","street":"Yesfv Avenue","streetno":"3132","address2":"","zip":"60141","city":"New York","country":"US","acceptedPrivacy":true,"newsletter":false,"state":"New York","recaptchaToken":"03AOLTBLQt8oFAs7FHLdt12D2hrroUdIEexUALXv9msV_1nMwVOZ3IiIrl_-Oo4lDXxwO6hiV6zwo_3nKHlS8w16u9-R4cnn-ZcNvuLTkH04C6Fl5T6KCG1JPM0ysebufyuxsH5S9vUJNWfgP7ej1hE1nybfd9_VjqWeq8o_f-QolO45eqst3DCrZ4FYDinsNwzB3w84UaqihYfcO3HLR3fVBMcJM4C5HIBS2n1xyZKccbxeTcAr__BWrrS9VOuUidKb8RKa6fz8NcGXz0EC4a2Oxav5g1aj9DrNtOsyDo3yuma6a8h5XGVbpD8MfeStk3QqmY_LT8znnE","raffle":{"raffleId":"air-jordan-1-retro-high-og-obsidian-","parentIndex":0,"option":"40"},"issuerId":"raffle.bstn.com"}', JSON: true }; cloudscraper.post(options).then(onResponse).catch(onError); async function onResponse(response) { await delay(4000) var request = await response.request.toJSON() var headers = await JSON.stringify(response.headers, null, 2); var cookies = JSON.stringify(request["headers"].cookie).split(";") await console.log("Clearance: " + cookies[1].replace(`"`, "")) await console.log("UID: " + cookies[0].replace(`"`, "")) submitRaffle(cookies[0].replace(`"`, ""), cookies[1].replace(`"`, "")) } function onError(error) { console.error(error.stack); if (error.cause) { console.log('Cause: ', error.cause); } if (error.response) { onResponse(error.response); } } } function submitRaffle(uid, clearance) { var cookie = `_ga=GA1.2.860778441.1565723692; cookieconsent_status=dismiss; ${uid}; __cf_bm=3892a44b19e11906234dd85e0e6a812495735938-1567037712-1800-AUyxq0xIEoeer5COx5/3mL8k659l+fBOGmFA85z+3YgE+0+zfKNkujSUPrh3cMhOejH7411YkYbcKLRTlSmKByU=; _gcl_au=1.1.1318149485.1567037735; _gid=GA1.2.728282739.1567037736; ${clearance}` var body = '{"additional":{"instagram":"conor.de"},"title":"male","email":"conorebeling@gmail.com","firstName":"Conor","lastName":"Ebeling","street":"Wesley Avenue","streetno":"1325","address2":"","zip":"60201","city":"Evanston","country":"US","acceptedPrivacy":true,"newsletter":false,"state":"Illinois","recaptchaToken":"03AOLTBLQUZj3k8q7ZN-lyTVzVcqI8kcLaVqHDe_7Bl3GbeV5VW4ZjrfqzSVs-YZnhYHZ2h3RYkVLRhUTtmyhBLBYVRNZY7EP_YuNL1WAP4iZbSD9fJtZDlEyfQyTM57g96Zn5wVaNPXu0roVjRfgW-kG7pARZWvkBAnmFXqtp4et6XWIvtcM3wdP2c4eU9qpCv5XvZnFeveuLKp4ZgxZHKMEVm-wHD4TMYbxkBGSoC2t31ukXfLGUJo8A_045wRMdS-NPBroyDoDvBVNbAc7k5lbJcFVfSz9LQ25xtd9Udr5bXG02WcnE8Z-JW3H6_ILh9J0EyVFneYVc","raffle":{"raffleId":"air-jordan-1-retro-high-og-obsidian-","parentIndex":0,"option":"40"},"issuerId":"raffle.bstn.com"}' console.log("Final Cookie: " + cookie) var options = { method: 'POST', url: 'https://raffle.bstn.com/api/register', headers: { 'cache-control': 'no-cache', 'Content-Length': '767', Host: 'raffle.bstn.com', 'Cache-Control': 'no-cache', Cookie: cookie, Referer: 'https://raffle.bstn.com/air-jordan-1-retro-high-og-obsidian-', Connection: 'keep-alive', 'Content-Type': 'application/json;charset=utf-8', 'Accept-Language': 'en-US,en;q=0.5', Accept: 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Firefox/68.0' }, body: body }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log("Status: " + response.statusCode); console.log("Body: " + body); }); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } ```I have tried using valid Recaptcha tokens and it makes no difference. Please let me know if you have any insight into this error, thanks!