Merge remote-tracking branch 'origin/master' into evanp-issue144
This commit is contained in:
82
lib/oauth.js
82
lib/oauth.js
@ -13,6 +13,9 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers
|
||||
this._accessUrl= accessUrl;
|
||||
this._consumerKey= consumerKey;
|
||||
this._consumerSecret= this._encodeData( consumerSecret );
|
||||
if (signatureMethod == "RSA-SHA1") {
|
||||
this._privateKey = consumerSecret;
|
||||
}
|
||||
this._version= version;
|
||||
if( authorize_callback === undefined ) {
|
||||
this._authorize_callback= "oob";
|
||||
@ -21,7 +24,7 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers
|
||||
this._authorize_callback= authorize_callback;
|
||||
}
|
||||
|
||||
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1")
|
||||
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1" && signatureMethod != "RSA-SHA1")
|
||||
throw new Error("Un-supported signature method: " + signatureMethod )
|
||||
this._signatureMethod= signatureMethod;
|
||||
this._nonceSize= nonceSize || 32;
|
||||
@ -29,7 +32,8 @@ exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, vers
|
||||
"Connection" : "close",
|
||||
"User-Agent" : "Node authentication"}
|
||||
this._clientOptions= this._defaultClientOptions= {"requestTokenHttpMethod": "POST",
|
||||
"accessTokenHttpMethod": "POST"};
|
||||
"accessTokenHttpMethod": "POST",
|
||||
"followRedirects": true};
|
||||
this._oauthParameterSeperator = ",";
|
||||
};
|
||||
|
||||
@ -40,9 +44,12 @@ exports.OAuthEcho= function(realm, verify_credentials, consumerKey, consumerSecr
|
||||
this._verifyCredentials = verify_credentials;
|
||||
this._consumerKey= consumerKey;
|
||||
this._consumerSecret= this._encodeData( consumerSecret );
|
||||
if (signatureMethod == "RSA-SHA1") {
|
||||
this._privateKey = consumerSecret;
|
||||
}
|
||||
this._version= version;
|
||||
|
||||
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1")
|
||||
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1" && signatureMethod != "RSA-SHA1")
|
||||
throw new Error("Un-supported signature method: " + signatureMethod );
|
||||
this._signatureMethod= signatureMethod;
|
||||
this._nonceSize= nonceSize || 32;
|
||||
@ -86,7 +93,7 @@ exports.OAuth.prototype._getSignature= function(method, url, parameters, tokenSe
|
||||
exports.OAuth.prototype._normalizeUrl= function(url) {
|
||||
var parsedUrl= URL.parse(url, true)
|
||||
var port ="";
|
||||
if( parsedUrl.port ) {
|
||||
if( parsedUrl.port ) {
|
||||
if( (parsedUrl.protocol == "http:" && parsedUrl.port != "80" ) ||
|
||||
(parsedUrl.protocol == "https:" && parsedUrl.port != "443") ) {
|
||||
port= ":" + parsedUrl.port;
|
||||
@ -94,7 +101,7 @@ exports.OAuth.prototype._normalizeUrl= function(url) {
|
||||
}
|
||||
|
||||
if( !parsedUrl.pathname || parsedUrl.pathname == "" ) parsedUrl.pathname ="/";
|
||||
|
||||
|
||||
return parsedUrl.protocol + "//" + parsedUrl.hostname + port + parsedUrl.pathname;
|
||||
}
|
||||
|
||||
@ -124,7 +131,7 @@ exports.OAuth.prototype._buildAuthorizationHeaders= function(orderedParameters)
|
||||
}
|
||||
}
|
||||
|
||||
authHeader= authHeader.substring(0, authHeader.length-this._oauthParameterSeperator.length);
|
||||
authHeader= authHeader.substring(0, authHeader.length-this._oauthParameterSeperator.length);
|
||||
return authHeader;
|
||||
}
|
||||
|
||||
@ -143,33 +150,33 @@ exports.OAuth.prototype._makeArrayOfArgumentsHash= function(argumentsHash) {
|
||||
argument_pairs[argument_pairs.length]= [key, value];
|
||||
}
|
||||
}
|
||||
return argument_pairs;
|
||||
}
|
||||
return argument_pairs;
|
||||
}
|
||||
|
||||
// Sorts the encoded key value pairs by encoded name, then encoded value
|
||||
exports.OAuth.prototype._sortRequestParams= function(argument_pairs) {
|
||||
// Sort by name, then value.
|
||||
argument_pairs.sort(function(a,b) {
|
||||
if ( a[0]== b[0] ) {
|
||||
return a[1] < b[1] ? -1 : 1;
|
||||
return a[1] < b[1] ? -1 : 1;
|
||||
}
|
||||
else return a[0] < b[0] ? -1 : 1;
|
||||
else return a[0] < b[0] ? -1 : 1;
|
||||
});
|
||||
|
||||
return argument_pairs;
|
||||
}
|
||||
|
||||
exports.OAuth.prototype._normaliseRequestParams= function(arguments) {
|
||||
var argument_pairs= this._makeArrayOfArgumentsHash(arguments);
|
||||
exports.OAuth.prototype._normaliseRequestParams= function(args) {
|
||||
var argument_pairs= this._makeArrayOfArgumentsHash(args);
|
||||
// First encode them #3.4.1.3.2 .1
|
||||
for(var i=0;i<argument_pairs.length;i++) {
|
||||
argument_pairs[i][0]= this._encodeData( argument_pairs[i][0] );
|
||||
argument_pairs[i][1]= this._encodeData( argument_pairs[i][1] );
|
||||
}
|
||||
|
||||
|
||||
// Then sort them #3.4.1.3.2 .2
|
||||
argument_pairs= this._sortRequestParams( argument_pairs );
|
||||
|
||||
|
||||
// Then concatenate together #3.4.1.3.2 .3 & .4
|
||||
var args= "";
|
||||
for(var i=0;i<argument_pairs.length;i++) {
|
||||
@ -177,19 +184,19 @@ exports.OAuth.prototype._normaliseRequestParams= function(arguments) {
|
||||
args+= "="
|
||||
args+= argument_pairs[i][1];
|
||||
if( i < argument_pairs.length-1 ) args+= "&";
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
exports.OAuth.prototype._createSignatureBase= function(method, url, parameters) {
|
||||
url= this._encodeData( this._normalizeUrl(url) );
|
||||
url= this._encodeData( this._normalizeUrl(url) );
|
||||
parameters= this._encodeData( parameters );
|
||||
return method.toUpperCase() + "&" + url + "&" + parameters;
|
||||
}
|
||||
|
||||
exports.OAuth.prototype._createSignature= function(signatureBase, tokenSecret) {
|
||||
if( tokenSecret === undefined ) var tokenSecret= "";
|
||||
else tokenSecret= this._encodeData( tokenSecret );
|
||||
else tokenSecret= this._encodeData( tokenSecret );
|
||||
// consumerSecret is already encoded
|
||||
var key= this._consumerSecret + "&" + tokenSecret;
|
||||
|
||||
@ -197,12 +204,16 @@ exports.OAuth.prototype._createSignature= function(signatureBase, tokenSecret) {
|
||||
if( this._signatureMethod == "PLAINTEXT" ) {
|
||||
hash= key;
|
||||
}
|
||||
else if (this._signatureMethod == "RSA-SHA1") {
|
||||
key = this._privateKey || "";
|
||||
hash= crypto.createSign("RSA-SHA1").update(signatureBase).sign(key, 'base64');
|
||||
}
|
||||
else {
|
||||
if( crypto.Hmac ) {
|
||||
hash = crypto.createHmac("sha1", key).update(signatureBase).digest("base64");
|
||||
}
|
||||
else {
|
||||
hash= sha1.HMACSHA1(key, signatureBase);
|
||||
hash= sha1.HMACSHA1(key, signatureBase);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
@ -218,7 +229,7 @@ exports.OAuth.prototype._getNonce= function(nonceSize) {
|
||||
var chars= this.NONCE_CHARS;
|
||||
var char_pos;
|
||||
var nonce_chars_length= chars.length;
|
||||
|
||||
|
||||
for (var i = 0; i < nonceSize; i++) {
|
||||
char_pos= Math.floor(Math.random() * nonce_chars_length);
|
||||
result[i]= chars[char_pos];
|
||||
@ -240,7 +251,7 @@ exports.OAuth.prototype._createClient= function( port, hostname, method, path, h
|
||||
} else {
|
||||
httpModel= http;
|
||||
}
|
||||
return httpModel.request(options);
|
||||
return httpModel.request(options);
|
||||
}
|
||||
|
||||
exports.OAuth.prototype._prepareParameters= function( oauth_token, oauth_token_secret, method, url, extra_params ) {
|
||||
@ -361,22 +372,23 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
||||
request= this._createClient(parsedUrl.port, parsedUrl.hostname, method, path, headers);
|
||||
}
|
||||
|
||||
var clientOptions = this._clientOptions;
|
||||
if( callback ) {
|
||||
var data="";
|
||||
var data="";
|
||||
var self= this;
|
||||
|
||||
// Some hosts *cough* google appear to close the connection early / send no content-length header
|
||||
// allow this behaviour.
|
||||
var allowEarlyClose= OAuthUtils.isAnEarlyCloseHost( parsedUrl.hostname );
|
||||
var callbackCalled= false;
|
||||
function passBackControl( response ) {
|
||||
var passBackControl = function( response ) {
|
||||
if(!callbackCalled) {
|
||||
callbackCalled= true;
|
||||
if ( response.statusCode >= 200 && response.statusCode <= 299 ) {
|
||||
callback(null, data, response);
|
||||
} else {
|
||||
// Follow 301 or 302 redirects with Location HTTP header
|
||||
if((response.statusCode == 301 || response.statusCode == 302) && response.headers && response.headers.location) {
|
||||
if((response.statusCode == 301 || response.statusCode == 302) && clientOptions.followRedirects && response.headers && response.headers.location) {
|
||||
self._performSecureRequest( oauth_token, oauth_token_secret, method, response.headers.location, extra_params, post_body, post_content_type, callback);
|
||||
}
|
||||
else {
|
||||
@ -400,12 +412,14 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
request.on("error", function(err) {
|
||||
callbackCalled= true;
|
||||
callback( err )
|
||||
if(!callbackCalled) {
|
||||
callbackCalled= true;
|
||||
callback( err )
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if( (method == "POST" || method =="PUT") && post_body != null && post_body != "" ) {
|
||||
request.write(post_body);
|
||||
}
|
||||
@ -417,7 +431,7 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -444,7 +458,7 @@ exports.OAuth.prototype.getOAuthAccessToken= function(oauth_token, oauth_token_s
|
||||
} else {
|
||||
extraParams.oauth_verifier= oauth_verifier;
|
||||
}
|
||||
|
||||
|
||||
this._performSecureRequest( oauth_token, oauth_token_secret, this._clientOptions.accessTokenHttpMethod, this._accessUrl, extraParams, null, null, function(error, data, response) {
|
||||
if( error ) callback(error);
|
||||
else {
|
||||
@ -484,7 +498,7 @@ exports.OAuth.prototype._putOrPost= function(method, url, oauth_token, oauth_tok
|
||||
}
|
||||
return this._performSecureRequest( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback );
|
||||
}
|
||||
|
||||
|
||||
|
||||
exports.OAuth.prototype.put= function(url, oauth_token, oauth_token_secret, post_body, post_content_type, callback) {
|
||||
return this._putOrPost("PUT", url, oauth_token, oauth_token_secret, post_body, post_content_type, callback);
|
||||
@ -500,7 +514,7 @@ exports.OAuth.prototype.post= function(url, oauth_token, oauth_token_secret, pos
|
||||
*
|
||||
* The callback should expect a function of the following form:
|
||||
*
|
||||
* function(err, token, token_secret, parsedQueryString) {}
|
||||
* function(err, token, token_secret, parsedQueryString) {}
|
||||
*
|
||||
* This method has optional parameters so can be called in the following 2 ways:
|
||||
*
|
||||
@ -519,7 +533,7 @@ exports.OAuth.prototype.getOAuthRequestToken= function( extraParams, callback )
|
||||
callback = extraParams;
|
||||
extraParams = {};
|
||||
}
|
||||
// Callbacks are 1.0A related
|
||||
// Callbacks are 1.0A related
|
||||
if( this._authorize_callback ) {
|
||||
extraParams["oauth_callback"]= this._authorize_callback;
|
||||
}
|
||||
@ -546,12 +560,12 @@ exports.OAuth.prototype.signUrl= function(url, oauth_token, oauth_token_secret,
|
||||
var orderedParameters= this._prepareParameters(oauth_token, oauth_token_secret, method, url, {});
|
||||
var parsedUrl= URL.parse( url, false );
|
||||
|
||||
var query="";
|
||||
var query="";
|
||||
for( var i= 0 ; i < orderedParameters.length; i++) {
|
||||
query+= orderedParameters[i][0]+"="+ this._encodeData(orderedParameters[i][1]) + "&";
|
||||
}
|
||||
query= query.substring(0, query.length-1);
|
||||
|
||||
|
||||
return parsedUrl.protocol + "//"+ parsedUrl.host + parsedUrl.pathname + "?" + query;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user