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
124
lib/oauth.js
124
lib/oauth.js
@ -1,14 +1,21 @@
|
||||
var sha1= require('./sha1'),
|
||||
var crypto= require('crypto'),
|
||||
sha1= require('./sha1'),
|
||||
http= require('http'),
|
||||
URL= require('url'),
|
||||
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._accessUrl= accessUrl;
|
||||
this._consumerKey= consumerKey;
|
||||
this._consumerSecret= this._encodeData( consumerSecret );
|
||||
this._version= version;
|
||||
if( authorize_callback === undefined ) {
|
||||
this._authorize_callback= "oob";
|
||||
}
|
||||
else {
|
||||
this._authorize_callback= authorize_callback;
|
||||
}
|
||||
|
||||
if( signatureMethod != "PLAINTEXT" && signatureMethod != "HMAC-SHA1")
|
||||
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 args= "";
|
||||
for(var i=0;i<argument_pairs.length;i++) {
|
||||
args+= argument_pairs[i][0];
|
||||
args+= this._encodeData( argument_pairs[i][0] );
|
||||
args+= "="
|
||||
args+= argument_pairs[i][1];
|
||||
args+= this._encodeData( argument_pairs[i][1] );
|
||||
if( i < argument_pairs.length-1 ) args+= "&";
|
||||
}
|
||||
return args;
|
||||
@ -91,7 +98,7 @@ exports.OAuth.prototype._normaliseRequestParams= function(arguments) {
|
||||
|
||||
exports.OAuth.prototype._createSignatureBase= function(method, url, parameters) {
|
||||
url= this._encodeData( this._normalizeUrl(url) );
|
||||
parameters= this._encodeData(parameters);
|
||||
parameters= this._encodeData( parameters );
|
||||
return method.toUpperCase() + "&" + url + "&" + parameters;
|
||||
}
|
||||
|
||||
@ -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',
|
||||
'4','5','6','7','8','9'];
|
||||
|
||||
exports.OAuth.prototype._createClient= function( port, hostname ) {
|
||||
return http.createClient(port, hostname);
|
||||
exports.OAuth.prototype._createClient= function( port, hostname, sshEnabled, credentials ) {
|
||||
return http.createClient(port, hostname, sshEnabled, credentials);
|
||||
}
|
||||
|
||||
exports.OAuth.prototype._getNonce= function(nonceSize) {
|
||||
@ -136,7 +143,7 @@ exports.OAuth.prototype._getNonce= function(nonceSize) {
|
||||
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= {
|
||||
"oauth_timestamp": this._getTimestamp(),
|
||||
"oauth_nonce": this._getNonce(this._nonceSize),
|
||||
@ -148,6 +155,11 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
||||
if( 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 );
|
||||
if( parsedUrl.protocol == "http:" && !parsedUrl.port ) parsedUrl.port= 80;
|
||||
@ -166,14 +178,41 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
||||
|
||||
var query="";
|
||||
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);
|
||||
|
||||
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 self= this;
|
||||
request.addListener('response', function (response) {
|
||||
@ -189,12 +228,12 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
request.end();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
else {
|
||||
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) {
|
||||
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) {
|
||||
var oauthParameters= {
|
||||
"oauth_timestamp": this._getTimestamp(),
|
||||
"oauth_nonce": this._getNonce(this._nonceSize),
|
||||
"oauth_version": this._version,
|
||||
"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])+"\",";
|
||||
var extraParams= {};
|
||||
// Callbacks are 1.0A related
|
||||
if( this._authorize_callback ) {
|
||||
extraParams["oauth_callback"]= this._authorize_callback;
|
||||
}
|
||||
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 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 {
|
||||
this._performSecureRequest( null, null, "POST", this._requestUrl, extraParams, function(error, data, response) {
|
||||
if( error ) callback(error);
|
||||
else {
|
||||
var results= querystring.parse(data);
|
||||
|
||||
var oauth_token= results["oauth_token"];
|
||||
@ -268,8 +268,6 @@ exports.OAuth.prototype.getOAuthRequestToken= function(callback) {
|
||||
callback(null, oauth_token, oauth_token_secret, results );
|
||||
}
|
||||
});
|
||||
});
|
||||
request.end();
|
||||
}
|
||||
|
||||
exports.OAuth.prototype.signUrl= function(url, oauth_token, oauth_token_secret, method) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user