171 lines
5.4 KiB
JavaScript
171 lines
5.4 KiB
JavaScript
// too bound to the request object, but ok for now
|
|
var RedisPool = require("./redis_pool")
|
|
, _ = require('underscore')
|
|
, OAuthUtil = require('oauth-client')
|
|
, url = require('url')
|
|
, Step = require('step');
|
|
_.mixin(require('underscore.string'));
|
|
|
|
var oAuth = function(){
|
|
var me = {
|
|
oauth_database: 3,
|
|
oauth_user_key: "rails:oauth_access_tokens:<%= oauth_access_key %>"
|
|
};
|
|
|
|
// oauth token cases:
|
|
// * in GET request
|
|
// * in header
|
|
me.parseTokens = function(req){
|
|
var query_oauth = _.clone(req.query);
|
|
var header_oauth = {};
|
|
var oauth_variables = ['oauth_consumer_key',
|
|
'oauth_token',
|
|
'oauth_signature_method',
|
|
'oauth_signature',
|
|
'oauth_timestamp',
|
|
'oauth_nonce',
|
|
'oauth_version'];
|
|
|
|
// 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]; });
|
|
|
|
// pull oauth tokens out of header
|
|
var header_string = req.headers.authorization;
|
|
if (!_.isUndefined(header_string)) {
|
|
_.each(oauth_variables, function(oauth_key){
|
|
var matched_string = header_string.match(new RegExp(oauth_key + '=\"([^\"]+)\"'))
|
|
if (!_.isNull(matched_string))
|
|
header_oauth[oauth_key] = decodeURIComponent(matched_string[1]);
|
|
});
|
|
}
|
|
|
|
//merge header and query oauth tokens. preference given to header oauth
|
|
var oauth = _.defaults(header_oauth, query_oauth);
|
|
if (_.keys(oauth).length !== oauth_variables.length) {
|
|
throw new Error('incomplete oauth tokens in request');
|
|
} else {
|
|
return oauth;
|
|
}
|
|
}
|
|
|
|
// remove oauthy tokens from an object
|
|
me.splitParams = function(obj) {
|
|
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;
|
|
}
|
|
|
|
|
|
// oauth token cases:
|
|
// * in GET request
|
|
// * in header
|
|
// WARNING DEPRECATED
|
|
me.parseParams = function(req){
|
|
var oauth_token = null;
|
|
|
|
if (_.isString(req.query.oauth_token)){
|
|
oauth_token = _.trim(req.query.oauth_token);
|
|
} else if (_.isString(req.headers.authorization)) {
|
|
oauth_token = req.headers.authorization.match(/oauth_token=\"([^\"]+)\"/)[1]
|
|
}
|
|
|
|
return (_.isString(oauth_token)) ? oauth_token : null
|
|
}
|
|
|
|
// find user from redis oauth token DB
|
|
// WARNING DEPRECATION IMMINENT
|
|
me.getUserId = function(access_key, callback){
|
|
var that = this;
|
|
RedisPool.acquire(this.oauth_database, function(client){
|
|
var redisClient = client;
|
|
redisClient.hget(_.template(that.oauth_user_key, {oauth_access_key: access_key}), "user_id", function(err, user_id){
|
|
RedisPool.release(that.oauth_database, redisClient);
|
|
return callback(err, user_id)
|
|
});
|
|
});
|
|
}
|
|
|
|
// do new fancy get User ID
|
|
me.verifyRequest = function(req, callback){
|
|
var that = this;
|
|
var http = arguments['2'];
|
|
var passed_tokens;
|
|
var ohash;
|
|
var signature;
|
|
|
|
Step(
|
|
function getTokensFromURL(){
|
|
return oAuth.parseTokens(req);
|
|
},
|
|
function getOAuthHash(err, data){
|
|
if (err) throw err;
|
|
passed_tokens = data;
|
|
that.getOAuthHash(passed_tokens.oauth_token, this);
|
|
},
|
|
function regenerateSignature(err, data){
|
|
if (err) throw err;
|
|
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);
|
|
|
|
var method = req.method;
|
|
var host = req.headers.host;
|
|
var path = http ? 'http://' + host + req.route.path : 'https://' + host + req.route.path;
|
|
that.splitParams(req.query);
|
|
|
|
// remove signature from passed_tokens
|
|
signature = passed_tokens.oauth_signature;
|
|
delete passed_tokens['oauth_signature'];
|
|
|
|
var base64;
|
|
var joined = {};
|
|
|
|
_.extend(joined, req.body ? req.body : null);
|
|
_.extend(joined, passed_tokens);
|
|
_.extend(joined, req.query);
|
|
|
|
return signer.sign(method, path, joined);
|
|
},
|
|
function checkSignature(err, data){
|
|
if (err) throw err;
|
|
callback(err, (signature === data && !_.isUndefined(data)) ? ohash.user_id : null);
|
|
}
|
|
);
|
|
}
|
|
|
|
me.getOAuthHash = function(access_key, callback){
|
|
var that = this;
|
|
RedisPool.acquire(this.oauth_database, function(client){
|
|
var redisClient = client;
|
|
redisClient.HGETALL(_.template(that.oauth_user_key, {oauth_access_key: access_key}), function(err, data){
|
|
RedisPool.release(that.oauth_database, redisClient);
|
|
return callback(err, data)
|
|
});
|
|
});
|
|
};
|
|
|
|
// helper method
|
|
// GONNA DEPRECATE
|
|
me.authorize = function(req, callback){
|
|
var oauth_params = this.parseParams(req);
|
|
return this.getUserId(oauth_params, callback);
|
|
}
|
|
|
|
return me;
|
|
}();
|
|
|
|
module.exports = oAuth;
|
|
|
|
|
|
// get the user secrets and shit by the consumer id, then do the signature. if ok, return user id.
|