From 33b2081a3e68090d4f3c64afbb6dddfac2e5dd70 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 9 Jan 2018 16:18:17 -0800 Subject: [PATCH 1/2] Normalize URLs in HMAC interceptor - and unit tests thereof - also, uncomment the HMAC debugging code (if variable GP_VERBOSE is true) Fixes: https://github.com/IBM-Cloud/gp-js-client/issues/113 --- lib/gp-hmac.js | 25 ++++++++++++++++++------- test/client-test.js | 17 ++++++++++++++++- test/hmac-test.js | 26 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/lib/gp-hmac.js b/lib/gp-hmac.js index 38bd0d3..fb0a9ff 100644 --- a/lib/gp-hmac.js +++ b/lib/gp-hmac.js @@ -14,8 +14,10 @@ * limitations under the License. */ -var crypto = require('crypto'); +/* eslint no-console: "off" */ +const crypto = require('crypto'); +const url = require('url'); /** * @author Steven R. Loomis * @ignore @@ -36,13 +38,14 @@ GaasHmac.prototype.user = undefined; GaasHmac.prototype.secret = undefined; GaasHmac.prototype.AUTH_SCHEME = "GaaS-HMAC"; +// GaasHmac.prototype.AUTH_SCHEME = "GP-HMAC"; GaasHmac.prototype.SEP = "\n"; GaasHmac.prototype.ENC = "ascii"; // ISO-8859-1 not supported! GaasHmac.prototype.HMAC_SHA1_ALGORITHM = 'sha1'; // "HmacSHA1"; GaasHmac.prototype.forceDate = null; GaasHmac.prototype.forceDateString = null; -// GaasHmac.prototype.VERBOSE = process.env.GP_VERBOSE || false; +GaasHmac.prototype.VERBOSE = process.env.GP_VERBOSE || false; function rfc1123date(d) { return d.toUTCString(); @@ -82,8 +85,17 @@ function rfc1123date(d) { * The Date: header is required for HMAC. */ GaasHmac.prototype.apply = function(obj) { - //if(this.VERBOSE) console.dir(obj, {color: true, depth: null}); + if(this.VERBOSE) console.dir(obj, {color: true, depth: null}); if(obj.url.indexOf("/swagger.json") !== -1) return obj; // skip for swagger.json + + const href = url.parse(obj.url).href; + if(href !== obj.url) { + if(this.VERBOSE) console.log('hmac: Warn: normalized', obj.url, '->', href); + // For example, if there is a quote (') in the URL, it will turn into %27 + // AFTER this interceptor is called (by Fetch). + obj.url = href; + } + var dateString = (this.forceDateString || rfc1123date(this.forceDate || new Date())); var bodyString = ""; @@ -98,15 +110,14 @@ GaasHmac.prototype.apply = function(obj) { obj.url + this.SEP + dateString + this.SEP + bodyString; - //if(this.VERBOSE) console.log('hmacText = <<' + hmacText + '>>'); - //var hmacBuffer = new Buffer(hmacText, this.ENC); + if(this.VERBOSE) console.log('hmacText = <<' + hmacText + '>>'); var hmacHash = crypto.createHmac(this.HMAC_SHA1_ALGORITHM, this.secretBuffer ) .update(hmacText, 'utf8') .digest('base64'); - //if(this.VERBOSE) console.log('hmacHash = ' + hmacHash ); + if(this.VERBOSE) console.log('hmacHash = ' + hmacHash ); var hmacHeader = this.AUTH_SCHEME + ' ' + this.user + ':' + hmacHash; - //if(this.VERBOSE) console.log('hmacHeader = ' + hmacHeader); + if(this.VERBOSE) console.log('hmacHeader = ' + hmacHeader); obj.headers.Authorization = hmacHeader; obj.headers.Date = dateString; return obj; diff --git a/test/client-test.js b/test/client-test.js index c33be8d..73b6e66 100644 --- a/test/client-test.js +++ b/test/client-test.js @@ -40,6 +40,7 @@ var NO_DELETE = process.env.NO_DELETE || false; if(VERBOSE) console.dir(module.filename); var projectId = process.env.GP_PROJECT || 'MyHLProject'+Math.random(); +const projectId_space = projectId+'_space'; // var projectId2 = process.env.GP_PROJECT2 || 'MyOtherHLProject'+Math.random(); var projectId3 = process.env.GP_PROJECT3 || 'MyUserProject'+Math.random(); var projectId4 = process.env.GP_PROJECT3 || 'MyUpdatedProject'+Math.random(); @@ -371,6 +372,11 @@ describe('gaasClient.bundle()', function() { targetLanguages: [gaasTest.TARGETS[0],gaasTest.CYRILLIC], notes: ['Note to self'] }); }); + it('Should let us create ' + projectId_space, () => + gaasClient + .bundle({id: projectId_space, serviceInstance: instanceName}) + .create({sourceLanguage: 'en', targetLanguages: []})); + // Create some strings for later it('Should let us create ' + projectId4, function() { var proj = gaasClient.bundle({id:projectId4, serviceInstance: instanceName}); @@ -467,7 +473,10 @@ describe('gaasClient.bundle()', function() { return done(); }); }); - + it('Should let us upload to ' + projectId_space, () => + gaasClient + .bundle({id: projectId_space, serviceInstance: instanceName}) + .uploadStrings({ languageId: 'en', strings: { "I' d_2dd7f01d": 'I’m sorry, Dave.' }})); if(DELAY_AVAIL) it('should let us verify the target entry(qru).key1 is in progress', function(done) { var proj = gaasClient.bundle({id:projectId, serviceInstance: instanceName}); @@ -530,6 +539,12 @@ describe('gaasClient.bundle()', function() { done(); }); }); + it('Should let us verfy ' + projectId_space, () => + gaasClient + .bundle({id: projectId_space, serviceInstance: instanceName}) + .getResourceEntryInfo({languageId: 'en', resourceKey: "I' d_2dd7f01d"}) + .then(((data) => console.dir(data) && expect(data.resourceEntry.value).to.contain('Dave')))); + it('should let us verify some source entries', function(done) { var bund = gaasClient.bundle({id:projectId, serviceInstance: instanceName}); var entry = bund.entry({languageId:gaasTest.SOURCES[0],resourceKey:'key1'}); diff --git a/test/hmac-test.js b/test/hmac-test.js index ef2a143..076fcaa 100644 --- a/test/hmac-test.js +++ b/test/hmac-test.js @@ -93,6 +93,32 @@ describe('lib/gaas-hmac', function() { expect(obj.headers.Date).to.be.ok; expect(obj.headers.Date).to.equal(myHmac.forceDateString); }); + it('Should verify that we can apply with a spacious key body (golden test)', function() { + var myHmac = new GaasHmac('MyAuth', 'MyUser', 'MySecret'); + + expect(myHmac).to.be.ok; + expect(myHmac.name).to.be.ok; + expect(myHmac.name).to.equal('MyAuth'); + + var obj = { + method: 'GET', + url: "https://example.com/translate/rest/19e7b569069447b6b1f7bbdf8106decc/v2/bundles/mybundle/fr/I'%20d_2dd7f01d", // This gets escaped to I%27%20 … + headers: { + Authorization: undefined + }, + body: '{"param":"value"}' + }; + + // we must force the Date so that we have a consistent test. + myHmac.forceDateString = "Mon, 30 Jun 2014 00:00:00 GMT"; // Bluemix launch date + expect(myHmac.apply(obj)).to.be.ok; + + expect(obj.headers.Authorization).to.be.ok; + expect(obj.headers.Authorization).to.equal( + 'GaaS-HMAC MyUser:6iqc3pISoVrgGLMzxhZ9jujUm64='); + expect(obj.headers.Date).to.be.ok; + expect(obj.headers.Date).to.equal(myHmac.forceDateString); + }); it('Should verify that we can apply with undefined body', function() { var myHmac = new GaasHmac('MyAuth', 'MyUser', 'MySecret'); From fe6e2128af87a34e4ae72a93ac81007baf55dc19 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 9 Jan 2018 16:42:14 -0800 Subject: [PATCH 2/2] remove debug printf Fixes: https://github.com/IBM-Cloud/gp-js-client/issues/113 --- test/client-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/client-test.js b/test/client-test.js index 73b6e66..d2a761e 100644 --- a/test/client-test.js +++ b/test/client-test.js @@ -543,7 +543,7 @@ describe('gaasClient.bundle()', function() { gaasClient .bundle({id: projectId_space, serviceInstance: instanceName}) .getResourceEntryInfo({languageId: 'en', resourceKey: "I' d_2dd7f01d"}) - .then(((data) => console.dir(data) && expect(data.resourceEntry.value).to.contain('Dave')))); + .then(((data) => expect(data.resourceEntry.value).to.contain('Dave')))); it('should let us verify some source entries', function(done) { var bund = gaasClient.bundle({id:projectId, serviceInstance: instanceName});