Adds support for 1.0A callback urls, and HTTPS endpoints
Introduces a breaking constructing change, there is now a 'callback url' argument that can be supplied prior to the signatureMethod in the constructor. Pass 'null' to explicitly ensure the callback url is never used, 'undefined' to use 'oob', 'oob' to use 'oob' or an absolute url.
This commit is contained in:
parent
6b7b8f3198
commit
63dc8facb6
122
lib/oauth.js
122
lib/oauth.js
@ -1,14 +1,21 @@
|
|||||||
var sha1= require('./sha1'),
|
var crypto= require('crypto'),
|
||||||
|
sha1= require('./sha1'),
|
||||||
http= require('http'),
|
http= require('http'),
|
||||||
URL= require('url'),
|
URL= require('url'),
|
||||||
querystring= require('querystring');
|
querystring= require('querystring');
|
||||||
|
|
||||||
exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, version, signatureMethod, nonceSize) {
|
exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, version, authorize_callback, signatureMethod, nonceSize) {
|
||||||
this._requestUrl= requestUrl;
|
this._requestUrl= requestUrl;
|
||||||
this._accessUrl= accessUrl;
|
this._accessUrl= accessUrl;
|
||||||
this._consumerKey= consumerKey;
|
this._consumerKey= consumerKey;
|
||||||
this._consumerSecret= this._encodeData( consumerSecret );
|
this._consumerSecret= this._encodeData( consumerSecret );
|
||||||
this._version= version;
|
this._version= version;
|
||||||
|
if( authorize_callback === undefined ) {
|
||||||
|
this._authorize_callback= "oob";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._authorize_callback= authorize_callback;
|
||||||
|
}
|
||||||
|
|
||||||
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1")
|
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1")
|
||||||
throw new Error("Un-supported signature method: " + signatureMethod )
|
throw new Error("Un-supported signature method: " + signatureMethod )
|
||||||
@ -81,9 +88,9 @@ exports.OAuth.prototype._normaliseRequestParams= function(arguments) {
|
|||||||
var argument_pairs= this._sortRequestParams( arguments );
|
var argument_pairs= this._sortRequestParams( arguments );
|
||||||
var args= "";
|
var args= "";
|
||||||
for(var i=0;i<argument_pairs.length;i++) {
|
for(var i=0;i<argument_pairs.length;i++) {
|
||||||
args+= argument_pairs[i][0];
|
args+= this._encodeData( argument_pairs[i][0] );
|
||||||
args+= "="
|
args+= "="
|
||||||
args+= argument_pairs[i][1];
|
args+= this._encodeData( argument_pairs[i][1] );
|
||||||
if( i < argument_pairs.length-1 ) args+= "&";
|
if( i < argument_pairs.length-1 ) args+= "&";
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
@ -119,8 +126,8 @@ exports.OAuth.prototype.NONCE_CHARS= ['a','b','c','d','e','f','g','h','i','j','k
|
|||||||
'Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3',
|
'Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3',
|
||||||
'4','5','6','7','8','9'];
|
'4','5','6','7','8','9'];
|
||||||
|
|
||||||
exports.OAuth.prototype._createClient= function( port, hostname ) {
|
exports.OAuth.prototype._createClient= function( port, hostname, sshEnabled, credentials ) {
|
||||||
return http.createClient(port, hostname);
|
return http.createClient(port, hostname, sshEnabled, credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.OAuth.prototype._getNonce= function(nonceSize) {
|
exports.OAuth.prototype._getNonce= function(nonceSize) {
|
||||||
@ -136,7 +143,7 @@ exports.OAuth.prototype._getNonce= function(nonceSize) {
|
|||||||
return result.join('');
|
return result.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, callback ) {
|
exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, callback ) {
|
||||||
var oauthParameters= {
|
var oauthParameters= {
|
||||||
"oauth_timestamp": this._getTimestamp(),
|
"oauth_timestamp": this._getTimestamp(),
|
||||||
"oauth_nonce": this._getNonce(this._nonceSize),
|
"oauth_nonce": this._getNonce(this._nonceSize),
|
||||||
@ -148,6 +155,11 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
|||||||
if( oauth_token ) {
|
if( oauth_token ) {
|
||||||
oauthParameters["oauth_token"]= oauth_token;
|
oauthParameters["oauth_token"]= oauth_token;
|
||||||
}
|
}
|
||||||
|
if( extra_params ) {
|
||||||
|
for( var key in extra_params ) {
|
||||||
|
oauthParameters[key]= extra_params[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var parsedUrl= URL.parse( url, false );
|
var parsedUrl= URL.parse( url, false );
|
||||||
if( parsedUrl.protocol == "http:" && !parsedUrl.port ) parsedUrl.port= 80;
|
if( parsedUrl.protocol == "http:" && !parsedUrl.port ) parsedUrl.port= 80;
|
||||||
@ -166,14 +178,41 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
|||||||
|
|
||||||
var query="";
|
var query="";
|
||||||
for( var i= 0 ; i < orderedParameters.length; i++) {
|
for( var i= 0 ; i < orderedParameters.length; i++) {
|
||||||
query+= orderedParameters[i][0]+"="+ this._encodeData(orderedParameters[i][1]) + "&";
|
query+= this._encodeData(orderedParameters[i][0])+"="+ this._encodeData(orderedParameters[i][1]) + "&";
|
||||||
}
|
}
|
||||||
query= query.substring(0, query.length-1);
|
query= query.substring(0, query.length-1);
|
||||||
|
|
||||||
var oauthProvider= this._createClient(parsedUrl.port, parsedUrl.hostname)
|
|
||||||
var headers= {'Host': parsedUrl.host}
|
|
||||||
var request = oauthProvider.request(method, parsedUrl.pathname + "?" + query, headers);
|
|
||||||
|
|
||||||
|
var oauthProvider;
|
||||||
|
if( parsedUrl.protocol == "https:" ) {
|
||||||
|
oauthProvider= this._createClient(parsedUrl.port, parsedUrl.hostname, true, crypto.createCredentials({}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
oauthProvider= this._createClient(parsedUrl.port, parsedUrl.hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
var headers= {}
|
||||||
|
|
||||||
|
// build request authorization header
|
||||||
|
var authHeader="OAuth ";
|
||||||
|
for( var i= 0 ; i < orderedParameters.length; i++) {
|
||||||
|
authHeader+= this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\",";
|
||||||
|
}
|
||||||
|
authHeader= authHeader.substring(0, authHeader.length-1);
|
||||||
|
|
||||||
|
headers["Authorization"]= authHeader;
|
||||||
|
headers["Host"] = parsedUrl.host
|
||||||
|
headers["Accept"]= "*/*"
|
||||||
|
headers["Connection"]= "close"
|
||||||
|
headers["User-Agent"]= "Express authentication"
|
||||||
|
headers["Content-length"]= 0
|
||||||
|
headers["Content-Type"]= "application/x-www-form-urlencoded"
|
||||||
|
|
||||||
|
var path;
|
||||||
|
if( parsedUrl.query ) path= parsedUrl.pathname + "?"+ parsedUrl.query ;
|
||||||
|
else path= parsedUrl.pathname;
|
||||||
|
|
||||||
|
var request = oauthProvider.request(method, path , headers);
|
||||||
var data="";
|
var data="";
|
||||||
var self= this;
|
var self= this;
|
||||||
request.addListener('response', function (response) {
|
request.addListener('response', function (response) {
|
||||||
@ -189,12 +228,12 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
request.end();
|
request.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
exports.OAuth.prototype.getOauthAccessToken= function(oauth_token, oauth_token_secret, callback) {
|
exports.OAuth.prototype.getOauthAccessToken= function(oauth_token, oauth_token_secret, callback) {
|
||||||
this._performSecureRequest( oauth_token, oauth_token_secret, "GET", this._accessUrl, function(error, data, response) {
|
this._performSecureRequest( oauth_token, oauth_token_secret, "GET", this._accessUrl, null, function(error, data, response) {
|
||||||
if( error ) callback(error);
|
if( error ) callback(error);
|
||||||
else {
|
else {
|
||||||
var results= querystring.parse( data );
|
var results= querystring.parse( data );
|
||||||
@ -208,57 +247,18 @@ exports.OAuth.prototype.getOauthAccessToken= function(oauth_token, oauth_token_s
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.OAuth.prototype.getProtectedResource= function(url, method, oauth_token, oauth_token_secret, callback) {
|
exports.OAuth.prototype.getProtectedResource= function(url, method, oauth_token, oauth_token_secret, callback) {
|
||||||
this._performSecureRequest( oauth_token, oauth_token_secret, method, url, callback );
|
this._performSecureRequest( oauth_token, oauth_token_secret, method, url, null, callback );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
exports.OAuth.prototype.getOAuthRequestToken= function(callback) {
|
exports.OAuth.prototype.getOAuthRequestToken= function(callback) {
|
||||||
var oauthParameters= {
|
var extraParams= {};
|
||||||
"oauth_timestamp": this._getTimestamp(),
|
// Callbacks are 1.0A related
|
||||||
"oauth_nonce": this._getNonce(this._nonceSize),
|
if( this._authorize_callback ) {
|
||||||
"oauth_version": this._version,
|
extraParams["oauth_callback"]= this._authorize_callback;
|
||||||
"oauth_signature_method": this._signatureMethod,
|
|
||||||
"oauth_consumer_key": this._consumerKey
|
|
||||||
};
|
|
||||||
var method= "POST";
|
|
||||||
var sig= this._getSignature( method, this._requestUrl, this._normaliseRequestParams(oauthParameters));
|
|
||||||
|
|
||||||
var parsedUrl= URL.parse( this._requestUrl, false );
|
|
||||||
if( parsedUrl.protocol == "http:" && !parsedUrl.port ) parsedUrl.port= 80;
|
|
||||||
if( parsedUrl.protocol == "https:" && !parsedUrl.port ) parsedUrl.port= 443;
|
|
||||||
|
|
||||||
var orderedParameters= this._sortRequestParams( oauthParameters );
|
|
||||||
orderedParameters[orderedParameters.length]= ["oauth_signature", sig];
|
|
||||||
var headers= {};
|
|
||||||
|
|
||||||
// build request authorization header
|
|
||||||
var authHeader="OAuth ";
|
|
||||||
for( var i= 0 ; i < orderedParameters.length; i++) {
|
|
||||||
authHeader+= orderedParameters[i][0]+"=\""+ this._encodeData(orderedParameters[i][1])+"\",";
|
|
||||||
}
|
}
|
||||||
authHeader= authHeader.substring(0, authHeader.length-1);
|
this._performSecureRequest( null, null, "POST", this._requestUrl, extraParams, function(error, data, response) {
|
||||||
|
if( error ) callback(error);
|
||||||
headers["Authorization"]= authHeader;
|
else {
|
||||||
headers["Host"] = parsedUrl.host
|
|
||||||
headers["Accept"]= "*/*"
|
|
||||||
headers["Connection"]= "close"
|
|
||||||
headers["User-Agent"]= "Express authentication"
|
|
||||||
headers["Content-length"]= 0
|
|
||||||
headers["Content-Type"]= "application/x-www-form-urlencoded"
|
|
||||||
|
|
||||||
var oauthProvider= this._createClient(parsedUrl.port, parsedUrl.hostname);
|
|
||||||
var request = oauthProvider.request(method, parsedUrl.pathname, headers);
|
|
||||||
var data="";
|
|
||||||
var self= this;
|
|
||||||
request.addListener('response', function (response) {
|
|
||||||
response.setEncoding('utf8');
|
|
||||||
response.addListener('data', function (chunk) {
|
|
||||||
data+=chunk;
|
|
||||||
});
|
|
||||||
response.addListener('end', function () {
|
|
||||||
if( response.statusCode != 200 ) {
|
|
||||||
callback( response.statusCode +" : " + data );
|
|
||||||
} else {
|
|
||||||
var results= querystring.parse(data);
|
var results= querystring.parse(data);
|
||||||
|
|
||||||
var oauth_token= results["oauth_token"];
|
var oauth_token= results["oauth_token"];
|
||||||
@ -268,8 +268,6 @@ exports.OAuth.prototype.getOAuthRequestToken= function(callback) {
|
|||||||
callback(null, oauth_token, oauth_token_secret, results );
|
callback(null, oauth_token, oauth_token_secret, results );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
request.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.OAuth.prototype.signUrl= function(url, oauth_token, oauth_token_secret, method) {
|
exports.OAuth.prototype.signUrl= function(url, oauth_token, oauth_token_secret, method) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user