Google nocaptcha post from server to siteverify says details are missing - node.js

[ { hostname: 'www.google.com',
path: '/recaptcha/api/siteverify',
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': 556 } },
'{"secret":"XXXUseThisForCommunicationBetweenYourSiteAndGoogleXXX","response":"03AHJ_VuusXdr5IdGpNzQPRjedGs-Le066Fx9r-Lk1gIfLqlzwxapPx70_LukmcOsw3x-m2DSfpvQVylx060H9IjFP82fy7505_t_rjSivauiwBUyQPrBMp5kTRviq_DD1L2mVMTTrBieUMlQM69AIuG3KwmdOQMyMJS2iJdRuRNnvAmDlPSejkASR4X-7c4IIP3NoMb52Qsl9QPeU6kGaPtxqmf1IpNwbSC3bzLXQD-QV1aI4GgaeqSPfOO8EPfISJMQ5kbCd9wqAwHqDAXMtNSvz10Ty30R71HqmsSk7YHddFQhei1L6y9j7nxnY5QtAxHehhpYwJVNjI96hxeIaG58_CQHGbAufy4aPGAlf-zJ6be_Xtdzd4AnHxiX9OuCKQI8eQlh6DZLGaymxXDmPNu4TijGyyu0VeTPTTKf12zVUg86_0ZmszWZDtALjnNnxBH7bZqrgWXhy","remoteip":"00.00.000.000"}' ]
If I post that and google returns this:
{ success: false, 'error-codes': [ 'missing-input-response', 'missing-input-secret'] }
I don't see what is happening wrong
https://www.google.com/recaptcha/admin#site/XXXXXX?setup says:
When your users submit the form where you integrated reCAPTCHA, you'll get as part of the payload a string with the name "g-recaptcha-response". In order to check whether Google has verified that user, send a POST request with these parameters:
URL: https://www.google.com/recaptcha/api/siteverify
secret(required) - XXXXXX,
response(required) - The value of 'g-recaptcha-response',
remoteip - The end user's ip address.
I have clearly sent all these things! What could be happening here? The error does not say they are wrong, it says they are 'missing'
And the above Quoted text from google clearly says POST not GET Google reCAPTCHA: how to get user response and validate in the server side
But if I try a GET request then the response is [ null, 400, undefined ]
UPDATE
As #mscdex pointed out application/x-www-form-urlencoded is required but the responce still said that it was missing the secret so I url encoded this instead as I figured something bad may be happening to the item at the start of the object.
{'_':'_','secret':'XXXXXX','response':'whateverXXYsgTSG','remoteip':'00.00.000.000'}
And finally it worked:
[ { hostname: 'www.google.com',
path: '/recaptcha/api/siteverify?',
method: 'POST',
headers:
{ 'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': 548 } },
'"_=_&secret=XXXXXX&response=03AHJ_VuurQFgsftybLlvrdGOwXfNneWp4v7FPJJbOD9CGpiHAkFBaiNy7YWXcHrAkU6SPU5UZpgKCptU3gRX5OPqXEh2qqP3nXJpiBWoxFW_Iv05P2UA23rzzZk0ecScmMSL1PP1uyBCdJ08HpAWEuz2PzL6m6u71k09xQbVbPZ5KT6qnb-mdPNyEkdBxtc9a5oYpnOoHg7ax6q4Ms4Lis4qrNBLCavKmYZ6vAmYitSEI0a0GERnlI3wLSvayhc-Yygv1koKIjg2q8GHXV1UhKLzBa8t8x2ibRBNwXUMBFs3Qj_lfwgiTNtIaU3kEAFPULJulZDOsAcovKpjk5xkyMM2C5YDGYMioeyOMl9ZmyyvkwfrrRe8e9o_tD6SaTTSAcrcxsfYGm-w0_CDbsa2IWSkjiMN-2B9SClOZJGXXVXVIuIYClIK3XuUvTsObCzxJAq2IKwwMTtYX&remoteip=00.00.000.000"' ]
[ { success: true }, 200, undefined ]
But I would like to do this properly not hacky So if anyone can answer how to do it properly that would be swell!
var JSON={
https:require('https')
, toquery:require('../node_modules/querystring').stringify
, stringify:require('../node_modules/json-stringify-safe')
, parse:require('../node_modules/try-json-parse')
, get:function(url,callback){process.env.NODE_TLS_REJECT_UNAUTHORIZED="0";var req=JSON.https.request(url,function(res){var buffer='';res.setEncoding('utf8');res.on('data',function(chunk){buffer+=chunk;});res.on('end',function(){try{var data=JSON.parse(buffer);callback(data,res.statusCode);}catch(e){console.log(e);}});});req.end();}
, post:function(url,path,data,type,callback){if(!callback){callback=type;type=undefined;}data=JSON.stringify(data);var options={hostname:url,path:path,method:'POST',headers:{'Content-Type':type||'application/json','Content-Length':data.length}};console.dir([options,data]);var req=JSON.https.request(options,function(res){var buffer='';res.setEncoding('utf8');res.on('data',function(chunk){buffer+=chunk;});res.on('end',function(){try{var data=JSON.parse(buffer);callback(data,res.statusCode);}catch(e){console.log(e);}});});req.write(data);req.end();}
};
JSON.post(
'www.google.com'
, '/recaptcha/api/siteverify?'
, JSON.toquery({'_':'_','secret':'XXXX','response':response,'remoteip':remoteip})
, 'application/x-www-form-urlencoded'
, function(data,result,statusCode){
console.dir([data,result,statusCode]);
if(result.success){}
else{}
});

Here is how I do it in one of my project using superagent. This is my recaptcha-helper.js
var request = require("superagent");
var config = {
recaptcha: {
secret: "XXXXX",
url: "https://www.google.com/recaptcha/api/siteverify",
},
};
var ERROR_CODES = {
"missing-input-secret": "Unexpected Server Error (1)",
"invalid-input-secret": "Unexpected Server Error (2)",
"missing-input-response": "Missing reCAPTCHA value",
"invalid-input-response": "Invalid reCATPCHA value",
};
exports.getErrorCode = function (errorCode) {
if (Array.isArray(errorCode)) {
var errors = errorCode.map(function (code) {
return exports.getErrorCode(code);
});
return errors.join("\n");
}
return ERROR_CODES[errorCode] ||
(errorCode ? ("Unexpected reCAPTCHA error: " + errorCode) : "Unexpected reCAPTCHA error");
};
exports.parseResponse = function (err, res) {
if (err) {
return { success: false, error: err };
} else if (!res.body.success) {
var error = new Error(exports.getErrorCode(res.body["error-codes"]));
return { success: false, error: error };
} else {
return { success: true };
}
};
exports.verify = function (response, ip) {
if (process.env.NODE_ENV === "test") {
return response ? Promise.resolve() :
Promise.reject(new Error("Test reCAPTCHA Error"));
}
return new Promise (function (resolve, reject) {
request.post(config.recaptcha.url)
.type("form")
.accept("json")
.send({
secret: config.recaptcha.secret,
response: response,
remoteip: ip,
})
.end(function (err, res) {
var parsedRes = exports.parseResponse(err, res);
return parsedRes.success ? resolve() : reject(parsedRes.error);
});
});
};
And you can use it doing
var captchaHelper = require('./recaptcha-helper');
captchaHelper.verify(req.body.captcha, req.ip)
.then(function () {
// on success
}).catch(function (err {
// on error
});

I solved this by passing secret and response as a query parameter:
Example :
axios.post("https://www.google.com/recaptcha/api/siteverify?secret="
+ 'XXXXXX' + "&response=" + response + "&remoteip=" + req.connection.remoteAddress);

Related

POST request with JSON payload with NodeJS

I'm trying to hit the Intercom API to retrieve a list of conversations and I can't figure out what's wrong. Here is the code:
const request=require('request')
const search_intercom=(admin_id, callback) => {
const options = {
url: 'https://api.intercom.io/conversations/search',
method: 'POST',
headers: {
Authorization: 'Bearer <token>'
},
json: {
query: JSON.stringify({
"field": "teammate_ids",
"operator": "=",
"value": admin_id
})
}
};
request(options, (error, {body} = {}) => {
if (error) {
callback('unable to connect to intercom API', undefined)
} else if (body.length === 0) {
callback('something went wrong', undefined)
} else {
callback(undefined, {
conversation_id: body.conversations[0].id,
client_name: body.conversations[0].source.author.name
})
console.log(body)
}
})
}
module.exports = search_intercom
I was able to wire it up correctly with the web server, so when I debug, options.json.query.admin_id does contain a valid id.
It breaks and says
conversation_id: body.conversations[0].id,
TypeError: Cannot read property '0' of undefined
Here is the content of the body response:
{
type: 'error.list',
request_id: '<some request_id>',
errors: [ { code: 'server_error', message: 'Server Error' } ]
}
Where should I look? I've tried a few different variations of options for sending the payload and I am guessing this is the issue, but I can't find the winning formula...
It looks like I got the body all wrong.
options should look like this instead:
const options = {
url: 'https://api.intercom.io/conversations/search',
method: 'POST',
headers: {
Authorization: 'Bearer <token>'
},
json: true,
body: {
query: {
"field": "teammate_ids",
"operator": "=",
"value": JSON.stringify(admin_id)
}
}
};

Unable to get request timeout response using node.js

I am trying to set the timeout values inside request module of node.js but as per the given time its not returning the response. I am explaining my code below.
postRequestOptions.url = `${nsoObj.protocol}://${nsoObj.ipAddress}:${nsoObj.httpPortNbr}/jsonrpc`;
postRequestOptions.headers = {
'Content-Type': 'application/json'
};
postRequestOptions.body = {
jsonrpc: '2.0',
id: 1,
method: 'login',
timeout: 5000,
params: {
user: nsoObj.userName,
passwd: nsoObj.password
}
};
request(postRequestOptions, (error, response, loginResponse) => {
console.log('\n error: ', error);
console.log('\n loginResponse: ', loginResponse);
if (error || !loginResponse.id) {
responseObj = {
status : 'error',
msg : `Error occurred while performing Login into "${nsoObj.nsoNickName}" Instance. ${error}`,
body : null
};
reject(responseObj);
} else {
loginResponse.sessionId = response.headers['set-cookie'][0];
responseObj = {
status : 'success',
msg : `Successfully performing Login into "${nsoObj.nsoNickName}" Instance`,
body : loginResponse
};
resolve(responseObj);
}
});
});
Here I am using request module of node.js and set timeout of 5ms. But When I am running this its taking 2min to sent back the timeout error response.
Here I need if this request could not sent back the response within 5 milisecond then it should return the timeout error.
delete timeout from body and using postRequestOptions.timeout = 5000; so do like this:
postRequestOptions.url = `${nsoObj.protocol}://${nsoObj.ipAddress}:${nsoObj.httpPortNbr}/jsonrpc`;
postRequestOptions.headers = {
'Content-Type': 'application/json'
};
postRequestOptions.body = {
jsonrpc: '2.0',
id: 1,
method: 'login',
params: {
user: nsoObj.userName,
passwd: nsoObj.password
}
};
postRequestOptions.timeout = 5000;//should be outside the body
request(postRequestOptions, (error, response, loginResponse) => {
console.log('\n error: ', error);
console.log('\n loginResponse: ', loginResponse);
if (error || !loginResponse.id) {
responseObj = {
status : 'error',
msg : `Error occurred while performing Login into "${nsoObj.nsoNickName}" Instance. ${error}`,
body : null
};
reject(responseObj);
} else {
loginResponse.sessionId = response.headers['set-cookie'][0];
responseObj = {
status : 'success',
msg : `Successfully performing Login into "${nsoObj.nsoNickName}" Instance`,
body : loginResponse
};
resolve(responseObj);
}
});
});

Firebase cloud messaging: Request contains an invalid argument

I'm following this tutorial, I got to the point to send an HTTP request to the fcm endpoint, but I'm getting the following error:
{
error:
{
code: 400,
message: 'Request contains an invalid argument.',
status: 'INVALID_ARGUMENT'
}
}
Instead of sending the request using curl I'm using a cloud function using node.js | express with the following code:
exports.messages = function (req, res) {
const api = 'https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send';
const headers = {
'Accept': 'application/json',
'Content-type': 'application/json',
};
return getAccessToken().then((accessToken) => {
headers.Authorization = `Bearer ${accessToken}` // <-- accessToken is OK
const { title, body, token } = req.body;
return fetch(api, {
headers,
method: 'POST',
body: JSON.stringify(
{
'message': {
'token': token, // <-- this is the client fcm token
'notification': {
'title': title,
'body': body
}
}
}
)
}).then(res => res.json()).then(data => {
console.log(data);
res.sendStatus(200);
}).catch((error) => {
console.error(error);
});
});
}
Where the token is an OAuth 2 token for my service account
function getAccessToken() {
return new Promise(function (resolve, reject) {
var key = require('../keys/service-account.json');
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
[
'https://www.googleapis.com/auth/firebase',
'https://www.googleapis.com/auth/firebase.database',
'https://www.googleapis.com/auth/firebase.messaging',
],
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
what am I missing here? any advice will be appreciated
I just realized I copied the uri for the fcm endpoint from the tutorial. I changed it to:
const api = 'https://fcm.googleapis.com/v1/projects/{project-Id}/messages:send';
and it worked!

ntlm tfs res api response is always "401 - Unauthorized: Access is denied due to invalid credentials"

I am try to get all the project names from a tfs api url. For that I am using the node.js ntlm package. Following is my code.
function getTFSProjectNames(credentials) {
return new Promise(function (resolve, reject) {
var ntlm = require('ntlm');
var ntlmrequest = require('request').defaults({
agentClass: require('agentkeepalive').HttpsAgent
});
var projectNames = [];
var url = "https://{instance}/tfs/DefaultCollection/_apis/projects?api-version=1.0"
, domain = 'domain'
, hostname = 'hostname';
var testOption = {
url:url,
headers: {
'Authorization': ntlm.challengeHeader(hostname, domain)
},
proxy: 'server proxy',
timeout: 10000,
followRedirect: true,
maxRedirects: 10
}
ntlmrequest(testOption , function (err, ntlmres) {
if (err && ntlmres == undefined)
resolve({ 'Projects': projectNames });
else {
var options = {
method: 'get',
json: true,
url: url,
headers: {
'Authorization': ntlm.responseHeader(ntlmres, url, domain, credentials.username, credentials.password),
'Content-Type': 'application/json'
},
proxy: 'server proxy',
timeout: 10000,
followRedirect: true,
maxRedirects: 10
}
ntlmrequest(options, function (err, ntlmres, body) {
if (err)
return next(err)
if (ntlmres != undefined && ntlmres.body != undefined && ntlmres.body.value != undefined) {
var projectNames = ntlmres.body.value.map(function (item) {
return item.name;
})
}
resolve({ 'Projects': projectNames });
});
}
});
});
}
Even if the correct credential, It's response is always as 401 - Unauthorized: Access is denied due to invalid credentials. It's a server error.I am not able to understand, why it's happening every time. Please help me to solve this issue.

Google Recaptcha not working with axios

I am encountering an error while trying to verify my recaptcha witch axios
try{
let result = await axios.post(
'https://www.google.com/recaptcha/api/siteverify',
{
secret: '6LcarRkTAAAAAPDNrruugUg1fJqOJnH-uvVa5KIL',
response: response
},
{
headers: {
"Content-Type": "application/json"
}
});
let data = result.data || {};
if(!data.success){
throw({
success: false,
error: 'response not valid'
})
}
}catch(err){
console.log(err);
throw err.response ? err.response.data : {success: false, error: 'verifyCatpcha Error'}
}
I am always getting the error
{ success: false,
'error-codes': [ 'missing-input-response', 'missing-input-secret' ] }
I tried it with postman and it works fine. Something wrong with my header?
You need to add one more key to your request: secret. The error message is caused by missing response and secret parameters when sending POST request.
UPDATE: The POST params in the doc are not JSON, they must be passed as query string. That's why the error says it's missing both missing-input-response and missing-input-secret
axios.post(
`https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${response}`,
{},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
},
},
);
Reference: Doc
I managed to solve it be adding params.
I will accept Ryan Wus answer cause it is basically the same with different writing.
try{
let result = await axios({
method: 'post',
url: 'https://www.google.com/recaptcha/api/siteverify',
params: {
secret: '6LcarRkTAAAAAPDNrruugUg1fJqOJnH-uvVa5KIL',
response: response
}
});
let data = result.data || {};
if(!data.success){
throw({
success: false,
error: 'response not valid'
})
}
}catch(err){
console.log(err);
throw err.response ? err.response.data : {success: false, error: 'captcha_error'}
}
https://stackoverflow.com/a/48083886/5426839
The POST params in the doc are not JSON, they must be passed as query string. That's why the error says it's missing both missing-input-response and missing-input-secret
Not opposite to the highest answer, just shorter syntax:
axios.post('https://www.google.com/recaptcha/api/siteverify', undefined, {
params: {
secret: RECAPTCHA_V3_SECRET,
response: recaptchaToken
}
})

Resources