Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS -- Add a sandbox based on quickjs #12604

Merged
merged 1 commit into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ external/webL10n/
external/cmapscompress/
external/builder/fixtures/
external/builder/fixtures_esprima/
external/quickjs/quickjs-eval.js
src/shared/cffStandardStrings.js
src/shared/fonts_utils.js
test/tmp/
Expand Down
42 changes: 42 additions & 0 deletions external/quickjs/quickjs-eval.js

Large diffs are not rendered by default.

243 changes: 200 additions & 43 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var stream = require("stream");
var exec = require("child_process").exec;
var spawn = require("child_process").spawn;
var spawnSync = require("child_process").spawnSync;
var stripComments = require("gulp-strip-comments");
var streamqueue = require("streamqueue");
var merge = require("merge-stream");
var zip = require("gulp-zip");
Expand Down Expand Up @@ -105,6 +106,7 @@ const DEFINES = Object.freeze({
COMPONENTS: false,
LIB: false,
IMAGE_DECODERS: false,
NO_SOURCE_MAP: false,
});

function transform(charEncoding, transformFunction) {
Expand Down Expand Up @@ -182,7 +184,8 @@ function createWebpackConfig(defines, output) {
var enableSourceMaps =
!bundleDefines.MOZCENTRAL &&
!bundleDefines.CHROME &&
!bundleDefines.TESTING;
!bundleDefines.TESTING &&
!bundleDefines.NO_SOURCE_MAP;
var skipBabel = bundleDefines.SKIP_BABEL;

// `core-js` (see /~https://github.com/zloirock/core-js/issues/514),
Expand Down Expand Up @@ -343,6 +346,53 @@ function createScriptingBundle(defines) {
.pipe(replaceJSRootName(scriptingAMDName, "pdfjsScripting"));
}

function createSandboxBundle(defines, code) {
var sandboxAMDName = "pdfjs-dist/build/pdf.sandbox";
var sandboxOutputName = "pdf.sandbox.js";
var sandboxFileConfig = createWebpackConfig(defines, {
filename: sandboxOutputName,
library: sandboxAMDName,
libraryTarget: "umd",
umdNamedDefine: true,
});

// The code is the one from the bundle pdf.scripting.js
// so in order to have it in a string (which will be eval-ed
// in the sandbox) we must escape some chars.
// This way we've all the code (initialization+sandbox) in
// the same bundle.
code = code.replace(/["\\\n\t]/g, match => {
if (match === "\n") {
return "\\n";
}
if (match === "\t") {
return "\\t";
}
return `\\${match}`;
});
return (
gulp
.src("./src/scripting_api/quickjs-sandbox.js")
.pipe(webpack2Stream(sandboxFileConfig))
.pipe(replaceWebpackRequire())
.pipe(replaceJSRootName(sandboxAMDName, "pdfjsSandbox"))
// put the code in a string to be eval-ed in the sandbox
.pipe(replace("/* INITIALIZATION_CODE */", `${code}`))
);
}

function buildSandbox(defines, dir) {
const scriptingDefines = builder.merge(defines, { NO_SOURCE_MAP: true });
return createScriptingBundle(scriptingDefines)
.pipe(stripComments())
.pipe(gulp.dest(dir + "build"))
.on("data", file => {
const content = file.contents.toString();
createSandboxBundle(defines, content).pipe(gulp.dest(dir + "build"));
fs.unlinkSync(dir + "build/pdf.scripting.js");
});
}

function createWorkerBundle(defines) {
var workerAMDName = "pdfjs-dist/build/pdf.worker";
var workerOutputName = "pdf.worker.js";
Expand Down Expand Up @@ -494,6 +544,25 @@ function makeRef(done, bot) {
});
}

gulp.task("sandbox", function (done) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest separating the createScriptingBundle from this gulp-task, and possible even remove this completely.

For the mozcentral task you added the createScriptingBundle to list existing list of tasks in

pdf.js/gulpfile.js

Lines 1065 to 1067 in 55f55f5

createScriptingBundle(defines).pipe(
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
),

hence I suggest adding createScriptingBundle and createSandboxBundle to buildGeneric instead:

pdf.js/gulpfile.js

Lines 723 to 729 in 55f55f5

function buildGeneric(defines, dir) {
rimraf.sync(dir);
return merge([
createMainBundle(defines).pipe(gulp.dest(dir + "build")),
createWorkerBundle(defines).pipe(gulp.dest(dir + "build")),
createWebBundle(defines).pipe(gulp.dest(dir + "web")),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's on purpose.
The idea is to get a bundle from initialization.js and the convert the bundle content into a string and inject this string in the sandbox bundle. This string will be eval-ed in the sandbox in order to create all what we need for the JS api.
But of course, if you see a better way to do, please tell me.

const defines = builder.merge(DEFINES, { GENERIC: true });
buildSandbox(defines, GENERIC_DIR);
done();
});

gulp.task("watch-sandbox", function (done) {
const defines = builder.merge(DEFINES, { GENERIC: true });
buildSandbox(defines, GENERIC_DIR);
const watcher = gulp.watch([
"src/scripting_api/*.js",
"external/quickjs/*.js",
]);
watcher.on("change", function () {
buildSandbox(defines, GENERIC_DIR);
});
done();
});

gulp.task("default", function (done) {
console.log("Available tasks:");
var tasks = Object.keys(gulp.registry().tasks());
Expand Down Expand Up @@ -762,26 +831,47 @@ function buildGeneric(defines, dir) {
// HTML5 browsers, which implement modern ECMAScript features.
gulp.task(
"generic",
gulp.series("buildnumber", "default_preferences", "locale", function () {
console.log();
console.log("### Creating generic viewer");
var defines = builder.merge(DEFINES, { GENERIC: true });
gulp.series(
"buildnumber",
"default_preferences",
"locale",
function () {
console.log();
console.log("### Creating generic viewer");
var defines = builder.merge(DEFINES, { GENERIC: true });

return buildGeneric(defines, GENERIC_DIR);
})
return buildGeneric(defines, GENERIC_DIR);
},
"sandbox"
)
);

// Builds the generic production viewer that should be compatible with most
// older HTML5 browsers.
gulp.task(
"generic-es5",
gulp.series("buildnumber", "default_preferences", "locale", function () {
console.log();
console.log("### Creating generic (ES5) viewer");
var defines = builder.merge(DEFINES, { GENERIC: true, SKIP_BABEL: false });
gulp.series(
"buildnumber",
"default_preferences",
"locale",
function () {
console.log();
console.log("### Creating generic (ES5) viewer");
var defines = builder.merge(DEFINES, {
GENERIC: true,
SKIP_BABEL: false,
});

return buildGeneric(defines, GENERIC_ES5_DIR);
})
return buildGeneric(defines, GENERIC_ES5_DIR);
},
function () {
const defines = builder.merge(DEFINES, {
GENERIC: true,
SKIP_BABEL: false,
});
return buildSandbox(defines, GENERIC_ES5_DIR);
}
)
);

function buildComponents(defines, dir) {
Expand Down Expand Up @@ -908,33 +998,61 @@ function buildMinified(defines, dir) {

gulp.task(
"minified-pre",
gulp.series("buildnumber", "default_preferences", "locale", function () {
console.log();
console.log("### Creating minified viewer");
var defines = builder.merge(DEFINES, { MINIFIED: true, GENERIC: true });
gulp.series(
"buildnumber",
"default_preferences",
"locale",
function () {
console.log();
console.log("### Creating minified viewer");
var defines = builder.merge(DEFINES, { MINIFIED: true, GENERIC: true });

return buildMinified(defines, MINIFIED_DIR);
})
return buildSandbox(defines, MINIFIED_DIR);
},
function () {
var defines = builder.merge(DEFINES, { MINIFIED: true, GENERIC: true });

return buildMinified(defines, MINIFIED_DIR);
}
)
);

gulp.task(
"minified-es5-pre",
gulp.series("buildnumber", "default_preferences", "locale", function () {
console.log();
console.log("### Creating minified (ES5) viewer");
var defines = builder.merge(DEFINES, {
MINIFIED: true,
GENERIC: true,
SKIP_BABEL: false,
});
gulp.series(
"buildnumber",
"default_preferences",
"locale",
function () {
console.log();
console.log("### Creating minified (ES5) viewer");
var defines = builder.merge(DEFINES, {
MINIFIED: true,
GENERIC: true,
SKIP_BABEL: false,
});

return buildMinified(defines, MINIFIED_ES5_DIR);
})
return buildSandbox(defines, MINIFIED_ES5_DIR);
},

function () {
var defines = builder.merge(DEFINES, {
MINIFIED: true,
GENERIC: true,
SKIP_BABEL: false,
});

return buildMinified(defines, MINIFIED_ES5_DIR);
}
)
);

async function parseMinified(dir) {
var pdfFile = fs.readFileSync(dir + "/build/pdf.js").toString();
var pdfWorkerFile = fs.readFileSync(dir + "/build/pdf.worker.js").toString();
var pdfSandboxFile = fs
.readFileSync(dir + "/build/pdf.sandbox.js")
.toString();
var pdfImageDecodersFile = fs
.readFileSync(dir + "/image_decoders/pdf.image_decoders.js")
.toString();
Expand Down Expand Up @@ -968,6 +1086,10 @@ async function parseMinified(dir) {
dir + "/build/pdf.worker.min.js",
(await Terser.minify(pdfWorkerFile, options)).code
);
fs.writeFileSync(
dir + "/build/pdf.sandbox.min.js",
(await Terser.minify(pdfSandboxFile, options)).code
);
fs.writeFileSync(
dir + "image_decoders/pdf.image_decoders.min.js",
(await Terser.minify(pdfImageDecodersFile, options)).code
Expand All @@ -980,9 +1102,14 @@ async function parseMinified(dir) {
fs.unlinkSync(dir + "/web/debugger.js");
fs.unlinkSync(dir + "/build/pdf.js");
fs.unlinkSync(dir + "/build/pdf.worker.js");
fs.unlinkSync(dir + "/build/pdf.sandbox.js");

fs.renameSync(dir + "/build/pdf.min.js", dir + "/build/pdf.js");
fs.renameSync(dir + "/build/pdf.worker.min.js", dir + "/build/pdf.worker.js");
fs.renameSync(
dir + "/build/pdf.sandbox.min.js",
dir + "/build/pdf.sandbox.js"
);
fs.renameSync(
dir + "/image_decoders/pdf.image_decoders.min.js",
dir + "/image_decoders/pdf.image_decoders.js"
Expand Down Expand Up @@ -1176,7 +1303,14 @@ gulp.task(
})
);

gulp.task("chromium", gulp.series("chromium-pre"));
gulp.task(
"chromium",
gulp.series("chromium-pre", function () {
var defines = builder.merge(DEFINES, { CHROME: true, SKIP_BABEL: false });
var CHROME_BUILD_CONTENT_DIR = BUILD_DIR + "/chromium/content/";
return buildSandbox(defines, CHROME_BUILD_CONTENT_DIR);
})
);

gulp.task("jsdoc", function (done) {
console.log();
Expand Down Expand Up @@ -1276,7 +1410,7 @@ function buildLib(defines, dir) {
return merge([
gulp.src(
[
"src/{core,display,scripting_api,shared}/*.js",
"src/{core,display,shared}/*.js",
"!src/shared/{cffStandardStrings,fonts_utils}.js",
"src/{pdf,pdf.worker}.js",
],
Expand All @@ -1294,24 +1428,46 @@ function buildLib(defines, dir) {

gulp.task(
"lib",
gulp.series("buildnumber", "default_preferences", function () {
var defines = builder.merge(DEFINES, { GENERIC: true, LIB: true });
gulp.series(
"buildnumber",
"default_preferences",
function () {
var defines = builder.merge(DEFINES, { GENERIC: true, LIB: true });

return buildLib(defines, "build/lib/");
})
return buildLib(defines, "build/lib/");
},
function () {
var defines = builder.merge(DEFINES, { GENERIC: true, LIB: true });

return buildSandbox(defines, "build/lib/");
}
)
);

gulp.task(
"lib-es5",
gulp.series("buildnumber", "default_preferences", function () {
var defines = builder.merge(DEFINES, {
GENERIC: true,
LIB: true,
SKIP_BABEL: false,
});
gulp.series(
"buildnumber",
"default_preferences",
function () {
var defines = builder.merge(DEFINES, {
GENERIC: true,
LIB: true,
SKIP_BABEL: false,
});

return buildLib(defines, "build/lib-es5/");
})
return buildLib(defines, "build/lib-es5/");
},
function () {
var defines = builder.merge(DEFINES, {
GENERIC: true,
LIB: true,
SKIP_BABEL: false,
});

return buildSandbox(defines, "build/lib-es5/");
}
)
);

function compressPublish(targetName, dir) {
Expand Down Expand Up @@ -1382,6 +1538,7 @@ gulp.task(
gulp.task(
"unittest",
gulp.series("testing-pre", "generic", "components", function () {
process.env.TZ = "UTC";
return createTestSource("unit");
})
);
Expand Down
Loading