diff --git a/packages/accounts-oauth1-helper/oauth1_binding.js b/packages/accounts-oauth1-helper/oauth1_binding.js index 4b4bcf11ce..011dd3708b 100644 --- a/packages/accounts-oauth1-helper/oauth1_binding.js +++ b/packages/accounts-oauth1-helper/oauth1_binding.js @@ -95,13 +95,13 @@ OAuth1Binding.prototype._getSignature = function(method, url, rawHeaders, access var signatureBase = [ method, - encodeURIComponent(url), - encodeURIComponent(parameters) + self._encodeString(url), + self._encodeString(parameters) ].join('&'); - var signingKey = encodeURIComponent(self._secret) + '&'; + var signingKey = self._encodeString(self._secret) + '&'; if (accessTokenSecret) - signingKey += encodeURIComponent(accessTokenSecret); + signingKey += self._encodeString(accessTokenSecret); return crypto.createHmac('SHA1', signingKey).update(signatureBase).digest('base64'); }; @@ -132,14 +132,22 @@ OAuth1Binding.prototype._call = function(method, url, headers, params) { }; OAuth1Binding.prototype._encodeHeader = function(header) { + var self = this; return _.reduce(header, function(memo, val, key) { - memo[encodeURIComponent(key)] = encodeURIComponent(val); + memo[self._encodeString(key)] = self._encodeString(val); return memo; }, {}); }; +OAuth1Binding.prototype._encodeString = function(str) { + if(str == null || str == "") return ""; + + return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A"); +}; + OAuth1Binding.prototype._getAuthHeaderString = function(headers) { + var self = this; return 'OAuth ' + _.map(headers, function(val, key) { - return encodeURIComponent(key) + '="' + encodeURIComponent(val) + '"'; + return self._encodeString(key) + '="' + self._encodeString(val) + '"'; }).sort().join(', '); }; diff --git a/packages/http/httpcall_common.js b/packages/http/httpcall_common.js index 101e8028f8..2b4513ef21 100644 --- a/packages/http/httpcall_common.js +++ b/packages/http/httpcall_common.js @@ -4,15 +4,22 @@ Meteor.http = Meteor.http || {}; (function() { Meteor.http._encodeParams = function(params) { + self = this; var buf = []; _.each(params, function(value, key) { if (buf.length) buf.push('&'); - buf.push(encodeURIComponent(key), '=', encodeURIComponent(value)); + buf.push(self._encodeString(key), '=', self._encodeString(value)); }); return buf.join('').replace(/%20/g, '+'); }; + Meteor.http._encodeString = function(str) { + if(str == null || str == "") return ""; + + return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A"); + }; + Meteor.http._buildUrl = function(before_qmark, from_qmark, opt_query, opt_params) { var url_without_query = before_qmark; var query = from_qmark ? from_qmark.slice(1) : null; diff --git a/packages/http/httpcall_tests.js b/packages/http/httpcall_tests.js index edd0a29fbd..b809e8d8bd 100644 --- a/packages/http/httpcall_tests.js +++ b/packages/http/httpcall_tests.js @@ -294,7 +294,6 @@ testAsyncMulti("httpcall - headers", [ testAsyncMulti("httpcall - params", [ function(test, expect) { - var do_test = function(method, url, params, opt_opts, expect_url, expect_body) { var opts = {}; if (typeof opt_opts === "string") { @@ -324,6 +323,8 @@ testAsyncMulti("httpcall - params", [ do_test("GET", "/", {foo:"bar", fruit:"apple"}, "/?foo=bar&fruit=apple", ""); do_test("POST", "/", {foo:"bar", fruit:"apple"}, "/", "foo=bar&fruit=apple"); do_test("POST", "/", {foo:"bar", fruit:"apple"}, "/", "foo=bar&fruit=apple"); + do_test("GET", "/", {'foo!':"bang!"}, {}, "/?foo%21=bang%21", ""); + do_test("POST", "/", {'foo!':"bang!"}, {}, "/", "foo%21=bang%21"); do_test("POST", "/", {foo:"bar", fruit:"apple"}, { content: "stuff!"}, "/?foo=bar&fruit=apple", "stuff!"); do_test("POST", "/", {foo:"bar", greeting:"Hello World"}, {