From b6f7e030617ae4dfa69195f86993a8e76f18d89b Mon Sep 17 00:00:00 2001 From: ciaranj Date: Sun, 31 Oct 2010 23:15:22 +0000 Subject: [PATCH] Extra params when passed as a POST will now properly get set as the POST body rather than be discarded as previously --- lib/oauth.js | 35 +++++++-- tests/oauth.js | 202 ++++++++++++++++++++++++++++--------------------- 2 files changed, 144 insertions(+), 93 deletions(-) diff --git a/lib/oauth.js b/lib/oauth.js index 6418144..0890f6a 100644 --- a/lib/oauth.js +++ b/lib/oauth.js @@ -51,8 +51,8 @@ exports.OAuth.prototype._decodeData= function(toDecode) { } exports.OAuth.prototype._getSignature= function(method, url, parameters, tokenSecret) { - var signatureBase= this._createSignatureBase(method, url, parameters); - return this._createSignature( signatureBase, tokenSecret ); + var signatureBase= this._createSignatureBase(method, url, parameters); + return this._createSignature( signatureBase, tokenSecret ); } exports.OAuth.prototype._normalizeUrl= function(url) { @@ -70,14 +70,24 @@ exports.OAuth.prototype._normalizeUrl= function(url) { return parsedUrl.protocol + "//" + parsedUrl.hostname + port + parsedUrl.pathname; } +// Is the parameter considered an OAuth parameter +exports.OAuth.prototype._isParameterNameAnOAuthParameter= function(parameter) { + var m = parameter.match('^oauth_'); + if( m && ( m[0] === "oauth_" ) ) { + return true; + } + else { + return false; + } +}; + // build the OAuth request authorization header exports.OAuth.prototype._buildAuthorizationHeaders= function(orderedParameters) { var authHeader="OAuth "; for( var i= 0 ; i < orderedParameters.length; i++) { // Whilst the all the parameters should be included within the signature, only the oauth_ arguments // should appear within the authorization header. - var m = orderedParameters[i][0].match('^oauth_'); - if( m && ( m[0] === "oauth_" || m[0] === 'scope' ) ) { + if( this._isParameterNameAnOAuthParameter(orderedParameters[i][0]) ) { authHeader+= this._encodeData(orderedParameters[i][0])+"=\""+ this._encodeData(orderedParameters[i][1])+"\","; } } @@ -220,6 +230,17 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke } } + // Filter out any passed extra_params that are really to do with OAuth + for(var key in extra_params) { + if( this._isParameterNameAnOAuthParameter( key ) ) { + delete extra_params[key]; + } + } + + if( method == "POST" && ( post_body == null && extra_params != null) ) { + post_body= querystring.stringify(extra_params); + } + headers["Content-length"]= post_body ? post_body.length : 0; //Probably going to fail if not posting ascii headers["Content-Type"]= post_content_type; @@ -270,7 +291,7 @@ exports.OAuth.prototype.getOAuthAccessToken= function(oauth_token, oauth_token_s extraParams.oauth_verifier= oauth_verifier; } - this._performSecureRequest( oauth_token, oauth_token_secret, "GET", this._accessUrl, extraParams, "", null, function(error, data, response) { + this._performSecureRequest( oauth_token, oauth_token_secret, "GET", this._accessUrl, extraParams, null, null, function(error, data, response) { if( error ) callback(error); else { var results= querystring.parse( data ); @@ -301,7 +322,7 @@ exports.OAuth.prototype.post= function(url, oauth_token, oauth_token_secret, pos if( typeof post_body != "string" ) { post_content_type= "application/x-www-form-urlencoded" extra_params= post_body; - post_body= querystring.stringify(post_body); + post_body= null; } return this._performSecureRequest( oauth_token, oauth_token_secret, "POST", url, extra_params, post_body, post_content_type, callback ); } @@ -316,7 +337,7 @@ exports.OAuth.prototype.getOAuthRequestToken= function(extraParams, callback) { if( this._authorize_callback ) { extraParams["oauth_callback"]= this._authorize_callback; } - this._performSecureRequest( null, null, "POST", this._requestUrl, extraParams, "", null, function(error, data, response) { + this._performSecureRequest( null, null, "POST", this._requestUrl, extraParams, null, null, function(error, data, response) { if( error ) callback(error); else { var results= querystring.parse(data); diff --git a/tests/oauth.js b/tests/oauth.js index e9ef9a7..e4f653e 100644 --- a/tests/oauth.js +++ b/tests/oauth.js @@ -110,21 +110,31 @@ vows.describe('OAuth').addBatch({ 'using the POST method' : { 'Any passed extra_params should form part of the POST body': function(oa) { var post_body_written= false; - var _oldRequest= oa.request; - oa.request= function(method, path, headers) { - return { - write: function(post_body) { - post_body_written= true; - assert.equal(post_body,"FOO"); + var op= oa._createClient; + try { + oa._createClient= function() { + return { + request: function(method, path, headers) { + return { + write: function(post_body){ + post_body_written= true; + assert.equal(post_body,"scope=foobar%2C1%2C2"); + }, + socket: {addListener: function(){}}, + addListener: function() {}, + end: function() {} + } + } } } + oa._performSecureRequest("token", "token_secret", 'POST', 'http://foo.com/protected_resource', {"scope": "foobar,1,2"}); + assert.equal(post_body_written, true); + } + finally { + oa._createClient= op; } - // oa._performSecureRequest("token", "token_secret", 'POST', 'http://foo.com/protected_resource', {"scope": "foobar"}); - oa.request= _oldRequest; - assert.equal(post_body_written, true); } } -// exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) { }, 'When performing a secure' : { topic: new OAuth("http://foo.com/RequestToken", @@ -144,102 +154,118 @@ vows.describe('OAuth').addBatch({ "it should call the internal request's end method and return nothing": function(oa) { var callbackCalled= false; var op= oa._createClient; - oa._createClient= function() { - return { - request: function(method, path, headers) { - return { - write: function(){}, - socket: {addListener: function(){}}, - addListener: function() {}, - end: function() { - callbackCalled= true; + try { + oa._createClient= function() { + return { + request: function(method, path, headers) { + return { + write: function(){}, + socket: {addListener: function(){}}, + addListener: function() {}, + end: function() { + callbackCalled= true; + } } } } } + var request= oa.post("http://foo.com/blah", "token", "token_secret", "BLAH", "text/plain", function(e,d){}) + assert.equal(callbackCalled, true); + assert.isUndefined(request); + } + finally { + oa._createClient= op; } - var request= oa.post("http://foo.com/blah", "token", "token_secret", "BLAH", "text/plain", function(e,d){}) - assert.equal(callbackCalled, true); - assert.isUndefined(request); - oa._createClient= op; } }, 'if the post_body is not a string' : { "It should be url encoded and the content type set to be x-www-form-urlencoded" : function(oa) { var op= oa._createClient; - var callbackCalled= false; - oa._createClient= function() { - return { - request: function(method, path, headers) { - assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded") - return { - socket: {addListener: function(){}}, - write: function(data) { - callbackCalled= true; - assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2"); - }, - addListener: function() {}, - end: function() {} + try { + var callbackCalled= false; + oa._createClient= function() { + return { + request: function(method, path, headers) { + assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded") + return { + socket: {addListener: function(){}}, + write: function(data) { + callbackCalled= true; + assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2"); + }, + addListener: function() {}, + end: function() {} + } } } } + var request= oa.post("http://foo.com/blah", "token", "token_secret", {"foo":"1,2,3", "bar":"1+2"}) + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; } - var request= oa.post("http://foo.com/blah", "token", "token_secret", {"foo":"1,2,3", "bar":"1+2"}) - assert.equal(callbackCalled, true); - oa._createClient= op; } }, 'if the post_body is a string' : { "and no post_content_type is specified" : { "It should be written as is, with a content length specified, and the encoding should be set to be x-www-form-urlencoded" : function(oa) { var op= oa._createClient; - var callbackCalled= false; - oa._createClient= function() { - return { - request: function(method, path, headers) { - assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded"); - assert.equal(headers["Content-length"], 23); - return { - socket: {addListener: function(){}}, - write: function(data) { - callbackCalled= true; - assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2"); - }, - addListener: function() {}, - end: function() {} + try { + var callbackCalled= false; + oa._createClient= function() { + return { + request: function(method, path, headers) { + assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded"); + assert.equal(headers["Content-length"], 23); + return { + socket: {addListener: function(){}}, + write: function(data) { + callbackCalled= true; + assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2"); + }, + addListener: function() {}, + end: function() {} + } } } } + var request= oa.post("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2") + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; } - var request= oa.post("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2") - assert.equal(callbackCalled, true); - oa._createClient= op; } }, "and a post_content_type is specified" : { "It should be written as is, with a content length specified, and the encoding should be set to be as specified" : function(oa) { var op= oa._createClient; - var callbackCalled= false; - oa._createClient= function() { - return { - request: function(method, path, headers) { - assert.equal(headers["Content-Type"], "unicorn/encoded"); - assert.equal(headers["Content-length"], 23); - return { - socket: {addListener: function(){}}, - write: function(data) { - callbackCalled= true; - assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2"); - }, - addListener: function() {}, - end: function() {} + try { + var callbackCalled= false; + oa._createClient= function() { + return { + request: function(method, path, headers) { + assert.equal(headers["Content-Type"], "unicorn/encoded"); + assert.equal(headers["Content-length"], 23); + return { + socket: {addListener: function(){}}, + write: function(data) { + callbackCalled= true; + assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2"); + }, + addListener: function() {}, + end: function() {} + } } } } + var request= oa.post("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2", "unicorn/encoded") + assert.equal(callbackCalled, true); + } + finally { + oa._createClient= op; } - var request= oa.post("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2", "unicorn/encoded") - assert.equal(callbackCalled, true); - oa._createClient= op; } } } @@ -248,7 +274,7 @@ vows.describe('OAuth').addBatch({ 'if no callback is passed' : { 'it should return a request object': function(oa) { var request= oa.get("http://foo.com/blah", "token", "token_secret") - assert.isObject(request); + assert.isObject(request); assert.equal(request.method, "GET"); request.end(); } @@ -257,23 +283,27 @@ vows.describe('OAuth').addBatch({ "it should call the internal request's end method and return nothing": function(oa) { var callbackCalled= false; var op= oa._createClient; - oa._createClient= function() { - return { - request: function(method, path, headers) { - return { - socket: {addListener: function(){}}, - addListener: function() {}, - end: function() { - callbackCalled= true; + try { + oa._createClient= function() { + return { + request: function(method, path, headers) { + return { + socket: {addListener: function(){}}, + addListener: function() {}, + end: function() { + callbackCalled= true; + } } } } } + var request= oa.get("http://foo.com/blah", "token", "token_secret", function(e,d) {}) + assert.equal(callbackCalled, true); + assert.isUndefined(request); + } + finally { + oa._createClient= op; } - var request= oa.get("http://foo.com/blah", "token", "token_secret", function(e,d) {}) - assert.equal(callbackCalled, true); - assert.isUndefined(request); - oa._createClient= op; } }, }