Skip to content

Commit

Permalink
parse data URIs in JS to resolve cross-environment and CSP issues (em…
Browse files Browse the repository at this point in the history
  • Loading branch information
buu700 committed Jun 14, 2017
1 parent 7169a30 commit 6ebbef4
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 11 deletions.
5 changes: 4 additions & 1 deletion src/jsifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ function JSify(data, functionsOnly) {
if (mainPass) {
var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js');

var thirdPartyFiles = ['../third_party/sodiumutil/dist/sodiumutil.js'];

// We will start to print out the data, but must do so carefully - we are
// dealing with potentially *huge* strings. Convenient replacements and
// manipulations may create in-memory copies, and we may OOM.
Expand All @@ -45,7 +47,8 @@ function JSify(data, functionsOnly) {
// else. This lets us not hold any strings in memory, we simply print
// things out as they are ready.

var shellParts = read(shellFile).split('{{BODY}}');
var thirdParty = thirdPartyFiles.map(function(f) { return read(f) }).join('\n');
var shellParts = read(shellFile).replace('{{THIRD_PARTY}}', thirdParty).split('{{BODY}}');
print(processMacros(preprocess(shellParts[0], shellFile)));
var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js';
var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()), preFile));
Expand Down
4 changes: 0 additions & 4 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,10 +860,6 @@ var SINGLE_FILE = 0; // If set to 1, embeds all subresources in the emitted JS f
// by converting their file names into base64 data URIs. Embedded
// subresources may include (but aren't limited to) wasm, asm.js,
// and static memory initialization code.
//
// Note that using this option may require a change to consuming
// pages' Content Security Policies -- specifically, adding data:
// to their connect-src directives.

var WASM_TEXT_FILE = ''; // name of the file containing wasm text, if relevant
var WASM_BINARY_FILE = ''; // name of the file containing wasm binary, if relevant
Expand Down
68 changes: 62 additions & 6 deletions src/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ if (!ENVIRONMENT_IS_PTHREAD) PthreadWorkerInit = {};
var currentScriptUrl = ENVIRONMENT_IS_WORKER ? undefined : document.currentScript.src;
#endif

{{THIRD_PARTY}}

if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
// Note that we pollute the global namespace here, otherwise we break in node
Expand All @@ -81,10 +83,13 @@ if (ENVIRONMENT_IS_NODE) {
var nodePath;

Module['read'] = function shell_read(filename, binary) {
if (!nodeFS) nodeFS = require('fs');
if (!nodePath) nodePath = require('path');
filename = nodePath['normalize'](filename);
var ret = nodeFS['readFileSync'](filename);
var ret = parseDataURI(filename);
if (!ret) {
if (!nodeFS) nodeFS = require('fs');
if (!nodePath) nodePath = require('path');
filename = nodePath['normalize'](filename);
ret = nodeFS['readFileSync'](filename);
}
return binary ? ret : ret.toString();
};

Expand Down Expand Up @@ -131,16 +136,26 @@ else if (ENVIRONMENT_IS_SHELL) {
if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm

if (typeof read != 'undefined') {
Module['read'] = read;
Module['read'] = function shell_read(f) {
var data = parseDataURI(f);
if (data) {
return sodiumUtil.to_string(data);
}
return read(f);
};
} else {
Module['read'] = function shell_read() { throw 'no read() available' };
}

Module['readBinary'] = function readBinary(f) {
var data = parseDataURI(f);
if (data) {
return data;
}
if (typeof readbuffer === 'function') {
return new Uint8Array(readbuffer(f));
}
var data = read(f, 'binary');
data = read(f, 'binary');
assert(typeof data === 'object');
return data;
};
Expand All @@ -163,6 +178,10 @@ else if (ENVIRONMENT_IS_SHELL) {
}
else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
Module['read'] = function shell_read(url) {
var data = parseDataURI(url);
if (data) {
return sodiumUtil.to_string(data);
}
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
Expand All @@ -171,6 +190,10 @@ else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {

if (ENVIRONMENT_IS_WORKER) {
Module['readBinary'] = function readBinary(url) {
var data = parseDataURI(f);
if (data) {
return data;
}
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.responseType = 'arraybuffer';
Expand All @@ -180,6 +203,17 @@ else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
}

Module['readAsync'] = function readAsync(url, onload, onerror) {
try {
var data = parseDataURI(url);
if (data) {
setTimeout(function () { onload(data.buffer); }, 0);
return;
}
}
catch (err) {
setTimeout(function () { onerror(err); }, 0);
return;
}
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
Expand Down Expand Up @@ -228,6 +262,28 @@ else {
throw 'Unknown runtime environment. Where are we?';
}

// If filename is a base64 data URI, parses and returns data (Buffer on node,
// Uint8Array otherwise). If filename is not a base64 data URI, returns undefined.
function parseDataURI(filename) {
var dataURIPrefix = 'data:application/octet-stream;base64,';

if (!(
String.prototype.startsWith ?
filename.startsWith(dataURIPrefix) :
filename.indexOf(dataURIPrefix) === 0
)) {
return;
}

var data = filename.slice(dataURIPrefix.length);

if (ENVIRONMENT_IS_NODE) {
return Buffer.from(data, 'base64');
}

return sodiumUtil.from_base64(data);
}

function globalEval(x) {
{{{ makeEval('eval.call(null, x);') }}}
}
Expand Down
48 changes: 48 additions & 0 deletions third_party/sodiumutil/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Simplified BSD License:

Copyright (c) 2017, Cyph, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

---

Copyright (c) 2015-2017
Ahmad Ben Mrad <batikhsouri at gmail dot org>
Frank Denis <j at pureftpd dot org>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

---

Base64 <-> Uint8Array conversion tools harvested from MDN
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
21 changes: 21 additions & 0 deletions third_party/sodiumutil/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
all:
rm -rf dist tmp 2> /dev/null
mkdir dist tmp

wget https://raw.githubusercontent.com/jedisct1/libsodium.js/d4fcfd5/wrapper/wrap-template.js -O tmp/wrap-template.js

cat pre.js > tmp/sodiumutil.js
cat tmp/wrap-template.js | tr '\n' '☁' | perl -pe 's/.*Codecs(.*?)Memory management.*/\1/g' | tr '☁' '\n' >> tmp/sodiumutil.js
echo >> tmp/sodiumutil.js
cat tmp/wrap-template.js | tr '\n' ' ' | perl -pe 's/\s+/ /g' | perl -pe 's/.*(function memcmp.*?)\s+function.*/\1/g' >> tmp/sodiumutil.js
echo >> tmp/sodiumutil.js
cat tmp/wrap-template.js | tr '\n' ' ' | perl -pe 's/\s+/ /g' | perl -pe 's/.*(function memzero.*?)\s+function.*/\1/g' >> tmp/sodiumutil.js
echo >> tmp/sodiumutil.js
cat post.js >> tmp/sodiumutil.js

uglifyjs tmp/sodiumutil.js -cmo dist/sodiumutil.js

rm -rf tmp

clean:
rm -rf dist tmp
5 changes: 5 additions & 0 deletions third_party/sodiumutil/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# sodiumutil

## Overview

Pulls out some useful functions from libsodium.js.
1 change: 1 addition & 0 deletions third_party/sodiumutil/dist/sodiumutil.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions third_party/sodiumutil/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "sodiumutil",
"version": "2.0.1",
"description": "Pulls out some useful functions from libsodium.js",
"main": "dist/sodiumutil.js",
"types": "./sodiumutil.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/cyph/sodiumutil.git"
},
"keywords": ["cryptography"],
"author": "Cyph, Inc. <[email protected]> (https://github.com/cyph)",
"license": "BSD-2-Clause",
"bugs": {
"url": "https://github.com/cyph/sodiumutil/issues"
}
}
57 changes: 57 additions & 0 deletions third_party/sodiumutil/post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
return {
from_base64: function (data) {
return typeof data === 'string' ?
from_base64(data) :
data
;
},
from_hex: function (data) {
return typeof data === 'string' ?
from_hex(data) :
data
;
},
from_string: function (message) {
return typeof message === 'string' ?
from_string(message) :
message
;
},
memcmp: memcmp,
memzero: function (data) {
if (data instanceof Uint8Array) {
memzero(data);
}
else if (typeof Buffer !== 'undefined' && data instanceof Buffer) {
data.fill(0);
}
},
to_base64: function (data) {
return typeof data === 'string' ?
data :
to_base64(data).replace(/\s+/g, '')
;
},
to_hex: function (data) {
return typeof data === 'string' ?
data :
to_hex(data).replace(/\s+/g, '')
;
},
to_string: function (message) {
return typeof message === 'string' ?
message :
to_string(message)
;
}
};
}());


if (typeof module !== 'undefined' && module.exports) {
sodiumUtil.sodiumUtil = sodiumUtil;
module.exports = sodiumUtil;
}
else {
self.sodiumUtil = sodiumUtil;
}
1 change: 1 addition & 0 deletions third_party/sodiumutil/pre.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
var sodiumUtil = (function () {
29 changes: 29 additions & 0 deletions third_party/sodiumutil/sodiumutil.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
declare module 'sodiumutil' {
interface ISodiumUtil {
/** Converts base64 string into binary byte array. */
from_base64 (s: string) : Uint8Array;

/** Converts hex string into binary byte array. */
from_hex (s: string) : Uint8Array;

/** Converts ASCII/Unicode string into binary byte array. */
from_string (s: string) : Uint8Array;

/** Indicates whether two blocks of memory contain the same data. */
memcmp (a: Uint8Array, b: Uint8Array) : boolean;

/** Zeroes out memory. */
memzero (a: Uint8Array) : void;

/** Converts binary into base64 string. */
to_base64 (a: Uint8Array) : string;

/** Converts binary into hex string. */
to_hex (a: Uint8Array) : string;

/** Converts binary into ASCII/Unicode string. */
to_string (a: Uint8Array) : string;
}

const sodiumUtil: ISodiumUtil;
}

0 comments on commit 6ebbef4

Please sign in to comment.