Skip to content

Instantly share code, notes, and snippets.

@andris9
Last active December 14, 2015 11:58
Show Gist options
  • Save andris9/5082700 to your computer and use it in GitHub Desktop.
Save andris9/5082700 to your computer and use it in GitHub Desktop.
var crypto = require("crypto"),
urllib = require("url");
/**
* Wrapper for new OAuthGenerator.
*
* Usage:
*
* var OAuthgen = createOAuthGenerator({});
* OAuthgen.getToken(function(err, OAuthtoken){
* request.headers['Authorization'] = OAuthtoken;
* });
*
* @param {Object} options See OAuth2Generator for details
* @return {Object}
*/
createOAuthGenerator = function(options){
return new OAuthGenerator(options);
};
/**
* Create a OAUTH login token generator
*
* @constructor
* @memberOf xoauth
* @param {Object} options
* @param {String} options.consumerKey OAuth consumer key
* @param {String} options.consumerSecret OAuth consumer secret
* @param {String} options.requestorId 2 legged OAuth requestor ID (e-mail address)
* @param {String} [options.nonce] Nonce value to be used for OAuth
* @param {Number} [options.timestamp] Unix timestamp value to be used for OAuth
* @param {String} options.requestUrl OAuth request URL
* @param {String} [options.method="GET"] OAuth request method
*/
function OAuthGenerator(options){
this.options = options || {};
}
/**
* Generates an OAuth authorization token, that can be used for "Authorization: " header
*
* @param {Function} callback Returns an error object and the token string
*/
OAuthGenerator.prototype.getToken = function(callback){
generateOAuthStr(this.options, function(err, token){
if(err){
return callback(err);
}
callback(null, "OAuth "+token);
});
};
/**
* Generate a OAuth login token
*
* @param {Function} [callback] Callback function to run when the access token is genertaed
* @return {String|undefined} If callback is not set, return the token value, otherwise run callback instead
*/
OAuthGenerator.prototype.generate = function(callback){
return generateOAuthStr(this.options, callback);
};
// Helper functions
/**
* Converts an array into urlencoded strings concated with &
*
* @param {Array} arr An array of strings to be concated
* @return {String} Urlencoded and concated string
*/
function escapeAndJoin(arr){
return arr.map(encodeURIComponent).join("&");
}
/**
* Create a HMAC-SHA1 hash
*
* @param {String} str String to be hashed
* @param {String} key HMAC key to be used for hashing
* @param {String} Base64 encoded hash
*/
function hmacSha1(str, key){
var hmac = crypto.createHmac("sha1", key);
hmac.update(str);
return hmac.digest("base64");
}
/**
* Setup OAuth params for signing and sending, generates a nonce and a timestamp
* if needed
*
* @param {Object} options OAuth params
* @return {Object} OAuth params
*/
function initOAuthParams(options){
return {
oauth_consumer_key: options.consumerKey || "anonymous",
oauth_nonce: options.nonce || "" + Date.now() + Math.round(Math.random()*1000000),
oauth_signature_method: "HMAC-SHA1",
oauth_version: "1.0",
oauth_timestamp: options.timestamp || "" + Math.round(Date.now()/1000)
};
}
/**
* Generates the string that will be signed, includes HTTP method, request url
* and oauth params.
*
* @param {String} method HTTP method (eg. "POST")
* @param {String} requestUrl Target url for the request being made
* @param {Object} params Params object created with initOAuthParams()
* @return {String} urlencoded and & concatted string
*/
function generateOAuthBaseStr(method, requestUrl, params){
var reqArr = [method, requestUrl].concat(Object.keys(params).sort().map(function(key){
return key + "=" + encodeURIComponent(params[key]);
}).join("&"));
return escapeAndJoin(reqArr);
}
/**
* Generates the token using provided options
*
* @param {Object} options OAuth options
* @param {Function} callback Callback function to run with the token
*/
function generateOAuthStr(options, callback){
options = options || {};
var params = initOAuthParams(options),
requestUrl = options.requestUrl || "https://mail.google.com/mail/b/" + (options.user || "") + "/imap/",
baseStr, signatureKey, paramsStr;
var urlparts = urllib.parse(requestUrl, true);
Object.keys(urlparts.query).forEach(function(key){
params[key] = urlparts.query[key];
});
if(options.token && !options.requestorId){
params.oauth_token = options.token;
}
if(options.requestorId){
params.xoauth_requestor_id = options.requestorId;
}
if(options.key){
params.key = options.key;
}
baseStr = generateOAuthBaseStr(options.method || "GET", requestUrl.split("?").shift(), params);
signatureKey = escapeAndJoin([options.consumerSecret || "anonymous", options.tokenSecret || ""]);
params.oauth_signature = hmacSha1(baseStr, signatureKey);
Object.keys(urlparts.query).forEach(function(key){
delete params[key];
});
delete params.key;
delete params.xoauth_requestor_id;
paramsStr = Object.keys(params).sort().map(function(key){
return key+"=\""+encodeURIComponent(params[key])+"\"";
}).join(",");
callback(null, paramsStr);
}
var OAuthgen = createOAuthGenerator({
requestorId: "andris@node.ee",
consumerKey: "node.ee",
consumerSecret: "qwerty...",
key: "poiuyt...",
nonce: "12345",
timestamp: "123456",
requestUrl: "https://www.googleapis.com/calendar/v3/users/me/calendarList",
method: "GET"
});
OAuthgen.getToken(function(err, OAuthtoken){
console.log("curl -X" + OAuthgen.options.method + " \"" + OAuthgen.options.requestUrl+(OAuthgen.options.requestUrl.match(/\?/)?"&":"?")+
"xoauth_requestor_id="+encodeURIComponent(OAuthgen.options.requestorId)+
"&"+
"key="+encodeURIComponent(OAuthgen.options.key) +"\" --header 'Authorization: " + OAuthtoken + "'")
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment