From 2c73fdb0bd73bc1b8b85bee4006b1f8d6c45801d Mon Sep 17 00:00:00 2001 From: e-tip Date: Thu, 22 Sep 2016 19:26:24 +0200 Subject: [PATCH] fix(s3-v4) Invalid v4 signature w/ chunked non-ASCII key (#1632) closes #1630 --- client/js/s3/request-signer.js | 2 +- client/js/s3/s3.xhr.upload.handler.js | 4 ++-- client/js/s3/util.js | 23 +++++++++++++++++++++++ test/unit/s3/util.js | 10 ++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/client/js/s3/request-signer.js b/client/js/s3/request-signer.js index 4fdf6c32b..dcc8ce422 100644 --- a/client/js/s3/request-signer.js +++ b/client/js/s3/request-signer.js @@ -148,7 +148,7 @@ qq.s3.RequestSigner = function(o) { if (queryParamIdx > 0) { path = endOfUri.substr(0, queryParamIdx); } - return escape("/" + decodeURIComponent(path)); + return "/" + path; }, getEncodedHashedPayload: function(body) { diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 481cc7e82..46572e7b0 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -456,8 +456,8 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { }, urlSafe: function(id) { - var encodedKey = encodeURIComponent(handler.getThirdPartyFileId(id)); - return encodedKey.replace(/%2F/g, "/"); + var encodedKey = handler.getThirdPartyFileId(id); + return qq.s3.util.uriEscapePath(encodedKey); } }, diff --git a/client/js/s3/util.js b/client/js/s3/util.js index ba4423fd4..544feb7ed 100644 --- a/client/js/s3/util.js +++ b/client/js/s3/util.js @@ -491,6 +491,29 @@ qq.s3.util = qq.s3.util || (function() { // replace percent-encoded spaces with a "+" return percentEncoded.replace(/%20/g, "+"); + }, + /** + * Escapes url part as for AWS requirements + * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js + */ + uriEscape: function(string) { + var output = encodeURIComponent(string); + output = output.replace(/[^A-Za-z0-9_.~\-%]+/g, escape); + output = output.replace(/[*]/g, function(ch) { + return "%" + ch.charCodeAt(0).toString(16).toUpperCase(); + }); + return output; + }, + /** + * Escapes a path as for AWS requirement + * AWS uriEscapePath function pulled from aws-sdk-js licensed under Apache 2.0 - http://github.com/aws/aws-sdk-js + */ + uriEscapePath: function(path) { + var parts = []; + qq.each(path.split("/"), function(idx, item) { + parts.push(qq.s3.util.uriEscape(item)); + }); + return parts.join("/"); } }; }()); diff --git a/test/unit/s3/util.js b/test/unit/s3/util.js index 08071d449..72422cdc7 100644 --- a/test/unit/s3/util.js +++ b/test/unit/s3/util.js @@ -153,6 +153,16 @@ describe("s3/util.js", function () { assert.equal(response.etag, "789"); }); }); + + describe("uriEscapePath",function(){ + it("encodes params following s3 directives",function(){ + assert.equal(qq.s3.util.uriEscapePath("pippo/pluto e topolino.jpg"),"pippo/pluto%20e%20topolino.jpg"); + assert.equal(qq.s3.util.uriEscapePath("pippo/pluto & mickey+mouse.jpg"),"pippo/pluto%20%26%20mickey%2Bmouse.jpg"); + assert.equal(qq.s3.util.uriEscapePath("pluto & àòè.jpg"),"pluto%20%26%20a%CC%80o%CC%80e%CC%80.jpg"); + assert.equal(qq.s3.util.uriEscapePath("pluto & micke#22.jpg"),"pluto%20%26%20micke%2322.jpg"); + assert.equal(qq.s3.util.uriEscapePath("pluto_lkjhàò=23£"),"pluto_lkjha%CC%80o%CC%80%3D23%C2%A3"); + }); + }); describe("encodeQueryStringParam", function() { it("handles params with spaces correctly", function() {