From ac078fa68ca34d0c7274d1a3e8623f9e544e68ba Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Thu, 24 Oct 2019 10:48:36 -0400 Subject: [PATCH 1/3] correctly decode runner config --- packages/runner/src/lib/util.js | 22 +++++++++++++++++++ packages/runner/src/lib/util.spec.js | 13 +++++++++++ packages/runner/src/main.jsx | 3 ++- packages/server/lib/controllers/runner.coffee | 2 ++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 packages/runner/src/lib/util.spec.js diff --git a/packages/runner/src/lib/util.js b/packages/runner/src/lib/util.js index 85e53764e7a8..e471a8677ece 100644 --- a/packages/runner/src/lib/util.js +++ b/packages/runner/src/lib/util.js @@ -1,6 +1,28 @@ import path from 'path' export default { + /** + * Correctly decodes Unicode string in encoded in base64 + * @see https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings + * + * @example + ``` + Buffer.from(JSON.stringify({state: '๐Ÿ™‚'})).toString('base64') + // 'eyJzdGF0ZSI6IvCfmYIifQ==' + // "window.atob" does NOT work + // atob('eyJzdGF0ZSI6IvCfmYIifQ==') + // "{"state":"รฐยŸย™ย‚"}" + // but this function works + b64DecodeUnicode('eyJzdGF0ZSI6IvCfmYIifQ==') + '{"state":"๐Ÿ™‚"}' + ``` + */ + b64DecodeUnicode (str) { + return decodeURIComponent(atob(str).split('').map(function (c) { + return `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}` + }).join('')) + }, + hasSpecFile () { return !!location.hash }, diff --git a/packages/runner/src/lib/util.spec.js b/packages/runner/src/lib/util.spec.js new file mode 100644 index 000000000000..f09c1061453e --- /dev/null +++ b/packages/runner/src/lib/util.spec.js @@ -0,0 +1,13 @@ +import util from './util' + +describe('util', () => { + context('b64DecodeUnicode', () => { + it('decodes unicode string correctly', () => { + const s = '๐Ÿ™‚ ะฟั€ะธะฒะตั‚ ๐ŸŒŽ' + const encoded = Buffer.from(s).toString('base64') + const decoded = util.b64DecodeUnicode(encoded) + + expect(decoded).to.equal(s) + }) + }) +}) diff --git a/packages/runner/src/main.jsx b/packages/runner/src/main.jsx index 1cc73f4c7f76..74afb5ef81c5 100644 --- a/packages/runner/src/main.jsx +++ b/packages/runner/src/main.jsx @@ -4,13 +4,14 @@ import { render } from 'react-dom' import State from './lib/state' import Container from './app/container' +import util from './lib/util' configure({ enforceActions: 'strict' }) const Runner = { start (el, base64Config) { action('started', () => { - const config = JSON.parse(atob(base64Config)) + const config = JSON.parse(util.b64DecodeUnicode(base64Config)) const state = new State((config.state || {}).reporterWidth) diff --git a/packages/server/lib/controllers/runner.coffee b/packages/server/lib/controllers/runner.coffee index 40bc3598e255..cffa5921fce9 100644 --- a/packages/server/lib/controllers/runner.coffee +++ b/packages/server/lib/controllers/runner.coffee @@ -22,6 +22,8 @@ module.exports = { debug("serving runner index.html with config %o", _.pick(config, "version", "platform", "arch", "projectName") ) + # log the env object's keys without values to avoid leaking sensitive info + debug("env object has the following keys: %s", _.keys(config.env).join(", ")) ## base64 before embedding so user-supplied contents can't break out of