xuxiaobo-bobo 842b34b5ca 0218
2024-02-18 15:40:48 +08:00

1045 lines
34 KiB
JavaScript

/* global host */
/* eslint-disable block-spacing, no-multi-spaces, brace-style, no-array-constructor, new-cap, no-use-before-define */
// debugger
'use strict';
// eslint-disable-next-line no-invalid-this, no-shadow
const global = this;
// global.async = function (fn) {
// return fn();
// };
// global.await = function (promise) {
// return promise;
// };
// debugger
const local = host.Object.create(null);
local.Object = Object;
local.Array = Array;
local.Reflect = host.Object.create(null);
local.Reflect.ownKeys = Reflect.ownKeys;
local.Reflect.enumerate = Reflect.enumerate;
local.Reflect.getPrototypeOf = Reflect.getPrototypeOf;
local.Reflect.construct = Reflect.construct;
local.Reflect.apply = Reflect.apply;
local.Reflect.set = Reflect.set;
local.Reflect.deleteProperty = Reflect.deleteProperty;
local.Reflect.has = Reflect.has;
local.Reflect.defineProperty = Reflect.defineProperty;
local.Reflect.setPrototypeOf = Reflect.setPrototypeOf;
local.Reflect.isExtensible = Reflect.isExtensible;
local.Reflect.preventExtensions = Reflect.preventExtensions;
local.Reflect.getOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor;
// local.Reflect.async = function (fn) {
// return fn();
// };
// local.Reflect.await = function (promise) {
// return promise;
// };
// global is originally prototype of host.Object so it can be used to climb up from the sandbox.
Object.setPrototypeOf(global, Object.prototype);
/*
Object.defineProperties(global, {
global: {value: global},
GLOBAL: {value: global},
root: {value: global},
isVM: {value: true}
});
*/
const DEBUG = false;
const OPNA = 'Operation not allowed on contextified object.';
const captureStackTrace = Error.captureStackTrace;
// debugger
const FROZEN_TRAPS = host.Object.create(null);
FROZEN_TRAPS.set = (target, key) => false;
FROZEN_TRAPS.setPrototypeOf = (target, key) => false;
FROZEN_TRAPS.defineProperty = (target, key) => false;
FROZEN_TRAPS.deleteProperty = (target, key) => false;
FROZEN_TRAPS.isExtensible = (target, key) => false;
FROZEN_TRAPS.preventExtensions = (target) => false;
// Map of contextified objects to original objects
const Contextified = new host.WeakMap();
const Decontextified = new host.WeakMap();
// We can't use host's hasInstance method
const hasInstance = local.Object[Symbol.hasInstance];
function instanceOf(value, construct) {
try {
return host.Reflect.apply(hasInstance, construct, [value]);
} catch (ex) {
// Never pass the handled exception through!
throw new VMError('Unable to perform instanceOf check.');
// This exception actually never get to the user. It only instructs the caller to return null because we wasn't able to perform instanceOf check.
}
}
const SHARED_OBJECT = { __proto__: null };
function createBaseObject(obj) {
let base;
if (typeof obj === 'function') {
try {
// eslint-disable-next-line no-new
new new host.Proxy(obj, {
__proto__: null,
construct() {
return this;
}
})();
// eslint-disable-next-line func-names
base = function () { };
base.prototype = null;
} catch (e) {
base = () => { };
}
} else if (host.Array.isArray(obj)) {
base = [];
} else {
return { __proto__: null };
}
if (!local.Reflect.setPrototypeOf(base, null)) {
// Should not happen
return null;
}
return base;
}
/**
* VMError definition.
*/
class VMError extends Error {
constructor(message, code) {
super(message);
debugger
this.name = 'VMError';
this.code = code;
captureStackTrace(this, this.constructor);
}
}
global.VMError = VMError;
/*
* This function will throw a TypeError for accessing properties
* on a strict mode function
*/
function throwCallerCalleeArgumentsAccess(key) {
'use strict';
throwCallerCalleeArgumentsAccess[key];
return new VMError('Unreachable');
}
function unexpected() {
throw new VMError('Should not happen');
}
function doPreventExtensions(target, object, doProxy) {
const keys = local.Reflect.ownKeys(object);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
let desc = local.Reflect.getOwnPropertyDescriptor(object, key);
if (!desc) continue;
if (!local.Reflect.setPrototypeOf(desc, null)) unexpected();
if (!desc.configurable) {
const current = local.Reflect.getOwnPropertyDescriptor(target, key);
if (current && !current.configurable) continue;
if (desc.get || desc.set) {
desc.get = doProxy(desc.get);
desc.set = doProxy(desc.set);
} else {
desc.value = doProxy(desc.value);
}
} else {
if (desc.get || desc.set) {
desc = {
__proto__: null,
configurable: true,
enumerable: desc.enumerable,
writable: true,
value: null
};
} else {
desc.value = null;
}
}
if (!local.Reflect.defineProperty(target, key, desc)) unexpected();
}
if (!local.Reflect.preventExtensions(target)) unexpected();
}
/**
* Decontextify.
*/
const Decontextify = host.Object.create(null);
Decontextify.proxies = new host.WeakMap();
Decontextify.arguments = args => {
if (!host.Array.isArray(args)) return new host.Array();
try {
const arr = new host.Array();
for (let i = 0, l = args.length; i < l; i++) arr[i] = Decontextify.value(args[i]);
return arr;
} catch (e) {
// Never pass the handled exception through!
return new host.Array();
}
};
Decontextify.instance = (instance, klass, deepTraps, flags, toStringTag) => {
if (typeof instance === 'function') return Decontextify.function(instance);
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return instance;
if (key === 'isVMProxy') return true;
if (key === 'constructor') return klass;
if (key === '__proto__') return klass.prototype;
} catch (e) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return host.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return host.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return host.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return host.Object.prototype.__lookupSetter__;
if (key === host.Symbol.toStringTag && toStringTag) return toStringTag;
try {
return Decontextify.value(instance[key], null, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return klass && klass.prototype;
};
return Decontextify.object(instance, base, deepTraps, flags);
};
Decontextify.function = (fnc, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
// eslint-disable-next-line prefer-const
let proxy;
base.apply = (target, context, args) => {
context = Contextify.value(context);
// Set context of all arguments to vm's context.
args = Contextify.arguments(args);
try {
return Decontextify.value(fnc.apply(context, args));
} catch (e) {
throw Decontextify.value(e);
}
};
base.construct = (target, args, newTarget) => {
args = Contextify.arguments(args);
try {
return Decontextify.instance(new fnc(...args), proxy, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return fnc;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return host.Function;
if (key === '__proto__') return host.Function.prototype;
} catch (e) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return host.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return host.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return host.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return host.Object.prototype.__lookupSetter__;
try {
return Decontextify.value(fnc[key], null, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return host.Function.prototype;
};
proxy = Decontextify.object(fnc, host.Object.assign(base, traps), deepTraps);
return proxy;
};
Decontextify.object = (object, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return object;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return host.Object;
if (key === '__proto__') return host.Object.prototype;
} catch (e) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return host.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return host.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return host.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return host.Object.prototype.__lookupSetter__;
try {
return Decontextify.value(object[key], null, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.set = (target, key, value, receiver) => {
value = Contextify.value(value);
try {
return local.Reflect.set(object, key, value);
} catch (e) {
throw Decontextify.value(e);
}
};
base.getOwnPropertyDescriptor = (target, prop) => {
let def;
try {
def = host.Object.getOwnPropertyDescriptor(object, prop);
} catch (e) {
throw Decontextify.value(e);
}
// Following code prevents V8 to throw
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>'
// which is either non-existant or configurable in the proxy target
let desc;
if (!def) {
return undefined;
} else if (def.get || def.set) {
desc = {
__proto__: null,
get: Decontextify.value(def.get) || undefined,
set: Decontextify.value(def.set) || undefined,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
} else {
desc = {
__proto__: null,
value: Decontextify.value(def.value),
writable: def.writable === true,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
}
if (!desc.configurable) {
try {
def = host.Object.getOwnPropertyDescriptor(target, prop);
if (!def || def.configurable || def.writable !== desc.writable) {
local.Reflect.defineProperty(target, prop, desc);
}
} catch (e) {
// Should not happen.
}
}
return desc;
};
base.defineProperty = (target, key, descriptor) => {
let success = false;
try {
success = local.Reflect.setPrototypeOf(descriptor, null);
} catch (e) {
// Should not happen
}
if (!success) return false;
// There's a chance accessing a property throws an error so we must not access them
// in try catch to prevent contextifying local objects.
const propertyDescriptor = host.Object.create(null);
if (descriptor.get || descriptor.set) {
propertyDescriptor.get = Contextify.value(descriptor.get, null, deepTraps, flags) || undefined;
propertyDescriptor.set = Contextify.value(descriptor.set, null, deepTraps, flags) || undefined;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
} else {
propertyDescriptor.value = Contextify.value(descriptor.value, null, deepTraps, flags);
propertyDescriptor.writable = descriptor.writable === true;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
}
try {
success = local.Reflect.defineProperty(object, key, propertyDescriptor);
} catch (e) {
throw Decontextify.value(e);
}
if (success && !descriptor.configurable) {
try {
local.Reflect.defineProperty(target, key, descriptor);
} catch (e) {
// This should not happen.
return false;
}
}
return success;
};
base.deleteProperty = (target, prop) => {
try {
return Decontextify.value(local.Reflect.deleteProperty(object, prop));
} catch (e) {
throw Decontextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return host.Object.prototype;
};
base.setPrototypeOf = (target) => {
throw new host.Error(OPNA);
};
base.has = (target, key) => {
try {
return Decontextify.value(local.Reflect.has(object, key));
} catch (e) {
throw Decontextify.value(e);
}
};
base.isExtensible = target => {
let result;
try {
result = local.Reflect.isExtensible(object);
} catch (e) {
throw Decontextify.value(e);
}
if (!result) {
try {
if (local.Reflect.isExtensible(target)) {
doPreventExtensions(target, object, obj => Contextify.value(obj, null, deepTraps, flags));
}
} catch (e) {
// Should not happen
}
}
return result;
};
base.ownKeys = target => {
try {
return Decontextify.value(local.Reflect.ownKeys(object));
} catch (e) {
throw Decontextify.value(e);
}
};
base.preventExtensions = target => {
let success;
try {
success = local.Reflect.preventExtensions(object);
} catch (e) {
throw Decontextify.value(e);
}
if (success) {
try {
if (local.Reflect.isExtensible(target)) {
doPreventExtensions(target, object, obj => Contextify.value(obj, null, deepTraps, flags));
}
} catch (e) {
// Should not happen
}
}
return success;
};
base.enumerate = target => {
try {
return Decontextify.value(local.Reflect.enumerate(object));
} catch (e) {
throw Decontextify.value(e);
}
};
host.Object.assign(base, traps, deepTraps);
let shallow;
if (host.Array.isArray(object)) {
const origGet = base.get;
shallow = {
__proto__: null,
ownKeys: base.ownKeys,
// TODO this get will call getOwnPropertyDescriptor of target all the time.
get: origGet
};
base.ownKeys = target => {
try {
const keys = local.Reflect.ownKeys(object);
// Do this hack so that console.log(decontextify([1,2,3])) doesn't write the properties twice
// a la [1,2,3,'0':1,'1':2,'2':3]
return Decontextify.value(keys.filter(key => typeof key !== 'string' || !key.match(/^\d+$/)));
} catch (e) {
throw Decontextify.value(e);
}
};
base.get = (target, key, receiver) => {
if (key === host.Symbol.toStringTag) return;
return origGet(target, key, receiver);
};
} else {
shallow = SHARED_OBJECT;
}
const proxy = new host.Proxy(createBaseObject(object), base);
Decontextified.set(proxy, object);
// We need two proxies since nodes inspect just removes one.
const proxy2 = new host.Proxy(proxy, shallow);
Decontextify.proxies.set(object, proxy2);
Decontextified.set(proxy2, object);
return proxy2;
};
Decontextify.value = (value, traps, deepTraps, flags, mock) => {
try {
if (Contextified.has(value)) {
// Contextified object has returned back from vm
return Contextified.get(value);
} else if (Decontextify.proxies.has(value)) {
// Decontextified proxy already exists, reuse
return Decontextify.proxies.get(value);
}
// debugger
switch (typeof value) {
case 'object':
if (value === null) {
return null;
} else if (instanceOf(value, Number)) {
return Decontextify.instance(value, host.Number, deepTraps, flags, 'Number');
} else if (instanceOf(value, String)) {
return Decontextify.instance(value, host.String, deepTraps, flags, 'String');
} else if (instanceOf(value, Boolean)) {
return Decontextify.instance(value, host.Boolean, deepTraps, flags, 'Boolean');
} else if (instanceOf(value, Date)) {
return Decontextify.instance(value, host.Date, deepTraps, flags, 'Date');
} else if (instanceOf(value, RangeError)) {
return Decontextify.instance(value, host.RangeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, ReferenceError)) {
return Decontextify.instance(value, host.ReferenceError, deepTraps, flags, 'Error');
} else if (instanceOf(value, SyntaxError)) {
return Decontextify.instance(value, host.SyntaxError, deepTraps, flags, 'Error');
} else if (instanceOf(value, TypeError)) {
return Decontextify.instance(value, host.TypeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, VMError)) {
return Decontextify.instance(value, host.VMError, deepTraps, flags, 'Error');
} else if (instanceOf(value, EvalError)) {
return Decontextify.instance(value, host.EvalError, deepTraps, flags, 'Error');
} else if (instanceOf(value, URIError)) {
return Decontextify.instance(value, host.URIError, deepTraps, flags, 'Error');
} else if (instanceOf(value, Error)) {
debugger
return Decontextify.instance(value, host.Error, deepTraps, flags, 'Error');
} else if (instanceOf(value, Array)) {
return Decontextify.instance(value, host.Array, deepTraps, flags, 'Array');
} else if (instanceOf(value, RegExp)) {
return Decontextify.instance(value, host.RegExp, deepTraps, flags, 'RegExp');
} else if (instanceOf(value, Map)) {
return Decontextify.instance(value, host.Map, deepTraps, flags, 'Map');
} else if (instanceOf(value, WeakMap)) {
return Decontextify.instance(value, host.WeakMap, deepTraps, flags, 'WeakMap');
} else if (instanceOf(value, Set)) {
return Decontextify.instance(value, host.Set, deepTraps, flags, 'Set');
} else if (instanceOf(value, WeakSet)) {
return Decontextify.instance(value, host.WeakSet, deepTraps, flags, 'WeakSet');
} else if (typeof Promise === 'function' && instanceOf(value, Promise)) {
return Decontextify.instance(value, host.Promise, deepTraps, flags, 'Promise');
} else if (local.Reflect.getPrototypeOf(value) === null) {
return Decontextify.instance(value, null, deepTraps, flags);
} else {
return Decontextify.object(value, traps, deepTraps, flags, mock);
}
case 'function':
return Decontextify.function(value, traps, deepTraps, flags, mock);
case 'undefined':
return undefined;
default: // string, number, boolean, symbol
return value;
}
} catch (ex) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
};
/**
* Contextify.
*/
const Contextify = host.Object.create(null);
Contextify.proxies = new host.WeakMap();
Contextify.arguments = args => {
if (!host.Array.isArray(args)) return new local.Array();
try {
const arr = new local.Array();
for (let i = 0, l = args.length; i < l; i++) arr[i] = Contextify.value(args[i]);
return arr;
} catch (e) {
// Never pass the handled exception through!
return new local.Array();
}
};
Contextify.instance = (instance, klass, deepTraps, flags, toStringTag) => {
if (typeof instance === 'function') return Contextify.function(instance);
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return instance;
if (key === 'isVMProxy') return true;
if (key === 'constructor') return klass;
if (key === '__proto__') return klass.prototype;
} catch (e) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return local.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return local.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return local.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return local.Object.prototype.__lookupSetter__;
if (key === host.Symbol.toStringTag && toStringTag) return toStringTag;
try {
return Contextify.value(host.Reflect.get(instance, key), null, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return klass && klass.prototype;
};
return Contextify.object(instance, base, deepTraps, flags);
};
Contextify.function = (fnc, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
// eslint-disable-next-line prefer-const
let proxy;
base.apply = (target, context, args) => {
context = Decontextify.value(context);
// Set context of all arguments to host's context.
args = Decontextify.arguments(args);
try {
return Contextify.value(fnc.apply(context, args));
} catch (e) {
throw Contextify.value(e);
}
};
base.construct = (target, args, newTarget) => {
// Fixes buffer unsafe allocation for node v6/7
if (host.version < 8 && fnc === host.Buffer && 'number' === typeof args[0]) {
args[0] = new Array(args[0]).fill(0);
}
args = Decontextify.arguments(args);
try {
return Contextify.instance(new fnc(...args), proxy, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return fnc;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return Function;
if (key === '__proto__') return Function.prototype;
} catch (e) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return local.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return local.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return local.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return local.Object.prototype.__lookupSetter__;
if (key === 'caller' || key === 'callee' || key === 'arguments') throw throwCallerCalleeArgumentsAccess(key);
try {
return Contextify.value(host.Reflect.get(fnc, key), null, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return Function.prototype;
};
proxy = Contextify.object(fnc, host.Object.assign(base, traps), deepTraps);
return proxy;
};
Contextify.object = (object, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return object;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return Object;
if (key === '__proto__') return Object.prototype;
} catch (e) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return local.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return local.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return local.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return local.Object.prototype.__lookupSetter__;
try {
return Contextify.value(host.Reflect.get(object, key), null, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.set = (target, key, value, receiver) => {
if (key === '__proto__') return false;
if (flags && flags.protected && typeof value === 'function') return false;
value = Decontextify.value(value);
try {
return host.Reflect.set(object, key, value);
} catch (e) {
throw Contextify.value(e);
}
};
base.getOwnPropertyDescriptor = (target, prop) => {
let def;
try {
def = host.Object.getOwnPropertyDescriptor(object, prop);
} catch (e) {
throw Contextify.value(e);
}
// Following code prevents V8 to throw
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>'
// which is either non-existant or configurable in the proxy target
let desc;
if (!def) {
return undefined;
} else if (def.get || def.set) {
desc = {
__proto__: null,
get: Contextify.value(def.get, null, deepTraps, flags) || undefined,
set: Contextify.value(def.set, null, deepTraps, flags) || undefined,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
} else {
desc = {
__proto__: null,
value: Contextify.value(def.value, null, deepTraps, flags),
writable: def.writable === true,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
}
if (!desc.configurable) {
try {
def = host.Object.getOwnPropertyDescriptor(target, prop);
if (!def || def.configurable || def.writable !== desc.writable) {
local.Reflect.defineProperty(target, prop, desc);
}
} catch (e) {
// Should not happen.
}
}
return desc;
};
base.defineProperty = (target, key, descriptor) => {
let success = false;
try {
success = local.Reflect.setPrototypeOf(descriptor, null);
} catch (e) {
// Should not happen
}
if (!success) return false;
// There's a chance accessing a property throws an error so we must not access them
// in try catch to prevent contextifying local objects.
const descGet = descriptor.get;
const descSet = descriptor.set;
const descValue = descriptor.value;
if (flags && flags.protected) {
if (descGet || descSet || typeof descValue === 'function') return false;
}
const propertyDescriptor = host.Object.create(null);
if (descGet || descSet) {
propertyDescriptor.get = Decontextify.value(descGet, null, deepTraps, flags) || undefined;
propertyDescriptor.set = Decontextify.value(descSet, null, deepTraps, flags) || undefined;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
} else {
propertyDescriptor.value = Decontextify.value(descValue, null, deepTraps, flags);
propertyDescriptor.writable = descriptor.writable === true;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
}
try {
success = host.Reflect.defineProperty(object, key, propertyDescriptor);
} catch (e) {
throw Contextify.value(e);
}
if (success && !descriptor.configurable) {
try {
local.Reflect.defineProperty(target, key, descriptor);
} catch (e) {
// This should not happen.
return false;
}
}
return success;
};
base.deleteProperty = (target, prop) => {
try {
return Contextify.value(host.Reflect.deleteProperty(object, prop));
} catch (e) {
throw Contextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return local.Object.prototype;
};
base.setPrototypeOf = (target) => {
throw new VMError(OPNA);
};
base.has = (target, key) => {
try {
return Contextify.value(host.Reflect.has(object, key));
} catch (e) {
throw Contextify.value(e);
}
};
base.isExtensible = target => {
let result;
try {
result = host.Reflect.isExtensible(object);
} catch (e) {
throw Contextify.value(e);
}
if (!result) {
try {
if (local.Reflect.isExtensible(target)) {
doPreventExtensions(target, object, obj => Decontextify.value(obj, null, deepTraps, flags));
}
} catch (e) {
// Should not happen
}
}
return result;
};
base.ownKeys = target => {
try {
return Contextify.value(host.Reflect.ownKeys(object));
} catch (e) {
throw Contextify.value(e);
}
};
base.preventExtensions = target => {
let success;
try {
success = local.Reflect.preventExtensions(object);
} catch (e) {
throw Contextify.value(e);
}
if (success) {
try {
if (local.Reflect.isExtensible(target)) {
doPreventExtensions(target, object, obj => Decontextify.value(obj, null, deepTraps, flags));
}
} catch (e) {
// Should not happen
}
}
return success;
};
base.enumerate = target => {
try {
return Contextify.value(host.Reflect.enumerate(object));
} catch (e) {
throw Contextify.value(e);
}
};
// const proxy = new host.Proxy(createBaseObject(object), host.Object.assign(base, traps, deepTraps));
// debugger
const proxy = object;
Contextify.proxies.set(object, proxy);
Contextified.set(proxy, object);
return proxy;
};
Contextify.value = (value, traps, deepTraps, flags, mock) => {
try {
if (Decontextified.has(value)) {
// Contextify.setGlobal Decontextified object has returned back to vm
return Decontextified.get(value);
} else if (Contextify.proxies.has(value)) {
// Contextified proxy already exists, reuse
return Contextify.proxies.get(value);
}
// debugger
switch (typeof value) {
case 'object':
if (value === null) {
return null;
} else if (instanceOf(value, host.Number)) {
return Contextify.instance(value, Number, deepTraps, flags, 'Number');
} else if (instanceOf(value, host.String)) {
return Contextify.instance(value, String, deepTraps, flags, 'String');
} else if (instanceOf(value, host.Boolean)) {
return Contextify.instance(value, Boolean, deepTraps, flags, 'Boolean');
} else if (instanceOf(value, host.Date)) {
return Contextify.instance(value, Date, deepTraps, flags, 'Date');
} else if (instanceOf(value, host.RangeError)) {
return Contextify.instance(value, RangeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.ReferenceError)) {
return Contextify.instance(value, ReferenceError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.SyntaxError)) {
return Contextify.instance(value, SyntaxError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.TypeError)) {
return Contextify.instance(value, TypeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.VMError)) {
return Contextify.instance(value, VMError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.EvalError)) {
return Contextify.instance(value, EvalError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.URIError)) {
return Contextify.instance(value, URIError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.Error)) {
debugger
return Contextify.instance(value, Error, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.Array)) {
return Contextify.instance(value, Array, deepTraps, flags, 'Array');
} else if (instanceOf(value, host.RegExp)) {
return Contextify.instance(value, RegExp, deepTraps, flags, 'RegExp');
} else if (instanceOf(value, host.Map)) {
return Contextify.instance(value, Map, deepTraps, flags, 'Map');
} else if (instanceOf(value, host.WeakMap)) {
return Contextify.instance(value, WeakMap, deepTraps, flags, 'WeakMap');
} else if (instanceOf(value, host.Set)) {
return Contextify.instance(value, Set, deepTraps, flags, 'Set');
} else if (instanceOf(value, host.WeakSet)) {
return Contextify.instance(value, WeakSet, deepTraps, flags, 'WeakSet');
} else if (typeof Promise === 'function' && instanceOf(value, host.Promise)) {
return Contextify.instance(value, Promise, deepTraps, flags, 'Promise');
} else if (instanceOf(value, host.Buffer)) {
return Contextify.instance(value, LocalBuffer, deepTraps, flags, 'Uint8Array');
} else if (host.Reflect.getPrototypeOf(value) === null) {
return Contextify.instance(value, null, deepTraps, flags);
} else {
return Contextify.object(value, traps, deepTraps, flags, mock);
}
case 'function':
return Contextify.function(value, traps, deepTraps, flags, mock);
case 'undefined':
return undefined;
default: // string, number, boolean, symbol
return value;
}
} catch (ex) {
// Never pass the handled exception through! This block can't throw an exception under normal conditions.
return null;
}
};
Contextify.setGlobal = (name, value) => {
const prop = Contextify.value(name);
try {
global[prop] = value;//Contextify.value(value);
} catch (e) {
throw Decontextify.value(e);
}
};
Contextify.getGlobal = (name) => {
const prop = Contextify.value(name);
try {
return Decontextify.value(global[prop]);
} catch (e) {
throw Decontextify.value(e);
}
};
Contextify.readonly = (value, mock) => {
// debugger
return Contextify.value(value, null, FROZEN_TRAPS, null, mock);
};
Contextify.protected = (value, mock) => {
return Contextify.value(value, null, null, { protected: true }, mock);
};
Contextify.connect = (outer, inner) => {
Decontextified.set(outer, inner);
Contextified.set(inner, outer);
};
Contextify.makeModule = () => ({ exports: {} });
Contextify.isVMProxy = (obj) => Decontextified.has(obj);
const BufferMock = host.Object.create(null);
BufferMock.allocUnsafe = function allocUnsafe(size) {
return this.alloc(size);
};
BufferMock.allocUnsafeSlow = function allocUnsafeSlow(size) {
return this.alloc(size);
};
const BufferOverride = host.Object.create(null);
BufferOverride.inspect = function inspect(recurseTimes, ctx) {
// Mimic old behavior, could throw but didn't pass a test.
const max = host.INSPECT_MAX_BYTES;
const actualMax = Math.min(max, this.length);
const remaining = this.length - max;
let str = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();
if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
return `<${this.constructor.name} ${str}>`;
};
const LocalBuffer = global.Buffer = Contextify.readonly(host.Buffer, BufferMock);
Contextify.connect(host.Buffer.prototype.inspect, BufferOverride.inspect);
const exportsMap = host.Object.create(null);
exportsMap.Contextify = Contextify;
exportsMap.Decontextify = Decontextify;
exportsMap.Buffer = LocalBuffer;
exportsMap.sandbox = Decontextify.value(global);
exportsMap.Function = Function;
// debugger
return exportsMap;