send email via google http rest api - node.js

I am trying to send email from NodeJS running on a Linux server to Google Gmail RESR HTTP API. Not using libraries, just sending https. I have figured out the OAuth part, have an access token and get responses from google. But I cannot get past various error messages. I have posted the code below. It is not obvious but EmailSend() is called after I get the access token from google, so yeah it is being called.
var emailStr = new Buffer(
"Content-Type: text/plain; charset=\"UTF-8\"\n" +
"MIME-Version: 1.0\n" +
"Content-Transfer-Encoding: 7bit\n" +
"to: SOMEONE#gmail.com\n" +
"from: SOMEONEELSE#MYDOMAIN.com\n" +
"subject: Subject Text\n\n" +
"The actual message text goes here"
).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
//var emailBase64UrlSafe = Rtrim( emailStr, '=' );
//var emailBase64UrlSafe = JsStrToUrlSafe ( emailStr );
var emailBase64UrlSafe = emailStr;
var http = require('https');
function EmailSend() {
var post_data = emailBase64UrlSafe;
var post_options = {
hostname: 'www.googleapis.com',
port: '443',
path: '/gmail/v1/users/me/messages/send',
method: 'POST',
headers: {
"Authorization": 'Bearer '+googleAccessKey['access_token'],
"Content-Type" : "application/json; charset=UTF-8"
},
};
console.log( post_options );
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
post_req.write(JSON.stringify({ "raw": emailBase64UrlSafe }));
post_req.end();
}; /* end EmailSend() */
Response: {
"error": {
"errors": [
{
"domain": "global",
"reason": "failedPrecondition",
"message": "Bad Request"
}
],
"code": 400,
"message": "Bad Request"
}
Resources used:
https://www.rfc-editor.org/rfc/rfc2822#appendix-A
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
https://nodejs.org/api/https.html#https_https_request_options_callback
Send email using Google API with only access token

Tried it for myself, and it worked!
var http = require('https');
var mail = new Buffer(
"From: example#gmail.com\n" +
"To: example#gmail.com\n" +
"Subject: Subject Text\n\n" +
"Message text"
).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
var post_options = {
hostname: 'www.googleapis.com',
port: '443',
path: '/gmail/v1/users/me/messages/send',
method: 'POST',
headers: {
"Authorization": 'Bearer <ACCESS_TOKEN>',
"Content-Type" : "application/json"
}
};
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
post_req.write(JSON.stringify({ "raw": mail }));
post_req.end();

Related

Error while requesting products in Uber API

I am requesting the /v1/products in node.js for getting list of cars available in a particular area but I am getting this :
{"fields":{"latitude":"Required","longitude":"Required"},"message":"Invalid request","code":"validation_failed"}
Code:
var https = require('https');
var data = {
'latitude': '37',
'longitude': '-122',
};
data = JSON.stringify(data);
var options = {
host: "api.uber.com",
path: "/v1/products",
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": "Token myAppToken",
"Content-Length": Buffer.byteLength(data)
}
};
var req = https.request(options, function(res) {
var responseString = "";
res.on("data", function(data) {
responseString += data;
});
res.on("end", function() {
console.log(responseString);
});
});
req.write(data);
req.end();
Did you post a real latitude and longitude in the format they specified? Update code with actual lat and longitude.
I would start over though using the module that Uber recommends https://github.com/shernshiou/node-uber and follow the example closely.

NodeJS Patreon API account link

I'm trying to connect user accounts on my website to patreon. I keep getting an access_denied error message in response to step 3. I'm following this documentation.
My node server code looks like this:
socket.on("patreon_register",function(code,user){
var reqString = "api.patreon.com/oauth2/token?code="
+code
+"&grant_type=authorization_code&client_id="
+settings.patreon.Client_ID
+"&client_secret="
+settings.patreon.Client_Secret
+"&redirect_uri="
+"http%3A%2F%2Fwww.levisinger.com%2F%3Fpage%3Dpatreon_success",
req = querystring.stringify({
"code": code,
"grant_type": "authorization_code",
"client_id": settings.patreon.Client_ID,
"client_secret": settings.patreon.Client_Secret,
"redirect_uri": "http%3A%2F%2Fwww.levisinger.com%2F%3Fpage%3Dpatreon_success"
}),
post_options = {
host: 'api.patreon.com',
port: '80',
path: '/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(req)
}
};
// Set up the request
console.log(req);
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log(chunk);
if(
chunk.access_token &&
chunk.refresh_token &&
chunk.expires_in &&
chunk.scope &&
chunk.token_type
){
Auth.linkPatreon(user,chunk,function(err,res){
if(err){ socket.emit('patreon_register',false,res); }
else { socket.emit('patreon_register',true,res); }
});
}
});
});
// post the data
post_req.write(req);
post_req.end();
});
The req variable that's actually sent to the server looks like this (changed my codes to generic values of course)
code=MY_RESPONSE_CODE&grant_type=authorization_code&client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&redirect_uri=MY_RESPONSE_URI
Any ideas?
In the end, my server looks like this and is working:
socket.on("patreon_register",function(code,user){
var req = querystring.stringify({
code: code,
grant_type: "authorization_code",
client_id: settings.patreon.Client_ID,
client_secret: settings.patreon.Client_Secret,
redirect_uri: settings.patreon.redirect_uri
}),
post_options = {
host: 'api.patreon.com',
port: '80',
path: '/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(req)
}
};
// Set up the request
console.log(req);
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
chunk = JSON.parse(chunk);
console.log(chunk);
if(!chunk["error"]){
console.log("Linking!");
Auth.linkPatreon(user,chunk,function(err,res){
if(err){ socket.emit('patreon_register',false,res); }
else { socket.emit('patreon_register',true,res); }
console.log("Linked!");
});
}
});
});

Calling NetSuite restlet from Node

I'm trying to call a restlet from nodejs; it's a simple post with some authorization but all I get is some error :
{"error" : {"code" : "SYNTAX_ERROR", "message" : "SyntaxError: Empty JSON string (null$lib#3)."}}
Here's my code
request.post({
url: netSuiteUrl
headers: {
'Content-Type': 'application/json'
'Authorization': 'NLAuth nlauth_account=<account>, nlauth_email=<email>, nlauth_signature=<username>, nlauth_role=3'
}
content: '{"data":"test"}'
}, (error, response, body) ->
console.log(body)
)
The restlet actually receives the call and authorization is working. The same data I'm sending works fine with the following PHP code:
$opts = array(
'http' => array(
'method' => "POST",
'header' => "Authorization: NLAuth nlauth_account=<account>, nlauth_email=<email>, nlauth_signature=<signature>, nlauth_role=3\r\n" .
"Content-Type: application/json\r\n",
'content': '{"data":"test"}'
)
);
$context = stream_context_create($opts);
$file = file_get_contents($url, false, $context);
Any hint?
Which library do you use to send your request? Do you try with the module http of Node JS? It seems that your content isn't sent within the request.
See code below for example:
var postData = querystring.stringify({data:'test'});
var options = {
hostname: '<my host>',
port: 80,
path: '/<mypath>',
method: 'POST',
headers: {
'Content-Type': 'application/json'
'Authorization': 'NLAuth nlauth_account=<account>, nlauth_email=<email>, nlauth_signature=<username>, nlauth_role=3',
}
};
var req = http.request(options, function(res) {
// Handle successful request
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
// Handle errors
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// Send data
req.write(postData);
req.end();
Hope it helps you,
Thierry

nodejs HTTP Digest Authentication not working

I've been digging deep into stack overflow but haven't been able to solve my problem. I'm trying to access an API that uses digest but have had no success, and my co-workers haven't been able to pin down the problem either. I've hit a wall and have come to Stack Overflow to ask my question.
Here is my authentication code:
var https = require("https"),
crypto = require('crypto'),
_ = require('underscore');
var options = {
host: 'api.example.com',
port: 80,
path: '/path/to/uri/',
method: 'GET',
accept: 'application/json',
acceptEncoding: 'gzip, deflate',
connection: 'keep-alive',
rejectUnauthorized: false,
requestCert: true,
agent: false
};
var username = 'username',
password = 'httppassword';
var req = https.get(options, function(res) {
res.setEncoding('utf-8');
console.log(res.url);
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
var data = "";
res.on('data', function (chunk) {
data = data + chunk;
});
res.on('end', function(){
console.log(data);
var challengeParams = parseDigest(res.headers['www-authenticate']);
console.log(challengeParams);
var ha1 = crypto.createHash('md5').update(username + ':' + challengeParams.realm + ':' + password).digest('hex');
var ha2 = crypto.createHash('md5').update('GET:' + options.path).digest('hex');
var response = crypto.createHash('md5').update(ha1 + ':' + challengeParams.nonce + ':1::auth:' + ha2).digest('hex');
var authRequestParams = {
username : username,
realm : challengeParams.realm,
nonce : challengeParams.nonce,
uri : options.path,
qop : challengeParams.qop,
response : response,
nc : 1,
cnonce : ''
};
options.headers = { 'Authorization' : renderDigest(authRequestParams) };
console.log(options);
https.get(options, function(res) {
console.log("STATUS: " + res.statusCode);
console.log("HEADERS: " + JSON.stringify(res.headers));
res.setEncoding('utf-8');
var content = '';
res.on('data', function(chunk) {
content += chunk;
}).on('end', function() {
console.log(content);
});
})
});
});
req.on('error' ,function(err){
console.log("request");
console.log(err);
});
req.write('data\n');
req.write('data\n');
req.end();
And here is the challenge header sent back by the API
{ realm: 'API realm',
domain: 'https:/api.example.com/',
qop: 'auth',
nonce: 'UZ43b0FWC9591pMjy1i6H2okVwgMbDVO6fcgcQ' }
EDIT:
I thought it would be helpful for those looking to answer this question for me to provide what I'm actually sending back to the API, so here it is.
{ host: 'api.example.com',
port: 80,
path: '/path/to/uri/',
method: 'GET',
accept: 'application/json',
acceptEncoding: 'gzip, deflate',
connection: 'keep-alive',
rejectUnauthorized: false,
requestCert: true,
agent: false,
headers: { Authorization: 'Digest username="uname", realm="API realm", nonce="UZ43b0FWC9591pMjy1i6H2okVwgMbDVO6fcgcQ", uri="/path/to/uri", qop="auth", response="09c536e22bca031cdbcb289e4065064a", nc="1", cnonce=""' } }
You can use http-auth module that supports digest authentication
// HTTP module
var http = require('http');
// Authentication module.
var auth = require('http-auth');
var digest = auth.digest({
realm: "Simon Area.",
file: __dirname + "/../data/users.htdigest" // vivi:anna, sona:testpass
});
// Creating new HTTP server.
http.createServer(digest, function(req, res) {
res.end("Welcome to private area - " + req.user + "!");
}).listen(1337);

Google Closure Compiler moved ?? It's giving a 302 error

I'm using nodejs 0.4.7 to make the request, this is my code:
var post_data = JSON.stringify({
'compilation_level' : 'ADVANCED_OPTIMIZATIONS',
'output_format': 'json',
'warning_level' : 'QUIET',
'js_code' : code
});
var post_options = {
host: 'closure-compiler.appspot.com',
port: '80',
path: 'compile',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
post_req.write(post_data);
post_req.end();
And the response I get is
Response: <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
here.
</BODY></HTML>
Why is this happening ? What am I doing wrong ? In the tutorial it says I'm suposed to make the POST request to http://closure-compiler.appspot.com/compile...
You're trying to send json data:
var post_data = JSON.stringify({
'compilation_level' : 'ADVANCED_OPTIMIZATIONS',
'output_format': 'json',
'warning_level' : 'QUIET',
'js_code' : code
});
Google Closure Compiler API wants standard form data, so you want to use querystring instead. Also you need to indicate the output format you want (compiled code I assume), as specified by their documentation:
var post_data = querystring.stringify({
'compilation_level' : 'ADVANCED_OPTIMIZATIONS',
'output_format': 'json',
'output_info': 'compiled_code',
'warning_level' : 'QUIET',
'js_code' : code
});
Path is better declared like so:
path: '/compile',
Here is the full proof of concept code:
var http = require('http');
var querystring = require('querystring');
var code ="// ADD YOUR CODE HERE\n" +
"function hello(name) {\n" +
" alert('Hello, ' + name);\n" +
"}\n" +
"hello('New user');\n";
var post_data = querystring.stringify({
'compilation_level' : 'ADVANCED_OPTIMIZATIONS',
'output_format': 'json',
'output_info': 'compiled_code',
'warning_level' : 'QUIET',
'js_code' : code
});
var post_options = {
host: 'closure-compiler.appspot.com',
port: '80',
path: '/compile',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
post_req.write(post_data);
post_req.end();
Running it with node.js produces the following:
$ node test.js
Response: {"compiledCode":"alert(\"Hello, New user\");"}

Resources