UNPKG

ses

Version:

Hardened JavaScript for Fearless Cooperation

243 lines (217 loc) 8.75 kB
import { toStringTagSymbol, iteratorSymbol } from './commons.js'; /** * @module Exports {@code enablements}, a recursively defined * JSON record defining the optimum set of intrinsics properties * that need to be "repaired" before hardening is applied on * enviromments subject to the override mistake. * * @author JF Paradis * @author Mark S. Miller */ /** * <p>Because "repairing" replaces data properties with accessors, every * time a repaired property is accessed, the associated getter is invoked, * which degrades the runtime performance of all code executing in the * repaired enviromment, compared to the non-repaired case. In order * to maintain performance, we only repair the properties of objects * for which hardening causes a breakage of their normal intended usage. * * There are three unwanted cases: * <ul> * <li>Overriding properties on objects typically used as records, * namely {@code "Object"} and {@code "Array"}. In the case of arrays, * the situation is unintentional, a given program might not be aware * that non-numerical properties are stored on the underlying object * instance, not on the array. When an object is typically used as a * map, we repair all of its prototype properties. * <li>Overriding properties on objects that provide defaults on their * prototype and that programs typically set using an assignment, such as * {@code "Error.prototype.message"} and {@code "Function.prototype.name"} * (both default to ""). * <li>Setting-up a prototype chain, where a constructor is set to extend * another one. This is typically set by assignment, for example * {@code "Child.prototype.constructor = Child"}, instead of invoking * Object.defineProperty(); * * <p>Each JSON record enumerates the disposition of the properties on * some corresponding intrinsic object. * * <p>For each such record, the values associated with its property * names can be: * <ul> * <li>true, in which case this property is simply repaired. The * value associated with that property is not traversed. For * example, {@code "Function.prototype.name"} leads to true, * meaning that the {@code "name"} property of {@code * "Function.prototype"} should be repaired (which is needed * when inheriting from @code{Function} and setting the subclass's * {@code "prototype.name"} property). If the property is * already an accessor property, it is not repaired (because * accessors are not subject to the override mistake). * <li>"*", in which case this property is not repaired but the * value associated with that property are traversed and repaired. * <li>Another record, in which case this property is not repaired * and that next record represents the disposition of the object * which is its value. For example,{@code "FunctionPrototype"} * leads to another record explaining which properties {@code * Function.prototype} need to be repaired. */ /** * Minimal enablements when all the code is modern and known not to * step into the override mistake, except for the following pervasive * cases. */ export const minEnablements = { '%ObjectPrototype%': { toString: true, }, '%FunctionPrototype%': { toString: true, // set by "rollup" }, '%ErrorPrototype%': { name: true, // set by "precond", "ava", "node-fetch" }, '%IteratorPrototype%': { toString: true, // https://github.com/tc39/proposal-iterator-helpers constructor: true, // https://github.com/tc39/proposal-iterator-helpers [toStringTagSymbol]: true, }, }; /** * Moderate enablements are usually good enough for legacy compat. */ export const moderateEnablements = { '%ObjectPrototype%': { toString: true, valueOf: true, }, '%ArrayPrototype%': { toString: true, push: true, // set by "Google Analytics" concat: true, // set by mobx generated code (old TS compiler?) [iteratorSymbol]: true, // set by mobx generated code (old TS compiler?) }, // Function.prototype has no 'prototype' property to enable. // Function instances have their own 'name' and 'length' properties // which are configurable and non-writable. Thus, they are already // non-assignable anyway. '%FunctionPrototype%': { constructor: true, // set by "regenerator-runtime" bind: true, // set by "underscore", "express" toString: true, // set by "rollup" }, '%ErrorPrototype%': { constructor: true, // set by "fast-json-patch", "node-fetch" message: true, name: true, // set by "precond", "ava", "node-fetch", "node 14" toString: true, // set by "bluebird" }, '%TypeErrorPrototype%': { constructor: true, // set by "readable-stream" message: true, // set by "tape" name: true, // set by "readable-stream", "node 14" }, '%SyntaxErrorPrototype%': { message: true, // to match TypeErrorPrototype.message name: true, // set by "node 14" }, '%RangeErrorPrototype%': { message: true, // to match TypeErrorPrototype.message name: true, // set by "node 14" }, '%URIErrorPrototype%': { message: true, // to match TypeErrorPrototype.message name: true, // set by "node 14" }, '%EvalErrorPrototype%': { message: true, // to match TypeErrorPrototype.message name: true, // set by "node 14" }, '%ReferenceErrorPrototype%': { message: true, // to match TypeErrorPrototype.message name: true, // set by "node 14" }, // https://github.com/endojs/endo/issues/550 '%AggregateErrorPrototype%': { message: true, // to match TypeErrorPrototype.message name: true, // set by "node 14"? }, '%PromisePrototype%': { constructor: true, // set by "core-js" }, '%TypedArrayPrototype%': '*', // set by https://github.com/feross/buffer '%Generator%': { constructor: true, name: true, toString: true, }, '%IteratorPrototype%': { toString: true, // https://github.com/tc39/proposal-iterator-helpers constructor: true, // https://github.com/tc39/proposal-iterator-helpers [toStringTagSymbol]: true, }, }; /** * The 'severe' enablement are needed because of issues tracked at * https://github.com/endojs/endo/issues/576 * * They are like the `moderate` enablements except for the entries below. */ export const severeEnablements = { ...moderateEnablements, /** * Rollup (as used at least by vega) and webpack * (as used at least by regenerator) both turn exports into assignments * to a big `exports` object that inherits directly from * `Object.prototype`. Some of the exported names we've seen include * `hasOwnProperty`, `constructor`, and `toString`. But the strategy used * by rollup and webpack potentionally turns any exported name * into an assignment rejected by the override mistake. That's why * the `severe` enablements takes the extreme step of enabling * everything on `Object.prototype`. * * In addition, code doing inheritance manually will often override * the `constructor` property on the new prototype by assignment. We've * seen this several times. * * The cost of enabling all these is that they create a miserable debugging * experience specifically on Node. * https://github.com/Agoric/agoric-sdk/issues/2324 * explains how it confused the Node console. * * (TODO Reexamine the vscode situation. I think it may have improved * since the following paragraph was written.) * * The vscode debugger's object inspector shows the own data properties of * an object, which is typically what you want, but also shows both getter * and setter for every accessor property whether inherited or own. * With the `'*'` setting here, all the properties inherited from * `Object.prototype` are accessors, creating an unusable display as seen * at As explained at * https://github.com/endojs/endo/blob/master/packages/ses/docs/lockdown.md#overridetaming-options * Open the triangles at the bottom of that section. */ '%ObjectPrototype%': '*', /** * The widely used Buffer defined at https://github.com/feross/buffer * on initialization, manually creates the equivalent of a subclass of * `TypedArray`, which it then initializes by assignment. These assignments * include enough of the `TypeArray` methods that here, the `severe` * enablements just enable them all. */ '%TypedArrayPrototype%': '*', /** * Needed to work with Immer before https://github.com/immerjs/immer/pull/914 * is accepted. */ '%MapPrototype%': '*', /** * Needed to work with Immer before https://github.com/immerjs/immer/pull/914 * is accepted. */ '%SetPrototype%': '*', };