ses
Version:
Hardened JavaScript for Fearless Cooperation
176 lines (167 loc) • 4.84 kB
JavaScript
import {
TypeError,
assign,
create,
defineProperty,
entries,
freeze,
hasOwn,
unscopablesSymbol,
} from './commons.js';
import { makeEvalFunction } from './make-eval-function.js';
import { makeFunctionConstructor } from './make-function-constructor.js';
import { constantProperties, universalPropertyNames } from './permits.js';
/**
* The host's ordinary global object is not provided by a `with` block, so
* assigning to Symbol.unscopables has no effect.
* Since this shim uses `with` blocks to create a confined lexical scope for
* guest programs, we cannot emulate the proper behavior.
* With this shim, assigning Symbol.unscopables causes the given lexical
* names to fall through to the terminal scope proxy.
* But, we can install this setter to prevent a program from proceding on
* this false assumption.
*
* @param {object} globalObject
*/
export const setGlobalObjectSymbolUnscopables = globalObject => {
defineProperty(
globalObject,
unscopablesSymbol,
freeze(
assign(create(null), {
set: freeze(() => {
throw TypeError(
`Cannot set Symbol.unscopables of a Compartment's globalThis`,
);
}),
enumerable: false,
configurable: false,
}),
),
);
};
/**
* setGlobalObjectConstantProperties()
* Initializes a new global object using a process similar to ECMA specifications
* (SetDefaultGlobalBindings). This process is split between this function and
* `setGlobalObjectMutableProperties`.
*
* @param {object} globalObject
*/
export const setGlobalObjectConstantProperties = globalObject => {
for (const [name, constant] of entries(constantProperties)) {
defineProperty(globalObject, name, {
value: constant,
writable: false,
enumerable: false,
configurable: false,
});
}
};
/**
* setGlobalObjectMutableProperties()
* Create new global object using a process similar to ECMA specifications
* (portions of SetRealmGlobalObject and SetDefaultGlobalBindings).
* `newGlobalPropertyNames` should be either `initialGlobalPropertyNames` or
* `sharedGlobalPropertyNames`.
*
* @param {object} globalObject
* @param {object} args
* @param {object} args.intrinsics
* @param {object} args.newGlobalPropertyNames
* @param {Function} args.makeCompartmentConstructor
* @param {(object) => void} args.markVirtualizedNativeFunction
* @param {Compartment} [args.parentCompartment]
*/
export const setGlobalObjectMutableProperties = (
globalObject,
{
intrinsics,
newGlobalPropertyNames,
makeCompartmentConstructor,
markVirtualizedNativeFunction,
parentCompartment,
},
) => {
for (const [name, intrinsicName] of entries(universalPropertyNames)) {
if (hasOwn(intrinsics, intrinsicName)) {
defineProperty(globalObject, name, {
value: intrinsics[intrinsicName],
writable: true,
enumerable: false,
configurable: true,
});
}
}
for (const [name, intrinsicName] of entries(newGlobalPropertyNames)) {
if (hasOwn(intrinsics, intrinsicName)) {
defineProperty(globalObject, name, {
value: intrinsics[intrinsicName],
writable: true,
enumerable: false,
configurable: true,
});
}
}
const perCompartmentGlobals = {
globalThis: globalObject,
};
perCompartmentGlobals.Compartment = freeze(
makeCompartmentConstructor(
makeCompartmentConstructor,
intrinsics,
markVirtualizedNativeFunction,
{
parentCompartment,
enforceNew: true,
},
),
);
// TODO These should still be tamed according to the permits before
// being made available.
for (const [name, value] of entries(perCompartmentGlobals)) {
defineProperty(globalObject, name, {
value,
writable: true,
enumerable: false,
configurable: true,
});
if (typeof value === 'function') {
markVirtualizedNativeFunction(value);
}
}
};
/**
* setGlobalObjectEvaluators()
* Set the eval and the Function evaluator on the global object with given evalTaming policy.
*
* @param {object} globalObject
* @param {Function} evaluator
* @param {(object) => void} markVirtualizedNativeFunction
*/
export const setGlobalObjectEvaluators = (
globalObject,
evaluator,
markVirtualizedNativeFunction,
) => {
{
const f = freeze(makeEvalFunction(evaluator));
markVirtualizedNativeFunction(f);
defineProperty(globalObject, 'eval', {
value: f,
writable: true,
enumerable: false,
configurable: true,
});
}
{
const f = freeze(makeFunctionConstructor(evaluator));
markVirtualizedNativeFunction(f);
defineProperty(globalObject, 'Function', {
value: f,
writable: true,
enumerable: false,
configurable: true,
});
}
};