Merge pull request #12689 from calixteman/mv_stuff_from_mc
In order to simplify m-c code, move some in pdf.js
This commit is contained in:
commit
c366390f6b
50
external/quickjs/quickjs-eval.js
vendored
50
external/quickjs/quickjs-eval.js
vendored
File diff suppressed because one or more lines are too long
28
gulpfile.js
28
gulpfile.js
@ -374,7 +374,28 @@ function createScriptingBundle(defines, extraOptions = undefined) {
|
|||||||
.src("./src/pdf.scripting.js")
|
.src("./src/pdf.scripting.js")
|
||||||
.pipe(webpack2Stream(scriptingFileConfig))
|
.pipe(webpack2Stream(scriptingFileConfig))
|
||||||
.pipe(replaceWebpackRequire())
|
.pipe(replaceWebpackRequire())
|
||||||
.pipe(replaceJSRootName(scriptingAMDName, "pdfjsScripting"));
|
.pipe(
|
||||||
|
replace(
|
||||||
|
'root["' + scriptingAMDName + '"] = factory()',
|
||||||
|
"root.pdfjsScripting = factory()"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSandboxExternal(defines) {
|
||||||
|
const preprocessor2 = require("./external/builder/preprocessor2.js");
|
||||||
|
const licenseHeader = fs.readFileSync("./src/license_header.js").toString();
|
||||||
|
|
||||||
|
const ctx = {
|
||||||
|
saveComments: false,
|
||||||
|
defines,
|
||||||
|
};
|
||||||
|
return gulp.src("./src/pdf.sandbox.external.js").pipe(
|
||||||
|
transform("utf8", content => {
|
||||||
|
content = preprocessor2.preprocessPDFJSCode(ctx, content);
|
||||||
|
return `${licenseHeader}\n${content}`;
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTemporaryScriptingBundle(defines, extraOptions = undefined) {
|
function createTemporaryScriptingBundle(defines, extraOptions = undefined) {
|
||||||
@ -1203,6 +1224,9 @@ gulp.task(
|
|||||||
createScriptingBundle(defines).pipe(
|
createScriptingBundle(defines).pipe(
|
||||||
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
|
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
|
||||||
),
|
),
|
||||||
|
createSandboxExternal(defines).pipe(
|
||||||
|
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
|
||||||
|
),
|
||||||
createWorkerBundle(defines).pipe(
|
createWorkerBundle(defines).pipe(
|
||||||
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
|
gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")
|
||||||
),
|
),
|
||||||
@ -1791,7 +1815,7 @@ gulp.task(
|
|||||||
gulp.task("watch-dev-sandbox", function () {
|
gulp.task("watch-dev-sandbox", function () {
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
[
|
[
|
||||||
"src/pdf.{sandbox,scripting}.js",
|
"src/pdf.{sandbox,sandbox.external,scripting}.js",
|
||||||
"src/scripting_api/*.js",
|
"src/scripting_api/*.js",
|
||||||
"src/shared/scripting_utils.js",
|
"src/shared/scripting_utils.js",
|
||||||
"external/quickjs/*.js",
|
"external/quickjs/*.js",
|
||||||
|
175
src/pdf.sandbox.external.js
Normal file
175
src/pdf.sandbox.external.js
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/* Copyright 2020 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// In mozilla-central, this file is loaded as non-module script,
|
||||||
|
// so it mustn't have any dependencies.
|
||||||
|
|
||||||
|
class SandboxSupportBase {
|
||||||
|
/**
|
||||||
|
* @param {DOMWindow} - win
|
||||||
|
*/
|
||||||
|
constructor(win) {
|
||||||
|
this.win = win;
|
||||||
|
this.timeoutIds = new Map();
|
||||||
|
|
||||||
|
// Will be assigned after the sandbox is initialized
|
||||||
|
this.commFun = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.commFunc = null;
|
||||||
|
this.timeoutIds.forEach(([_, id]) => this.win.clearTimeout(id));
|
||||||
|
this.timeoutIds = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} val - Export a value in the sandbox.
|
||||||
|
*/
|
||||||
|
exportValueToSandbox(val) {
|
||||||
|
throw new Error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} val - Import a value from the sandbox.
|
||||||
|
*/
|
||||||
|
importValueFromSandbox(val) {
|
||||||
|
throw new Error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} errorMessage - Create an error in the sandbox.
|
||||||
|
*/
|
||||||
|
createErrorForSandbox(errorMessage) {
|
||||||
|
throw new Error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} name - Name of the function to call in the sandbox
|
||||||
|
* @param {Array<Object>} args - Arguments of the function.
|
||||||
|
*/
|
||||||
|
callSandboxFunction(name, args) {
|
||||||
|
try {
|
||||||
|
args = this.exportValueToSandbox(args);
|
||||||
|
this.commFun(name, args);
|
||||||
|
} catch (e) {
|
||||||
|
this.win.console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createSandboxExternals() {
|
||||||
|
// All the functions in externals object are called
|
||||||
|
// from the sandbox.
|
||||||
|
const externals = {
|
||||||
|
setTimeout: (callbackId, nMilliseconds) => {
|
||||||
|
if (
|
||||||
|
typeof callbackId !== "number" ||
|
||||||
|
typeof nMilliseconds !== "number"
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = this.win.setTimeout(() => {
|
||||||
|
this.timeoutIds.delete(callbackId);
|
||||||
|
this.callSandboxFunction("timeoutCb", {
|
||||||
|
callbackId,
|
||||||
|
interval: false,
|
||||||
|
});
|
||||||
|
}, nMilliseconds);
|
||||||
|
this.timeoutIds.set(callbackId, id);
|
||||||
|
},
|
||||||
|
clearTimeout: id => {
|
||||||
|
this.win.clearTimeout(this.timeoutIds.get(id));
|
||||||
|
this.timeoutIds.delete(id);
|
||||||
|
},
|
||||||
|
setInterval: (callbackId, nMilliseconds) => {
|
||||||
|
if (
|
||||||
|
typeof callbackId !== "number" ||
|
||||||
|
typeof nMilliseconds !== "number"
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = this.win.setInterval(() => {
|
||||||
|
this.callSandboxFunction("timeoutCb", {
|
||||||
|
callbackId,
|
||||||
|
interval: true,
|
||||||
|
});
|
||||||
|
}, nMilliseconds);
|
||||||
|
this.timeoutIds.set(callbackId, id);
|
||||||
|
},
|
||||||
|
clearInterval: id => {
|
||||||
|
this.win.clearInterval(this.timeoutIds.get(id));
|
||||||
|
this.timeoutIds.delete(id);
|
||||||
|
},
|
||||||
|
alert: cMsg => {
|
||||||
|
if (typeof cMsg !== "string") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.win.alert(cMsg);
|
||||||
|
},
|
||||||
|
prompt: (cQuestion, cDefault) => {
|
||||||
|
if (typeof cQuestion !== "string" || typeof cDefault !== "string") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.win.prompt(cQuestion, cDefault);
|
||||||
|
},
|
||||||
|
parseURL: cUrl => {
|
||||||
|
const url = new this.win.URL(cUrl);
|
||||||
|
const props = [
|
||||||
|
"hash",
|
||||||
|
"host",
|
||||||
|
"hostname",
|
||||||
|
"href",
|
||||||
|
"origin",
|
||||||
|
"password",
|
||||||
|
"pathname",
|
||||||
|
"port",
|
||||||
|
"protocol",
|
||||||
|
"search",
|
||||||
|
"searchParams",
|
||||||
|
"username",
|
||||||
|
];
|
||||||
|
|
||||||
|
return Object.fromEntries(
|
||||||
|
props.map(name => [name, url[name].toString()])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
send: data => {
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const event = new this.win.CustomEvent("updateFromSandbox", {
|
||||||
|
detail: this.importValueFromSandbox(data),
|
||||||
|
});
|
||||||
|
this.win.dispatchEvent(event);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Object.setPrototypeOf(externals, null);
|
||||||
|
|
||||||
|
return (name, args) => {
|
||||||
|
try {
|
||||||
|
const result = externals[name](...args);
|
||||||
|
return this.exportValueToSandbox(result);
|
||||||
|
} catch (error) {
|
||||||
|
throw this.createErrorForSandbox(error?.toString() ?? "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
|
||||||
|
exports.SandboxSupportBase = SandboxSupportBase;
|
||||||
|
} else {
|
||||||
|
/* eslint-disable-next-line no-unused-vars, no-var */
|
||||||
|
var EXPORTED_SYMBOLS = ["SandboxSupportBase"];
|
||||||
|
}
|
@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import ModuleLoader from "../external/quickjs/quickjs-eval.js";
|
import ModuleLoader from "../external/quickjs/quickjs-eval.js";
|
||||||
|
import { SandboxSupportBase } from "./pdf.sandbox.external.js";
|
||||||
|
|
||||||
/* eslint-disable-next-line no-unused-vars */
|
/* eslint-disable-next-line no-unused-vars */
|
||||||
const pdfjsVersion = PDFJSDev.eval("BUNDLE_VERSION");
|
const pdfjsVersion = PDFJSDev.eval("BUNDLE_VERSION");
|
||||||
@ -23,79 +24,111 @@ const pdfjsBuild = PDFJSDev.eval("BUNDLE_BUILD");
|
|||||||
const TESTING =
|
const TESTING =
|
||||||
typeof PDFJSDev === "undefined" || PDFJSDev.test("!PRODUCTION || TESTING");
|
typeof PDFJSDev === "undefined" || PDFJSDev.test("!PRODUCTION || TESTING");
|
||||||
|
|
||||||
|
class SandboxSupport extends SandboxSupportBase {
|
||||||
|
exportValueToSandbox(val) {
|
||||||
|
// The communication with the Quickjs sandbox is based on strings
|
||||||
|
// So we use JSON.stringfy to serialize
|
||||||
|
return JSON.stringify(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
importValueFromSandbox(val) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
createErrorForSandbox(errorMessage) {
|
||||||
|
return new Error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Sandbox {
|
class Sandbox {
|
||||||
constructor(module) {
|
constructor(win, module) {
|
||||||
this._evalInSandbox = module.cwrap("evalInSandbox", null, [
|
this.support = new SandboxSupport(win, this);
|
||||||
"string",
|
|
||||||
"int",
|
// The "external" functions created in pdf.sandbox.external.js
|
||||||
]);
|
// are finally used here:
|
||||||
this._dispatchEventName = null;
|
// https://github.com/mozilla/pdf.js.quickjs/blob/main/src/myjs.js
|
||||||
|
// They're called from the sandbox only.
|
||||||
|
module.externalCall = this.support.createSandboxExternals();
|
||||||
|
|
||||||
this._module = module;
|
this._module = module;
|
||||||
this._alertOnError = 1;
|
|
||||||
|
// 0 to display error using console.error
|
||||||
|
// else display error using window.alert
|
||||||
|
this._alertOnError = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
create(data) {
|
create(data) {
|
||||||
const sandboxData = JSON.stringify(data);
|
const sandboxData = JSON.stringify(data);
|
||||||
const extra = [
|
const code = [
|
||||||
"send",
|
|
||||||
"setTimeout",
|
|
||||||
"clearTimeout",
|
|
||||||
"setInterval",
|
|
||||||
"clearInterval",
|
|
||||||
"crackURL",
|
|
||||||
];
|
|
||||||
const extraStr = extra.join(",");
|
|
||||||
let code = [
|
|
||||||
"exports = Object.create(null);",
|
|
||||||
"module = Object.create(null);",
|
|
||||||
// Next line is replaced by code from initialization.js
|
// Next line is replaced by code from initialization.js
|
||||||
// when we create the bundle for the sandbox.
|
// when we create the bundle for the sandbox.
|
||||||
PDFJSDev.eval("PDF_SCRIPTING_JS_SOURCE"),
|
PDFJSDev.eval("PDF_SCRIPTING_JS_SOURCE"),
|
||||||
`data = ${sandboxData};`,
|
`pdfjsScripting.initSandbox({ data: ${sandboxData} })`,
|
||||||
`module.exports.initSandbox({ data, extra: {${extraStr}}, out: this});`,
|
|
||||||
"delete exports;",
|
|
||||||
"delete module;",
|
|
||||||
"delete data;",
|
|
||||||
];
|
];
|
||||||
if (!TESTING) {
|
if (!TESTING) {
|
||||||
code = code.concat(extra.map(name => `delete ${name};`));
|
code.push("delete dump;");
|
||||||
code.push("delete debugMe;");
|
} else {
|
||||||
|
code.unshift(
|
||||||
|
`globalThis.sendResultForTesting = callExternalFunction.bind(null, "send");`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let success = false;
|
||||||
|
try {
|
||||||
|
success = !!this._module.ccall(
|
||||||
|
"init",
|
||||||
|
"number",
|
||||||
|
["string", "number"],
|
||||||
|
[code.join("\n"), this._alertOnError]
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
this.support.commFun = this._module.cwrap("commFun", null, [
|
||||||
|
"string",
|
||||||
|
"string",
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
this.nukeSandbox();
|
||||||
|
throw new Error("Cannot start sandbox");
|
||||||
}
|
}
|
||||||
this._evalInSandbox(code.join("\n"), this._alertOnError);
|
|
||||||
this._dispatchEventName = data.dispatchEventName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchEvent(event) {
|
dispatchEvent(event) {
|
||||||
if (this._dispatchEventName === null) {
|
this.support.callSandboxFunction("dispatchEvent", event);
|
||||||
throw new Error("Sandbox must have been initialized");
|
|
||||||
}
|
|
||||||
event = JSON.stringify(event);
|
|
||||||
this._evalInSandbox(
|
|
||||||
`app["${this._dispatchEventName}"](${event});`,
|
|
||||||
this._alertOnError
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dumpMemoryUse() {
|
dumpMemoryUse() {
|
||||||
this._module.ccall("dumpMemoryUse", null, []);
|
if (this._module) {
|
||||||
|
this._module.ccall("dumpMemoryUse", null, []);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nukeSandbox() {
|
nukeSandbox() {
|
||||||
this._dispatchEventName = null;
|
if (this._module !== null) {
|
||||||
this._module.ccall("nukeSandbox", null, []);
|
this.support.destroy();
|
||||||
this._module = null;
|
this.support = null;
|
||||||
this._evalInSandbox = null;
|
this._module.ccall("nukeSandbox", null, []);
|
||||||
|
this._module = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
evalForTesting(code, key) {
|
evalForTesting(code, key) {
|
||||||
if (TESTING) {
|
if (TESTING) {
|
||||||
this._evalInSandbox(
|
this._module.ccall(
|
||||||
`try {
|
"evalInSandbox",
|
||||||
send({ id: "${key}", result: ${code} });
|
null,
|
||||||
} catch (error) {
|
["string", "int"],
|
||||||
send({ id: "${key}", result: error.message });
|
[
|
||||||
}`,
|
`try {
|
||||||
this._alertOnError
|
sendResultForTesting([{ id: "${key}", result: ${code} }]);
|
||||||
|
} catch (error) {
|
||||||
|
sendResultForTesting([{ id: "${key}", result: error.message }]);
|
||||||
|
}`,
|
||||||
|
this._alertOnError,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +136,7 @@ class Sandbox {
|
|||||||
|
|
||||||
function QuickJSSandbox() {
|
function QuickJSSandbox() {
|
||||||
return ModuleLoader().then(module => {
|
return ModuleLoader().then(module => {
|
||||||
return new Sandbox(module);
|
return new Sandbox(window, module);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,15 +49,28 @@ class App extends PDFObject {
|
|||||||
data.calculationOrder,
|
data.calculationOrder,
|
||||||
this._objects
|
this._objects
|
||||||
);
|
);
|
||||||
this._setTimeout = data.setTimeout;
|
|
||||||
this._clearTimeout = data.clearTimeout;
|
|
||||||
this._setInterval = data.setInterval;
|
|
||||||
this._clearInterval = data.clearInterval;
|
|
||||||
this._timeoutIds = null;
|
|
||||||
this._timeoutIdsRegistry = null;
|
|
||||||
|
|
||||||
// used in proxy.js to check that this is the object with the backdoor
|
this._timeoutIds = new WeakMap();
|
||||||
this._isApp = true;
|
// eslint-disable-next-line no-undef
|
||||||
|
if (typeof FinalizationRegistry !== "undefined") {
|
||||||
|
// About setTimeOut/setInterval return values (specs):
|
||||||
|
// The return value of this method must be held in a
|
||||||
|
// JavaScript variable.
|
||||||
|
// Otherwise, the timeout object is subject to garbage-collection,
|
||||||
|
// which would cause the clock to stop.
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
this._timeoutIdsRegistry = new FinalizationRegistry(
|
||||||
|
this._cleanTimeout.bind(this)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this._timeoutIdsRegistry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._timeoutCallbackIds = new Map();
|
||||||
|
this._timeoutCallbackId = 0;
|
||||||
|
this._globalEval = data.globalEval;
|
||||||
|
this._externalCall = data.externalCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is called thanks to the proxy
|
// This function is called thanks to the proxy
|
||||||
@ -66,50 +79,58 @@ class App extends PDFObject {
|
|||||||
this._eventDispatcher.dispatch(pdfEvent);
|
this._eventDispatcher.dispatch(pdfEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_registerTimeout(timeout, id, interval) {
|
_registerTimeoutCallback(cExpr) {
|
||||||
if (!this._timeoutIds) {
|
const id = this._timeoutCallbackId++;
|
||||||
this._timeoutIds = new WeakMap();
|
this._timeoutCallbackIds.set(id, cExpr);
|
||||||
// FinalizationRegistry isn't implemented in QuickJS
|
return id;
|
||||||
// eslint-disable-next-line no-undef
|
}
|
||||||
if (typeof FinalizationRegistry !== "undefined") {
|
|
||||||
// About setTimeOut/setInterval return values (specs):
|
|
||||||
// The return value of this method must be held in a
|
|
||||||
// JavaScript variable.
|
|
||||||
// Otherwise, the timeout object is subject to garbage-collection,
|
|
||||||
// which would cause the clock to stop.
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
_unregisterTimeoutCallback(id) {
|
||||||
this._timeoutIdsRegistry = new FinalizationRegistry(
|
this._timeoutCallbackIds.delete(id);
|
||||||
([timeoutId, isInterval]) => {
|
}
|
||||||
if (isInterval) {
|
|
||||||
this._clearInterval(timeoutId);
|
_evalCallback({ callbackId, interval }) {
|
||||||
} else {
|
const expr = this._timeoutCallbackIds.get(callbackId);
|
||||||
this._clearTimeout(timeoutId);
|
if (!interval) {
|
||||||
}
|
this._unregisterTimeoutCallback(callbackId);
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this._timeoutIds.set(timeout, [id, interval]);
|
|
||||||
if (this._timeoutIdsRegistry) {
|
if (expr) {
|
||||||
this._timeoutIdsRegistry.register(timeout, [id, interval]);
|
this._globalEval(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unregisterTimeout(timeout) {
|
_registerTimeout(callbackId, interval) {
|
||||||
if (!this._timeoutIds || !this._timeoutIds.has(timeout)) {
|
const timeout = Object.create(null);
|
||||||
return;
|
const id = { callbackId, interval };
|
||||||
|
this._timeoutIds.set(timeout, id);
|
||||||
|
if (this._timeoutIdsRegistry) {
|
||||||
|
this._timeoutIdsRegistry.register(timeout, id);
|
||||||
}
|
}
|
||||||
const [id, interval] = this._timeoutIds.get(timeout);
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
_unregisterTimeout(timeout) {
|
||||||
if (this._timeoutIdsRegistry) {
|
if (this._timeoutIdsRegistry) {
|
||||||
this._timeoutIdsRegistry.unregister(timeout);
|
this._timeoutIdsRegistry.unregister(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const data = this._timeoutIds.get(timeout);
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._timeoutIds.delete(timeout);
|
this._timeoutIds.delete(timeout);
|
||||||
|
this._cleanTimeout(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanTimeout({ callbackId, interval }) {
|
||||||
|
this._unregisterTimeoutCallback(callbackId);
|
||||||
|
|
||||||
if (interval) {
|
if (interval) {
|
||||||
this._clearInterval(id);
|
this._externalCall("clearInterval", [callbackId]);
|
||||||
} else {
|
} else {
|
||||||
this._clearTimeout(id);
|
this._externalCall("clearTimeout", [callbackId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,7 +430,7 @@ class App extends PDFObject {
|
|||||||
oDoc = null,
|
oDoc = null,
|
||||||
oCheckbox = null
|
oCheckbox = null
|
||||||
) {
|
) {
|
||||||
this._send({ command: "alert", value: cMsg });
|
this._externalCall("alert", [cMsg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
beep() {
|
beep() {
|
||||||
@ -425,11 +446,11 @@ class App extends PDFObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearInterval(oInterval) {
|
clearInterval(oInterval) {
|
||||||
this.unregisterTimeout(oInterval);
|
this._unregisterTimeout(oInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearTimeOut(oTime) {
|
clearTimeOut(oTime) {
|
||||||
this.unregisterTimeout(oTime);
|
this._unregisterTimeout(oTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
endPriv() {
|
endPriv() {
|
||||||
@ -524,8 +545,8 @@ class App extends PDFObject {
|
|||||||
/* Not implemented */
|
/* Not implemented */
|
||||||
}
|
}
|
||||||
|
|
||||||
response() {
|
response(cQuestion, cTitle = "", cDefault = "", bPassword = "", cLabel = "") {
|
||||||
/* TODO or not */
|
return this._externalCall("prompt", [cQuestion, cDefault || ""]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(cExpr, nMilliseconds) {
|
setInterval(cExpr, nMilliseconds) {
|
||||||
@ -537,11 +558,9 @@ class App extends PDFObject {
|
|||||||
"Second argument of app.setInterval must be a number"
|
"Second argument of app.setInterval must be a number"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const callbackId = this._registerTimeoutCallback(cExpr);
|
||||||
const id = this._setInterval(cExpr, nMilliseconds);
|
this._externalCall("setInterval", [callbackId, nMilliseconds]);
|
||||||
const timeout = Object.create(null);
|
return this._registerTimeout(callbackId, true);
|
||||||
this._registerTimeout(timeout, id, true);
|
|
||||||
return timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeOut(cExpr, nMilliseconds) {
|
setTimeOut(cExpr, nMilliseconds) {
|
||||||
@ -551,11 +570,9 @@ class App extends PDFObject {
|
|||||||
if (typeof nMilliseconds !== "number") {
|
if (typeof nMilliseconds !== "number") {
|
||||||
throw new TypeError("Second argument of app.setTimeOut must be a number");
|
throw new TypeError("Second argument of app.setTimeOut must be a number");
|
||||||
}
|
}
|
||||||
|
const callbackId = this._registerTimeoutCallback(cExpr);
|
||||||
const id = this._setTimeout(cExpr, nMilliseconds);
|
this._externalCall("setTimeout", [callbackId, nMilliseconds]);
|
||||||
const timeout = Object.create(null);
|
return this._registerTimeout(callbackId, false);
|
||||||
this._registerTimeout(timeout, id, false);
|
|
||||||
return timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trustedFunction() {
|
trustedFunction() {
|
||||||
|
@ -30,7 +30,6 @@ class InfoProxyHandler {
|
|||||||
class Doc extends PDFObject {
|
class Doc extends PDFObject {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
super(data);
|
super(data);
|
||||||
this.calculate = true;
|
|
||||||
|
|
||||||
this.baseURL = data.baseURL || "";
|
this.baseURL = data.baseURL || "";
|
||||||
this.calculate = true;
|
this.calculate = true;
|
||||||
|
@ -180,11 +180,7 @@ class Field extends PDFObject {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.rc = false;
|
event.rc = false;
|
||||||
const value =
|
throw error;
|
||||||
`"${error.toString()}" for event ` +
|
|
||||||
`"${eventName}" in object ${this._id}.` +
|
|
||||||
`\n${error.stack}`;
|
|
||||||
this._send({ command: "error", value });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -35,16 +35,20 @@ import { Field } from "./field.js";
|
|||||||
import { ProxyHandler } from "./proxy.js";
|
import { ProxyHandler } from "./proxy.js";
|
||||||
import { Util } from "./util.js";
|
import { Util } from "./util.js";
|
||||||
|
|
||||||
function initSandbox({ data, extra, out }) {
|
function initSandbox(params) {
|
||||||
const proxyHandler = new ProxyHandler(data.dispatchEventName);
|
delete globalThis.pdfjsScripting;
|
||||||
const {
|
|
||||||
send,
|
// externalCall is a function to call a function defined
|
||||||
crackURL,
|
// outside the sandbox.
|
||||||
setTimeout,
|
// (see src/pdf.sandbox.external.js).
|
||||||
clearTimeout,
|
const externalCall = globalThis.callExternalFunction;
|
||||||
setInterval,
|
delete globalThis.callExternalFunction;
|
||||||
clearInterval,
|
|
||||||
} = extra;
|
// eslint-disable-next-line no-eval
|
||||||
|
const globalEval = code => globalThis.eval(code);
|
||||||
|
const send = data => externalCall("send", [data]);
|
||||||
|
const proxyHandler = new ProxyHandler();
|
||||||
|
const { data } = params;
|
||||||
const doc = new Doc({
|
const doc = new Doc({
|
||||||
send,
|
send,
|
||||||
...data.docInfo,
|
...data.docInfo,
|
||||||
@ -52,21 +56,21 @@ function initSandbox({ data, extra, out }) {
|
|||||||
const _document = { obj: doc, wrapped: new Proxy(doc, proxyHandler) };
|
const _document = { obj: doc, wrapped: new Proxy(doc, proxyHandler) };
|
||||||
const app = new App({
|
const app = new App({
|
||||||
send,
|
send,
|
||||||
setTimeout,
|
globalEval,
|
||||||
clearTimeout,
|
externalCall,
|
||||||
setInterval,
|
|
||||||
clearInterval,
|
|
||||||
_document,
|
_document,
|
||||||
calculationOrder: data.calculationOrder,
|
calculationOrder: data.calculationOrder,
|
||||||
proxyHandler,
|
proxyHandler,
|
||||||
...data.appInfo,
|
...data.appInfo,
|
||||||
});
|
});
|
||||||
const util = new Util({ crackURL });
|
|
||||||
|
const util = new Util({ externalCall });
|
||||||
const aform = new AForm(doc, app, util);
|
const aform = new AForm(doc, app, util);
|
||||||
|
|
||||||
for (const [name, objs] of Object.entries(data.objects)) {
|
for (const [name, objs] of Object.entries(data.objects)) {
|
||||||
const obj = objs[0];
|
const obj = objs[0];
|
||||||
obj.send = send;
|
obj.send = send;
|
||||||
|
obj.globalEval = globalEval;
|
||||||
obj.doc = _document.wrapped;
|
obj.doc = _document.wrapped;
|
||||||
const field = new Field(obj);
|
const field = new Field(obj);
|
||||||
const wrapped = new Proxy(field, proxyHandler);
|
const wrapped = new Proxy(field, proxyHandler);
|
||||||
@ -74,28 +78,44 @@ function initSandbox({ data, extra, out }) {
|
|||||||
app._objects[obj.id] = { obj: field, wrapped };
|
app._objects[obj.id] = { obj: field, wrapped };
|
||||||
}
|
}
|
||||||
|
|
||||||
out.global = Object.create(null);
|
globalThis.event = null;
|
||||||
out.app = new Proxy(app, proxyHandler);
|
globalThis.global = Object.create(null);
|
||||||
out.color = new Proxy(new Color(), proxyHandler);
|
globalThis.app = new Proxy(app, proxyHandler);
|
||||||
out.console = new Proxy(new Console({ send }), proxyHandler);
|
globalThis.doc = _document.wrapped;
|
||||||
out.util = new Proxy(util, proxyHandler);
|
globalThis.color = new Proxy(new Color(), proxyHandler);
|
||||||
out.border = Border;
|
globalThis.console = new Proxy(new Console({ send }), proxyHandler);
|
||||||
out.cursor = Cursor;
|
globalThis.util = new Proxy(util, proxyHandler);
|
||||||
out.display = Display;
|
globalThis.border = Border;
|
||||||
out.font = Font;
|
globalThis.cursor = Cursor;
|
||||||
out.highlight = Highlight;
|
globalThis.display = Display;
|
||||||
out.position = Position;
|
globalThis.font = Font;
|
||||||
out.scaleHow = ScaleHow;
|
globalThis.highlight = Highlight;
|
||||||
out.scaleWhen = ScaleWhen;
|
globalThis.position = Position;
|
||||||
out.style = Style;
|
globalThis.scaleHow = ScaleHow;
|
||||||
out.trans = Trans;
|
globalThis.scaleWhen = ScaleWhen;
|
||||||
out.zoomtype = ZoomType;
|
globalThis.style = Style;
|
||||||
|
globalThis.trans = Trans;
|
||||||
|
globalThis.zoomtype = ZoomType;
|
||||||
|
|
||||||
for (const name of Object.getOwnPropertyNames(AForm.prototype)) {
|
for (const name of Object.getOwnPropertyNames(AForm.prototype)) {
|
||||||
if (name !== "constructor" && !name.startsWith("_")) {
|
if (name !== "constructor" && !name.startsWith("_")) {
|
||||||
out[name] = aform[name].bind(aform);
|
globalThis[name] = aform[name].bind(aform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const functions = {
|
||||||
|
dispatchEvent: app._dispatchEvent.bind(app),
|
||||||
|
timeoutCb: app._evalCallback.bind(app),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (name, args) => {
|
||||||
|
try {
|
||||||
|
functions[name](args);
|
||||||
|
} catch (error) {
|
||||||
|
const value = `${error.toString()}\n${error.stack}`;
|
||||||
|
send({ command: "error", value });
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { initSandbox };
|
export { initSandbox };
|
||||||
|
@ -14,18 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class ProxyHandler {
|
class ProxyHandler {
|
||||||
constructor(dispatchEventName) {
|
|
||||||
this.dispatchEventName = dispatchEventName;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(obj, prop) {
|
get(obj, prop) {
|
||||||
if (obj._isApp && prop === this.dispatchEventName) {
|
|
||||||
// a backdoor to be able to call _dispatchEvent method
|
|
||||||
// the value of 'dispatchEvent' is generated randomly
|
|
||||||
// and injected in the code
|
|
||||||
return obj._dispatchEvent.bind(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// script may add some properties to the object
|
// script may add some properties to the object
|
||||||
if (prop in obj._expandos) {
|
if (prop in obj._expandos) {
|
||||||
const val = obj._expandos[prop];
|
const val = obj._expandos[prop];
|
||||||
|
@ -19,7 +19,6 @@ class Util extends PDFObject {
|
|||||||
constructor(data) {
|
constructor(data) {
|
||||||
super(data);
|
super(data);
|
||||||
|
|
||||||
this._crackURL = data.crackURL;
|
|
||||||
this._scandCache = new Map();
|
this._scandCache = new Map();
|
||||||
this._months = [
|
this._months = [
|
||||||
"January",
|
"January",
|
||||||
@ -46,13 +45,9 @@ class Util extends PDFObject {
|
|||||||
];
|
];
|
||||||
this.MILLISECONDS_IN_DAY = 86400000;
|
this.MILLISECONDS_IN_DAY = 86400000;
|
||||||
this.MILLISECONDS_IN_WEEK = 604800000;
|
this.MILLISECONDS_IN_WEEK = 604800000;
|
||||||
}
|
|
||||||
|
|
||||||
crackURL(cURL) {
|
// used with crackURL
|
||||||
if (typeof cURL !== "string") {
|
this._externalCall = data.externalCall;
|
||||||
throw new TypeError("First argument of util.crackURL must be a string");
|
|
||||||
}
|
|
||||||
return this._crackURL(cURL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(...args) {
|
printf(...args) {
|
||||||
|
@ -48,6 +48,10 @@ describe("Scripting", function () {
|
|||||||
send_queue.set(event.detail.id, event.detail);
|
send_queue.set(event.detail.id, event.detail);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
window.alert = value => {
|
||||||
|
const command = "alert";
|
||||||
|
send_queue.set(command, { command, value });
|
||||||
|
};
|
||||||
const promise = loadScript(sandboxBundleSrc).then(() => {
|
const promise = loadScript(sandboxBundleSrc).then(() => {
|
||||||
return window.pdfjsSandbox.QuickJSSandbox();
|
return window.pdfjsSandbox.QuickJSSandbox();
|
||||||
});
|
});
|
||||||
@ -104,7 +108,6 @@ describe("Scripting", function () {
|
|||||||
},
|
},
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
};
|
};
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
sandbox
|
sandbox
|
||||||
@ -132,7 +135,6 @@ describe("Scripting", function () {
|
|||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
objects: {},
|
objects: {},
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -263,7 +265,6 @@ describe("Scripting", function () {
|
|||||||
},
|
},
|
||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
};
|
};
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
sandbox
|
sandbox
|
||||||
@ -301,7 +302,6 @@ describe("Scripting", function () {
|
|||||||
},
|
},
|
||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
};
|
};
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
sandbox
|
sandbox
|
||||||
@ -343,7 +343,6 @@ describe("Scripting", function () {
|
|||||||
},
|
},
|
||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
};
|
};
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
sandbox
|
sandbox
|
||||||
@ -384,7 +383,6 @@ describe("Scripting", function () {
|
|||||||
},
|
},
|
||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
};
|
};
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
sandbox
|
sandbox
|
||||||
@ -429,7 +427,6 @@ describe("Scripting", function () {
|
|||||||
},
|
},
|
||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
calculationOrder: [refId2],
|
calculationOrder: [refId2],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
};
|
};
|
||||||
sandbox.createSandbox(data);
|
sandbox.createSandbox(data);
|
||||||
sandbox
|
sandbox
|
||||||
@ -458,7 +455,6 @@ describe("Scripting", function () {
|
|||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
objects: {},
|
objects: {},
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -553,7 +549,6 @@ describe("Scripting", function () {
|
|||||||
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
objects: {},
|
objects: {},
|
||||||
calculationOrder: [],
|
calculationOrder: [],
|
||||||
dispatchEventName: "_dispatchMe",
|
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
51
web/app.js
51
web/app.js
@ -19,7 +19,6 @@ import {
|
|||||||
AutoPrintRegExp,
|
AutoPrintRegExp,
|
||||||
DEFAULT_SCALE_VALUE,
|
DEFAULT_SCALE_VALUE,
|
||||||
EventBus,
|
EventBus,
|
||||||
generateRandomStringForSandbox,
|
|
||||||
getActiveOrFocusedElement,
|
getActiveOrFocusedElement,
|
||||||
getPDFFileNameFromURL,
|
getPDFFileNameFromURL,
|
||||||
isValidRotation,
|
isValidRotation,
|
||||||
@ -1483,10 +1482,6 @@ const PDFViewerApplication = {
|
|||||||
const { id, command, value } = detail;
|
const { id, command, value } = detail;
|
||||||
if (!id) {
|
if (!id) {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "alert":
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
window.alert(value);
|
|
||||||
break;
|
|
||||||
case "clear":
|
case "clear":
|
||||||
console.clear();
|
console.clear();
|
||||||
break;
|
break;
|
||||||
@ -1501,7 +1496,7 @@ const PDFViewerApplication = {
|
|||||||
return;
|
return;
|
||||||
case "print":
|
case "print":
|
||||||
this.triggerPrinting();
|
this.triggerPrinting();
|
||||||
return;
|
break;
|
||||||
case "println":
|
case "println":
|
||||||
console.log(value);
|
console.log(value);
|
||||||
break;
|
break;
|
||||||
@ -1511,7 +1506,7 @@ const PDFViewerApplication = {
|
|||||||
} else {
|
} else {
|
||||||
this.pdfViewer.currentScale = value;
|
this.pdfViewer.currentScale = value;
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1551,8 +1546,6 @@ const PDFViewerApplication = {
|
|||||||
window.addEventListener("mouseup", mouseUp);
|
window.addEventListener("mouseup", mouseUp);
|
||||||
this._scriptingInstance.events.set("mouseup", mouseUp);
|
this._scriptingInstance.events.set("mouseup", mouseUp);
|
||||||
|
|
||||||
const dispatchEventName = generateRandomStringForSandbox(objects);
|
|
||||||
|
|
||||||
if (!this._contentLength) {
|
if (!this._contentLength) {
|
||||||
// Always waiting for the entire PDF document to be loaded will, most
|
// Always waiting for the entire PDF document to be loaded will, most
|
||||||
// likely, delay sandbox-creation too much in the general case for all
|
// likely, delay sandbox-creation too much in the general case for all
|
||||||
@ -1569,24 +1562,28 @@ const PDFViewerApplication = {
|
|||||||
const filename =
|
const filename =
|
||||||
this._contentDispositionFilename || getPDFFileNameFromURL(this.url);
|
this._contentDispositionFilename || getPDFFileNameFromURL(this.url);
|
||||||
|
|
||||||
scripting.createSandbox({
|
try {
|
||||||
objects,
|
await scripting.createSandbox({
|
||||||
dispatchEventName,
|
objects,
|
||||||
calculationOrder,
|
calculationOrder,
|
||||||
appInfo: {
|
appInfo: {
|
||||||
platform: navigator.platform,
|
platform: navigator.platform,
|
||||||
language: navigator.language,
|
language: navigator.language,
|
||||||
},
|
},
|
||||||
docInfo: {
|
docInfo: {
|
||||||
...this.documentInfo,
|
...this.documentInfo,
|
||||||
baseURL: this.baseUrl,
|
baseURL: this.baseUrl,
|
||||||
filesize: this._contentLength,
|
filesize: this._contentLength,
|
||||||
filename,
|
filename,
|
||||||
metadata: this.metadata,
|
metadata: this.metadata,
|
||||||
numPages: pdfDocument.numPages,
|
numPages: pdfDocument.numPages,
|
||||||
URL: this.url,
|
URL: this.url,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
this._destroyScriptingInstance();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -256,15 +256,21 @@ class FirefoxComDataRangeTransport extends PDFDataRangeTransport {
|
|||||||
|
|
||||||
class FirefoxScripting {
|
class FirefoxScripting {
|
||||||
static createSandbox(data) {
|
static createSandbox(data) {
|
||||||
FirefoxCom.requestSync("createSandbox", data);
|
return new Promise(resolve => {
|
||||||
|
FirefoxCom.request("createSandbox", data, resolve);
|
||||||
|
}).then(success => {
|
||||||
|
if (!success) {
|
||||||
|
throw new Error("Cannot start sandbox");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static dispatchEventInSandbox(event) {
|
static async dispatchEventInSandbox(event) {
|
||||||
FirefoxCom.requestSync("dispatchEventInSandbox", event);
|
FirefoxCom.request("dispatchEventInSandbox", event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static destroySandbox() {
|
static async destroySandbox() {
|
||||||
FirefoxCom.requestSync("destroySandbox", null);
|
FirefoxCom.request("destroySandbox", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,42 +1015,6 @@ function getActiveOrFocusedElement() {
|
|||||||
return curActiveOrFocused;
|
return curActiveOrFocused;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a random string which is not define somewhere in actions.
|
|
||||||
*
|
|
||||||
* @param {Object} objects - The value returned by `getFieldObjects` in the API.
|
|
||||||
* @returns {string} A unique string.
|
|
||||||
*/
|
|
||||||
function generateRandomStringForSandbox(objects) {
|
|
||||||
const allObjects = Object.values(objects).flat(2);
|
|
||||||
const actions = allObjects
|
|
||||||
.filter(obj => !!obj.actions)
|
|
||||||
.map(obj => Object.values(obj.actions))
|
|
||||||
.flat(2);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const name = new Uint8Array(64);
|
|
||||||
if (typeof crypto !== "undefined") {
|
|
||||||
crypto.getRandomValues(name);
|
|
||||||
} else {
|
|
||||||
for (let i = 0, ii = name.length; i < ii; i++) {
|
|
||||||
name[i] = Math.floor(256 * Math.random());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const nameString =
|
|
||||||
"_" +
|
|
||||||
btoa(
|
|
||||||
Array.from(name)
|
|
||||||
.map(x => String.fromCharCode(x))
|
|
||||||
.join("")
|
|
||||||
);
|
|
||||||
if (actions.every(action => !action.includes(nameString))) {
|
|
||||||
return nameString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
AutoPrintRegExp,
|
AutoPrintRegExp,
|
||||||
CSS_UNITS,
|
CSS_UNITS,
|
||||||
@ -1074,7 +1038,6 @@ export {
|
|||||||
NullL10n,
|
NullL10n,
|
||||||
EventBus,
|
EventBus,
|
||||||
ProgressBar,
|
ProgressBar,
|
||||||
generateRandomStringForSandbox,
|
|
||||||
getPDFFileNameFromURL,
|
getPDFFileNameFromURL,
|
||||||
noContextMenuHandler,
|
noContextMenuHandler,
|
||||||
parseQueryString,
|
parseQueryString,
|
||||||
|
Loading…
Reference in New Issue
Block a user