2011-06-13 11:23:02 +08:00
|
|
|
// too bound to the request object, but ok for now
|
2015-05-13 00:00:30 +08:00
|
|
|
var _ = require('underscore');
|
|
|
|
var OAuthUtil = require('oauth-client');
|
|
|
|
var step = require('step');
|
|
|
|
var assert = require('assert');
|
2011-06-13 11:23:02 +08:00
|
|
|
|
2015-05-13 00:00:30 +08:00
|
|
|
var oAuth = (function(){
|
2011-08-18 00:27:45 +08:00
|
|
|
var me = {
|
|
|
|
oauth_database: 3,
|
2012-06-30 07:54:21 +08:00
|
|
|
oauth_user_key: "rails:oauth_access_tokens:<%= oauth_access_key %>",
|
|
|
|
is_oauth_request: true
|
2011-08-22 20:33:12 +08:00
|
|
|
};
|
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
// oauth token cases:
|
|
|
|
// * in GET request
|
2011-08-22 20:33:12 +08:00
|
|
|
// * in header
|
2011-08-18 00:27:45 +08:00
|
|
|
me.parseTokens = function(req){
|
2015-05-13 00:00:30 +08:00
|
|
|
var query_oauth = _.clone(req.method === "POST" ? req.body: req.query);
|
2011-08-18 00:27:45 +08:00
|
|
|
var header_oauth = {};
|
2011-08-22 20:33:12 +08:00
|
|
|
var oauth_variables = ['oauth_body_hash',
|
|
|
|
'oauth_consumer_key',
|
|
|
|
'oauth_token',
|
|
|
|
'oauth_signature_method',
|
2011-08-18 00:27:45 +08:00
|
|
|
'oauth_signature',
|
|
|
|
'oauth_timestamp',
|
|
|
|
'oauth_nonce',
|
|
|
|
'oauth_version'];
|
|
|
|
|
2011-08-22 20:33:12 +08:00
|
|
|
// pull only oauth tokens out of query
|
|
|
|
var non_oauth = _.difference(_.keys(query_oauth), oauth_variables);
|
|
|
|
_.each(non_oauth, function(key){ delete query_oauth[key]; });
|
2011-08-18 00:27:45 +08:00
|
|
|
|
|
|
|
// pull oauth tokens out of header
|
|
|
|
var header_string = req.headers.authorization;
|
2011-08-22 20:33:12 +08:00
|
|
|
if (!_.isUndefined(header_string)) {
|
2011-08-18 00:27:45 +08:00
|
|
|
_.each(oauth_variables, function(oauth_key){
|
2015-05-13 00:00:30 +08:00
|
|
|
var matched_string = header_string.match(new RegExp(oauth_key + '=\"([^\"]+)\"'));
|
|
|
|
if (!_.isNull(matched_string)) {
|
2011-08-18 00:27:45 +08:00
|
|
|
header_oauth[oauth_key] = decodeURIComponent(matched_string[1]);
|
2015-05-13 00:00:30 +08:00
|
|
|
}
|
2011-08-18 00:27:45 +08:00
|
|
|
});
|
2011-08-22 20:33:12 +08:00
|
|
|
}
|
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
//merge header and query oauth tokens. preference given to header oauth
|
2011-08-22 20:33:12 +08:00
|
|
|
return _.defaults(header_oauth, query_oauth);
|
|
|
|
};
|
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
// remove oauthy tokens from an object
|
|
|
|
me.splitParams = function(obj) {
|
2011-12-26 19:51:15 +08:00
|
|
|
var removed = null;
|
|
|
|
for (var prop in obj) {
|
|
|
|
if (/^oauth_\w+$/.test(prop)) {
|
|
|
|
if(!removed) {
|
|
|
|
removed = {};
|
|
|
|
}
|
|
|
|
removed[prop] = obj[prop];
|
|
|
|
delete obj[prop];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return removed;
|
2011-08-22 20:33:12 +08:00
|
|
|
};
|
2011-06-13 11:23:02 +08:00
|
|
|
|
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
// do new fancy get User ID
|
2014-08-06 18:51:55 +08:00
|
|
|
me.verifyRequest = function(req, metadataBackend, callback) {
|
2011-08-18 00:27:45 +08:00
|
|
|
var that = this;
|
2011-12-26 19:51:15 +08:00
|
|
|
//TODO: review this
|
2014-08-06 18:51:55 +08:00
|
|
|
var httpProto = req.protocol;
|
2011-08-18 00:27:45 +08:00
|
|
|
var passed_tokens;
|
2011-08-22 20:33:12 +08:00
|
|
|
var ohash;
|
2011-08-18 00:27:45 +08:00
|
|
|
var signature;
|
2011-08-22 20:33:12 +08:00
|
|
|
|
2015-05-13 00:00:30 +08:00
|
|
|
step(
|
2011-08-18 00:27:45 +08:00
|
|
|
function getTokensFromURL(){
|
|
|
|
return oAuth.parseTokens(req);
|
|
|
|
},
|
|
|
|
function getOAuthHash(err, data){
|
2015-05-13 00:00:30 +08:00
|
|
|
assert.ifError(err);
|
2012-06-30 07:54:21 +08:00
|
|
|
|
|
|
|
// this is oauth request only if oauth headers are present
|
|
|
|
this.is_oauth_request = !_.isEmpty(data);
|
|
|
|
|
|
|
|
if (this.is_oauth_request) {
|
|
|
|
passed_tokens = data;
|
2014-08-06 18:51:55 +08:00
|
|
|
that.getOAuthHash(metadataBackend, passed_tokens.oauth_token, this);
|
2012-06-30 07:54:21 +08:00
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
2011-08-18 00:27:45 +08:00
|
|
|
},
|
|
|
|
function regenerateSignature(err, data){
|
2015-05-13 00:00:30 +08:00
|
|
|
assert.ifError(err);
|
|
|
|
if (!this.is_oauth_request) {
|
|
|
|
return null;
|
|
|
|
}
|
2012-06-30 07:54:21 +08:00
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
ohash = data;
|
|
|
|
var consumer = OAuthUtil.createConsumer(ohash.consumer_key, ohash.consumer_secret);
|
|
|
|
var access_token = OAuthUtil.createToken(ohash.access_token_token, ohash.access_token_secret);
|
|
|
|
var signer = OAuthUtil.createHmac(consumer, access_token);
|
2011-08-22 20:33:12 +08:00
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
var method = req.method;
|
|
|
|
var host = req.headers.host;
|
2013-05-15 00:01:37 +08:00
|
|
|
|
2015-05-13 00:00:30 +08:00
|
|
|
if(!httpProto || (httpProto !== 'http' && httpProto !== 'https')) {
|
2013-05-20 15:05:27 +08:00
|
|
|
var msg = "Unknown HTTP protocol " + httpProto + ".";
|
2013-05-15 00:01:37 +08:00
|
|
|
err = new Error(msg);
|
|
|
|
err.http_status = 500;
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-29 23:35:16 +08:00
|
|
|
var path = httpProto + '://' + host + req.path;
|
2011-08-18 00:27:45 +08:00
|
|
|
that.splitParams(req.query);
|
2011-08-22 20:33:12 +08:00
|
|
|
|
2011-08-18 00:27:45 +08:00
|
|
|
// remove signature from passed_tokens
|
|
|
|
signature = passed_tokens.oauth_signature;
|
2015-05-13 00:00:30 +08:00
|
|
|
delete passed_tokens.oauth_signature;
|
2011-08-22 20:33:12 +08:00
|
|
|
|
2011-12-26 19:51:15 +08:00
|
|
|
var joined = {};
|
2011-08-18 00:27:45 +08:00
|
|
|
|
2011-12-26 19:51:15 +08:00
|
|
|
// remove oauth_signature from body
|
|
|
|
if(req.body) {
|
2015-05-13 00:00:30 +08:00
|
|
|
delete req.body.oauth_signature;
|
2011-12-26 19:51:15 +08:00
|
|
|
}
|
|
|
|
_.extend(joined, req.body ? req.body : null);
|
|
|
|
_.extend(joined, passed_tokens);
|
|
|
|
_.extend(joined, req.query);
|
2011-08-22 20:33:12 +08:00
|
|
|
|
2011-12-26 19:51:15 +08:00
|
|
|
return signer.sign(method, path, joined);
|
2011-08-18 00:27:45 +08:00
|
|
|
},
|
2011-08-22 20:33:12 +08:00
|
|
|
function checkSignature(err, data){
|
2015-05-13 00:00:30 +08:00
|
|
|
assert.ifError(err);
|
2012-06-30 07:54:21 +08:00
|
|
|
|
2011-08-22 21:18:42 +08:00
|
|
|
//console.log(data + " should equal the provided signature: " + signature);
|
2014-08-05 08:29:07 +08:00
|
|
|
callback(err, (signature === data && !_.isUndefined(data)) ? true : null);
|
2011-08-18 00:27:45 +08:00
|
|
|
}
|
|
|
|
);
|
2011-08-22 20:33:12 +08:00
|
|
|
};
|
|
|
|
|
2014-08-06 18:51:55 +08:00
|
|
|
me.getOAuthHash = function(metadataBackend, oAuthAccessKey, callback){
|
|
|
|
metadataBackend.getOAuthHash(oAuthAccessKey, callback);
|
2011-08-18 00:27:45 +08:00
|
|
|
};
|
2011-08-22 20:33:12 +08:00
|
|
|
|
2011-06-13 11:23:02 +08:00
|
|
|
return me;
|
2015-05-13 00:00:30 +08:00
|
|
|
})();
|
2011-06-13 11:23:02 +08:00
|
|
|
|
2014-08-05 22:20:06 +08:00
|
|
|
function OAuthAuth(req) {
|
|
|
|
this.req = req;
|
|
|
|
this.isOAuthRequest = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
OAuthAuth.prototype.verifyCredentials = function(options, callback) {
|
|
|
|
if (this.hasCredentials()) {
|
2014-08-06 18:51:55 +08:00
|
|
|
oAuth.verifyRequest(this.req, options.metadataBackend, callback);
|
2014-08-05 22:20:06 +08:00
|
|
|
} else {
|
|
|
|
callback(null, false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
OAuthAuth.prototype.hasCredentials = function() {
|
|
|
|
if (this.isOAuthRequest === null) {
|
|
|
|
var passed_tokens = oAuth.parseTokens(this.req);
|
|
|
|
this.isOAuthRequest = !_.isEmpty(passed_tokens);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.isOAuthRequest;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = OAuthAuth;
|
|
|
|
module.exports.backend = oAuth;
|