diff --git a/noname/init/index.js b/noname/init/index.js index 6c39036d3..262d6c802 100644 --- a/noname/init/index.js +++ b/noname/init/index.js @@ -10,7 +10,7 @@ import * as config from "../util/config.js"; import { promiseErrorHandlerMap } from "../util/browser.js"; import { importCardPack, importCharacterPack, importExtension, importMode } from "./import.js"; import { onload } from "./onload.js"; -import security from "../util/security.js"; +import { initializeSandboxRealms } from "../util/initRealms.js"; // 判断是否从file协议切换到http/s协议 export function canUseHttpProtocol() { @@ -125,7 +125,12 @@ export async function boot() { // 加载polyfill内容 await import("./polyfill.js"); + // 初始化沙盒的Realms + await initializeSandboxRealms(); + // 初始化security + const securityModule = await import("../util/security.js"); + const security = securityModule.default; security.initSecurity({ lib, game, ui, get, ai, _status, gnc, }); diff --git a/noname/library/init/index.js b/noname/library/init/index.js index 99774b251..6ea159fba 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -12,7 +12,6 @@ import { GameEventPromise } from "../element/gameEventPromise.js"; import { rootURL } from "../../../noname.js"; import security from "../../util/security.js"; -import { Domain, Marshal, Sandbox } from "../../util/sandbox.js"; export class LibInit { /** @@ -596,32 +595,15 @@ export class LibInit { * @returns */ parsex(item, scope) { - let ModFunction = Function; - let ModGeneratorFunction = GeneratorFunction; - // let ModAsyncFunction = AsyncFunction; - // let ModAsyncGeneratorFunction = AsyncGeneratorFunction; - // 虽然现在 parsex 被控制到了沙盒, // 但是因为默认沙盒还是可以额外操作东西, // 故而对不同的运行域做了区分 - if (security.SANDBOX_ENABLED) { - const domain = Marshal.getMarshalledDomain(item) || Domain.caller; - - // 非顶级域调用情况下我们替换掉Function类型 - if (domain && domain !== Domain.topDomain) { - const sandbox = Sandbox.from(domain); - - if (!sandbox) - throw "意外的运行域: 运行域没有绑定沙盒"; - - [ - ModFunction, - ModGeneratorFunction, - // ModAsyncFunction, - // ModAsyncGeneratorFunction, - ] = security.getIsolateds(sandbox); - } - } + let [ + ModFunction, + ModGeneratorFunction, + // ModAsyncFunction, + // ModAsyncGeneratorFunction, + ] = security.getIsolatedsFrom(item); //by 诗笺、Tipx-L /** diff --git a/noname/ui/create/menu/pages/otherMenu.js b/noname/ui/create/menu/pages/otherMenu.js index 1a28beda1..834d14335 100644 --- a/noname/ui/create/menu/pages/otherMenu.js +++ b/noname/ui/create/menu/pages/otherMenu.js @@ -21,7 +21,6 @@ import { getTreesFromGithub, } from "../../../../library/update.js"; import security from "../../../../util/security.js"; -import { AccessAction, Marshal, Monitor } from "../../../../util/sandbox.js"; export const otherMenu = function (/** @type { boolean | undefined } */ connectMenu) { if (connectMenu) return; @@ -1215,6 +1214,7 @@ export const otherMenu = function (/** @type { boolean | undefined } */ connectM cheat: lib.cheat, }); if (security.isSandboxRequired()) { + const { Monitor, AccessAction } = security.importSandbox(); new Monitor() .action(AccessAction.DEFINE) .action(AccessAction.WRITE) diff --git a/noname/util/initRealms.js b/noname/util/initRealms.js new file mode 100644 index 000000000..e277ed948 --- /dev/null +++ b/noname/util/initRealms.js @@ -0,0 +1,121 @@ +// 为了兼容无法使用顶级await的版本 +const iframe = document.createElement("iframe"); + +// 执行上下文传递函数,请勿动喵 +// 用于传递顶级execute context + +/** @type {(target: Function, thiz: Object, args: Array) => any} */ +// @ts-ignore +const ContextInvoker1 = (function (apply, target, thiz, args) { + return apply(target, thiz, args); +}).bind(null, Reflect.apply); + +/** @type {(target: Function, args: Array, newTarget: Function) => any} */ +// @ts-ignore +const ContextInvoker2 = (function (construct, target, args, newTarget) { + return construct(target, args, newTarget); +}).bind(null, Reflect.construct); + +/** @type {(closure: Object, target: Function) => ((...args: any[]) => any)} */ +// @ts-ignore +const ContextInvokerCreator = (function (apply, closure, target) { + return function (...args) { + return apply(target, closure, + // @ts-ignore + [this === window ? null : this, args, new.target]); + }; +}).bind(null, Reflect.apply); + +/** + * @param {string} path + * @param {string} name + */ +function replaceName(path, name) { + const index = path.lastIndexOf("/"); + return path.slice(0, index + 1) + name; +} + +const TARGET_URL = replaceName(import.meta.url, "sandbox.js"); +const SANDBOX_EXPORT = {}; + +async function initializeSandboxRealms() { + const document = window.document; + const createElement = document.createElement.bind(document); + const appendChild = document.body.appendChild.bind(document.body); + + // 通过构造 iframe 来创建新的变量域 + // 我们需要确保顶级运行域的原型链不暴露 + // 为此我们从新的变量域重新载入当前脚本 + // 然后就可以直接冻结当前变量域的原型链 + const iframe = createElement("iframe"); + iframe.style.display = "none"; + appendChild(iframe); + + if (!iframe.contentWindow) + throw new ReferenceError("无法载入运行域"); + + // 定义 createRealms 函数 + Reflect.defineProperty(iframe.contentWindow, "createRealms", { + value() { + // 通过构造 iframe 来创建新的变量域 + const iframe = createElement("iframe"); + iframe.style.display = "none"; + appendChild(iframe); + + const window = iframe.contentWindow; + if (!window) + throw new ReferenceError("顶级域已经被卸载"); + + iframe.remove(); + return window; + }, + }); + + // 传递顶级变量域、上下文执行器 + // @ts-ignore + iframe.contentWindow.replacedGlobal = window; + // @ts-ignore + iframe.contentWindow.replacedCI1 = ContextInvoker1; + // @ts-ignore + iframe.contentWindow.replacedCI2 = ContextInvoker2; + // @ts-ignore + iframe.contentWindow.replacedCIC = ContextInvokerCreator; + + // 重新以新的变量域载入当前脚本 + const script = iframe.contentWindow.document.createElement("script"); + script.src = TARGET_URL; + script.type = "module"; + + // 无法同步载入 + // script.async = false; + // script.defer = false; + + const promise = new Promise((resolve, reject) => { + script.onload = resolve; + script.onerror = reject; + }); + iframe.contentWindow.document.head.appendChild(script); + await promise; // Top Await Required Chrome 89 + + // @ts-ignore + if (!iframe.contentWindow.SANDBOX_EXPORT) + throw new ReferenceError("无法同步载入运行域"); + + // @ts-ignore + delete iframe.contentWindow.replacedGlobal; + // @ts-ignore + delete iframe.contentWindow.replacedCI1; + // @ts-ignore + delete iframe.contentWindow.replacedCI2; + // @ts-ignore + delete iframe.contentWindow.replacedCIC; + + // @ts-ignore + Object.assign(SANDBOX_EXPORT, iframe.contentWindow.SANDBOX_EXPORT); + iframe.remove(); +} + +export { + initializeSandboxRealms, + SANDBOX_EXPORT, +}; \ No newline at end of file diff --git a/noname/util/sandbox.js b/noname/util/sandbox.js index ae00c0fcb..a4851fc69 100644 --- a/noname/util/sandbox.js +++ b/noname/util/sandbox.js @@ -1,4 +1,9 @@ -const FILE_URL = import.meta.url; +import { SANDBOX_EXPORT } from "./initRealms.js"; + +// 很重要的事情! +// 请不要在在其他文件中import sandbox.js! +// 如果需要沙盒相关的类请用security.importSandbox()导入!!! +// 什么时候支持顶级await(Chrome 89)就可以改回去了,现在好麻烦哦 /** @typedef {any} Window */ @@ -1030,28 +1035,15 @@ class NativeWrapper { /** @type {(target: Function, thiz: Object, args: Array) => any} */ // @ts-ignore -const ContextInvoker1 = window.replacedCI1 - || (function (apply, target, thiz, args) { - return apply(target, thiz, args); - }).bind(null, Reflect.apply); +const ContextInvoker1 = window.replacedCI1; /** @type {(target: Function, args: Array, newTarget: Function) => any} */ // @ts-ignore -const ContextInvoker2 = window.replacedCI2 - || (function (construct, target, args, newTarget) { - return construct(target, args, newTarget); - }).bind(null, Reflect.construct); +const ContextInvoker2 = window.replacedCI2; /** @type {(closure: Object, target: Function) => ((...args: any[]) => any)} */ // @ts-ignore -const ContextInvokerCreator = window.replacedCIC - || (function (apply, closure, target) { - return function (...args) { - return apply(target, closure, - // @ts-ignore - [this === window ? null : this, args, new.target]); - }; - }).bind(null, Reflect.apply); +const ContextInvokerCreator = window.replacedCIC; /** * ```plain @@ -3521,89 +3513,9 @@ function sealObject(obj, freeze = Object.freeze) { } } -const SANDBOX_EXPORT = { - AccessAction, - Rule, - Monitor, - Marshal, - Domain, - Sandbox, -}; - -// TODO: 其他扩展的全局变量 - if (SANDBOX_ENABLED) { // 确保顶级运行域的原型链不暴露 if (window.top === window) { - // 如果当前是顶级运行域 - const document = window.document; - const createElement = document.createElement.bind(document); - const appendChild = document.body.appendChild.bind(document.body); - - // 通过构造 iframe 来创建新的变量域 - // 我们需要确保顶级运行域的原型链不暴露 - // 为此我们从新的变量域重新载入当前脚本 - // 然后就可以直接冻结当前变量域的原型链 - const iframe = createElement("iframe"); - iframe.style.display = "none"; - appendChild(iframe); - - if (!iframe.contentWindow) - throw new ReferenceError("无法载入运行域"); - - // 定义 createRealms 函数 - Reflect.defineProperty(iframe.contentWindow, "createRealms", { - value() { - // 通过构造 iframe 来创建新的变量域 - const iframe = createElement("iframe"); - iframe.style.display = "none"; - appendChild(iframe); - - const window = iframe.contentWindow; - if (!window) - throw new ReferenceError("顶级域已经被卸载"); - - iframe.remove(); - return window; - }, - }); - - // 传递顶级变量域、上下文执行器 - // @ts-ignore - iframe.contentWindow.replacedGlobal = window; - // @ts-ignore - iframe.contentWindow.replacedCI1 = ContextInvoker1; - // @ts-ignore - iframe.contentWindow.replacedCI2 = ContextInvoker2; - // @ts-ignore - iframe.contentWindow.replacedCIC = ContextInvokerCreator; - - // 重新以新的变量域载入当前脚本 - const script = iframe.contentWindow.document.createElement("script"); - script.src = FILE_URL; - script.type = "module"; - - const promise = new Promise((resolve, reject) => { - script.onload = resolve; - script.onerror = reject; - }); - iframe.contentWindow.document.head.appendChild(script); - await promise; - - // @ts-ignore - delete iframe.contentWindow.replacedGlobal; - // @ts-ignore - delete iframe.contentWindow.replacedCI1; - // @ts-ignore - delete iframe.contentWindow.replacedCI2; - // @ts-ignore - delete iframe.contentWindow.replacedCIC; - - // 从新的变量域暴露的对象获取导出 - // @ts-ignore - Object.assign(SANDBOX_EXPORT, iframe.contentWindow.SANDBOX_EXPORT); - iframe.remove(); // 释放 iframe 与相关的 browser context - ({ // @ts-ignore AccessAction, @@ -3658,8 +3570,14 @@ if (SANDBOX_ENABLED) { // 向顶级运行域暴露导出 // @ts-ignore - window.SANDBOX_EXPORT = - Object.assign({}, SANDBOX_EXPORT); + window.SANDBOX_EXPORT = { + AccessAction, + Rule, + Monitor, + Marshal, + Domain, + Sandbox, + }; } } diff --git a/noname/util/security.js b/noname/util/security.js index 79c71b02e..f4755ff04 100644 --- a/noname/util/security.js +++ b/noname/util/security.js @@ -1,5 +1,3 @@ -import { Sandbox, Domain, Marshal, Monitor, AccessAction, Rule, SANDBOX_ENABLED } from "./sandbox.js"; - // 是否强制所有模式下使用沙盒 const SANDBOX_FORCED = true; // 是否启用自动测试 @@ -12,11 +10,37 @@ const TRUSTED_IPS = Object.freeze([ "47.99.105.222", ]); +/** @type {boolean} */ +let SANDBOX_ENABLED = true; +/** @type {typeof import("./sandbox.js").AccessAction} */ +let AccessAction; +/** @type {typeof import("./sandbox.js").Domain} */ +let Domain; +/** @type {typeof import("./sandbox.js").Marshal} */ +let Marshal; +/** @type {typeof import("./sandbox.js").Monitor} */ +let Monitor; +/** @type {typeof import("./sandbox.js").Rule} */ +let Rule; +/** @type {typeof import("./sandbox.js").Sandbox} */ +let Sandbox; + +/** @typedef {import("./sandbox.js").AccessAction} AccessAction */ +/** @typedef {import("./sandbox.js").Domain} Domain */ +/** @typedef {import("./sandbox.js").Marshal} Marshal */ +/** @typedef {import("./sandbox.js").Monitor} Monitor */ +/** @typedef {import("./sandbox.js").Rule} Rule */ +/** @typedef {import("./sandbox.js").Sandbox} Sandbox */ + +/** @type {boolean} */ let initialized = false; +/** @type {Sandbox} */ +let defaultSandbox; /** @type {Array} */ const sandboxStack = []; +// 沙盒Function类型缓存 /** @type {WeakMap>} */ const isolatedsMap = new WeakMap(); @@ -46,6 +70,16 @@ const polyfills = { namespaces: {}, }; +// 被封装的Function类型 +/** @type {typeof Function} */ +let ModFunction; +/** @type {typeof Function} */ +let ModGeneratorFunction; +/** @type {typeof Function} */ +let ModAsyncFunction; +/** @type {typeof Function} */ +let ModAsyncGeneratorFunction; + /** * ```plain * 将一个沙盒作为当前联网传输的运行沙盒 @@ -283,7 +317,12 @@ function _exec2(x, scope = {}) { return scope; } -function initSecurity({ +/** + * ```plain + * 初始化模块 + * ``` + */ +async function initSecurity({ lib, game, ui, @@ -295,6 +334,15 @@ function initSecurity({ if (initialized) throw "security 已经被初始化过了"; + const sandbox = await import("./sandbox.js"); + SANDBOX_ENABLED = sandbox.SANDBOX_ENABLED; + AccessAction = sandbox.AccessAction; + Domain = sandbox.Domain; + Marshal = sandbox.Marshal; + Monitor = sandbox.Monitor; + Rule = sandbox.Rule; + Sandbox = sandbox.Sandbox; + topVariables.lib = lib; topVariables.game = game; topVariables.ui = ui; @@ -307,11 +355,7 @@ function initSecurity({ return; loadPolyfills(); - - // @ts-ignore - Object.assign(defaultSandbox.scope, topVariables); - // @ts-ignore - setupPolyfills(defaultSandbox); + initIsolatedEnvironment(); // 不允许被远程代码访问的game函数 const ioFuncs = [ @@ -510,6 +554,181 @@ function getIsolateds(sandbox) { return isolateds.slice(); } +/** + * ```plain + * 根据传入对象的运行域获取对应的Function类型 + * ``` + * + * @param {Object} item + * @returns {Array} + */ +function getIsolatedsFrom(item) { + const domain = Marshal.getMarshalledDomain(item) || Domain.caller; + + // 非顶级域调用情况下我们替换掉Function类型 + if (domain && domain !== Domain.topDomain) { + const box = Sandbox.from(domain); + + if (!box) + throw "意外的运行域: 运行域没有绑定沙盒"; + + return getIsolateds(box); + } + + return [ + ModFunction, + ModGeneratorFunction, + ModAsyncFunction, + ModAsyncGeneratorFunction, + ]; +} + +/** + * ```plain + * 导入 `sandbox.js` 的相关类 + * ``` + * + * @returns {{ + * AccessAction: typeof import("./sandbox.js").AccessAction, + * Domain: typeof import("./sandbox.js").Domain, + * Marshal: typeof import("./sandbox.js").Marshal, + * Monitor: typeof import("./sandbox.js").Monitor, + * Rule: typeof import("./sandbox.js").Rule, + * Sandbox: typeof import("./sandbox.js").Sandbox, + * }} + */ +function importSandbox() { + if (!AccessAction) + throw new ReferenceError("sandbox.js 还没有被载入"); + + return { + AccessAction, + Domain, + Marshal, + Monitor, + Rule, + Sandbox, + }; +} + +/** + * ```plain + * 初始化顶级域的Funcion类型封装 + * ``` + */ +function initIsolatedEnvironment() { + /** @type {typeof Function} */ + // @ts-ignore + const defaultFunction = function () { }.constructor; + /** @type {typeof Function} */ + // @ts-ignore + const defaultGeneratorFunction = function* () { }.constructor; + /** @type {typeof Function} */ + // @ts-ignore + const defaultAsyncFunction = async function () { }.constructor; + /** @type {typeof Function} */ + // @ts-ignore + const defaultAsyncGeneratorFunction = async function* () { }.constructor; + + // @ts-ignore + defaultSandbox = createSandbox(); // 所有 eval、parsex 代码全部丢进去喵 + + // @ts-ignore + // 对于 defaultSandbox 我们要补充一些东西喵 + defaultSandbox.scope.localStorage = localStorage; + + // 对Function类型进行包裹 + /** @type {Array} */ + const [ + IsolatedFunction, + IsolatedGeneratorFunction, + IsolatedAsyncFunction, + IsolatedAsyncGeneratorFunction, + ] + // @ts-ignore + = getIsolateds(defaultSandbox); + + // 封装Function类型 + + ModFunction = new Proxy(defaultFunction, { + apply(target, thisArg, argumentsList) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedFunction(...argumentsList); + }, + construct(target, argumentsList, newTarget) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedFunction(...argumentsList); + }, + }); + + /** @type {typeof Function} */ + ModGeneratorFunction = new Proxy(defaultGeneratorFunction, { + apply(target, thisArg, argumentsList) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedGeneratorFunction(...argumentsList); + }, + construct(target, argumentsList, newTarget) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedGeneratorFunction(...argumentsList); + }, + }); + + /** @type {typeof Function} */ + ModAsyncFunction = new Proxy(defaultAsyncFunction, { + apply(target, thisArg, argumentsList) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedAsyncFunction(...argumentsList); + }, + construct(target, argumentsList, newTarget) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedAsyncFunction(...argumentsList); + }, + }); + + /** @type {typeof Function} */ + ModAsyncGeneratorFunction = new Proxy(defaultAsyncGeneratorFunction, { + apply(target, thisArg, argumentsList) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedAsyncGeneratorFunction(...argumentsList); + }, + construct(target, argumentsList, newTarget) { + if (!sandBoxRequired) + return new target(...argumentsList); + + return new IsolatedAsyncGeneratorFunction(...argumentsList); + }, + }); + + function rewriteCtor(prototype, newCtor) { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') + || { configurable: true, writable: true, enumerable: false }; + if (!descriptor.configurable) throw new TypeError("无法覆盖不可配置的构造函数"); + descriptor.value = newCtor; + Reflect.defineProperty(prototype, 'constructor', descriptor); + } + + // 覆盖所有的Function类型构造函数 + window.Function = ModFunction; + rewriteCtor(defaultFunction.prototype, ModFunction); + rewriteCtor(defaultGeneratorFunction.prototype, ModGeneratorFunction); + rewriteCtor(defaultAsyncFunction.prototype, ModAsyncFunction); + rewriteCtor(defaultAsyncGeneratorFunction.prototype, ModAsyncGeneratorFunction); +} + /** * ```plain * 加载当前的垫片函数 @@ -607,127 +826,6 @@ function setupPolyfills(sandbox) { `, context); } -/** @type {typeof Function} */ -// @ts-ignore -const defaultFunction = function () { }.constructor; -/** @type {typeof Function} */ -// @ts-ignore -const defaultGeneratorFunction = function* () { }.constructor; -/** @type {typeof Function} */ -// @ts-ignore -const defaultAsyncFunction = async function () { }.constructor; -/** @type {typeof Function} */ -// @ts-ignore -const defaultAsyncGeneratorFunction = async function* () { }.constructor; - -const defaultSandbox = createSandbox(); // 所有 eval、parsex 代码全部丢进去喵 - -if (SANDBOX_ENABLED) { - // @ts-ignore - // 对于 defaultSandbox 我们要补充一些东西喵 - defaultSandbox.scope.localStorage = localStorage; - - // 对Function类型进行包裹 - /** @type {Array} */ - const [ - IsolatedFunction, - IsolatedGeneratorFunction, - IsolatedAsyncFunction, - IsolatedAsyncGeneratorFunction, - ] - // @ts-ignore - = getIsolateds(defaultSandbox); - - /** @type {typeof Function} */ - let ModFunction; - /** @type {typeof Function} */ - let ModGeneratorFunction; - /** @type {typeof Function} */ - let ModAsyncFunction; - /** @type {typeof Function} */ - let ModAsyncGeneratorFunction; - - // 封装Function类型 - - ModFunction = new Proxy(defaultFunction, { - apply(target, thisArg, argumentsList) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedFunction(...argumentsList); - }, - construct(target, argumentsList, newTarget) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedFunction(...argumentsList); - }, - }); - - /** @type {typeof Function} */ - ModGeneratorFunction = new Proxy(defaultGeneratorFunction, { - apply(target, thisArg, argumentsList) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedGeneratorFunction(...argumentsList); - }, - construct(target, argumentsList, newTarget) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedGeneratorFunction(...argumentsList); - }, - }); - - /** @type {typeof Function} */ - ModAsyncFunction = new Proxy(defaultAsyncFunction, { - apply(target, thisArg, argumentsList) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedAsyncFunction(...argumentsList); - }, - construct(target, argumentsList, newTarget) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedAsyncFunction(...argumentsList); - }, - }); - - /** @type {typeof Function} */ - ModAsyncGeneratorFunction = new Proxy(defaultAsyncGeneratorFunction, { - apply(target, thisArg, argumentsList) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedAsyncGeneratorFunction(...argumentsList); - }, - construct(target, argumentsList, newTarget) { - if (!sandBoxRequired) - return new target(...argumentsList); - - return new IsolatedAsyncGeneratorFunction(...argumentsList); - }, - }); - - function rewriteCtor(prototype, newCtor) { - const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') - || { configurable: true, writable: true, enumerable: false }; - if (!descriptor.configurable) throw new TypeError("无法覆盖不可配置的构造函数"); - descriptor.value = newCtor; - Reflect.defineProperty(prototype, 'constructor', descriptor); - } - - // 覆盖所有的Function类型构造函数 - window.Function = ModFunction; - rewriteCtor(defaultFunction.prototype, ModFunction); - rewriteCtor(defaultGeneratorFunction.prototype, ModGeneratorFunction); - rewriteCtor(defaultAsyncFunction.prototype, ModAsyncFunction); - rewriteCtor(defaultAsyncGeneratorFunction.prototype, ModAsyncGeneratorFunction); -} - // 测试暴露喵 // window.sandbox = defaultSandbox; @@ -739,6 +837,8 @@ const exports = { isUnsafeObject, assertSafeObject, getIsolateds, + getIsolatedsFrom, + importSandbox, requireSandbox, requireSandboxOn, isSandboxRequired,