From 18fcbaa6e8fe97e92ad7cc7dea9147ff5d37055f Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 26 Aug 2019 11:11:46 +0800 Subject: [PATCH 1/9] add mutable.js from tc39/proposal-ses e5271cc --- src/bundle/mutable.js | 133 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/bundle/mutable.js diff --git a/src/bundle/mutable.js b/src/bundle/mutable.js new file mode 100644 index 0000000..381876d --- /dev/null +++ b/src/bundle/mutable.js @@ -0,0 +1,133 @@ +// Adapted from SES/Caja +// Copyright (C) 2011 Google Inc. +// https://github.com/google/caja/blob/master/src/com/google/caja/ses/startSES.js +// https://github.com/google/caja/blob/master/src/com/google/caja/ses/repairES5.js + +import { + defineProperty, + getOwnPropertyDescriptor, + getOwnPropertyDescriptors, + getOwnPropertyNames, + getOwnPropertySymbols, + objectHasOwnProperty +} from '../realms-shim/src/commons'; + + +/** + * For a special set of properties (defined below), it ensures that the + * effect of freezing does not suppress the ability to override these + * properties on derived objects by simple assignment. + * + * Because of lack of sufficient foresight at the time, ES5 unfortunately + * specified that a simple assignment to a non-existent property must fail if + * it would override a non-writable data property of the same name. (In + * retrospect, this was a mistake, but it is now too late and we must live + * with the consequences.) As a result, simply freezing an object to make it + * tamper proof has the unfortunate side effect of breaking previously correct + * code that is considered to have followed JS best practices, if this + * previous code used assignment to override. + * + * To work around this mistake, deepFreeze(), prior to freezing, replaces + * selected configurable own data properties with accessor properties which + * simulate what we should have specified -- that assignments to derived + * objects succeed if otherwise possible. + */ +function beMutable(obj, prop, desc) { + if ('value' in desc && desc.configurable) { + const value = desc.value; + + // eslint-disable-next-line no-inner-declarations + function getter() { + return value; + } + + // Re-attach the data property on the object so + // it can be found by the deep-freeze traversal process. + getter.value = value; + + // eslint-disable-next-line no-inner-declarations + function setter(newValue) { + if (obj === this) { + throw new TypeError(`Cannot assign to read only property '${prop}' of object '${obj}'`); + } + if (objectHasOwnProperty.call(this, prop)) { + this[prop] = newValue; + } else { + defineProperty(this, prop, { + value: newValue, + writable: true, + enumerable: desc.enumerable, + configurable: desc.configurable + }); + } + } + + defineProperty(obj, prop, { + get: getter, + set: setter, + enumerable: desc.enumerable, + configurable: desc.configurable + }); + } +} + +export function beMutableProperties(obj) { + if (!obj) { + return; + } + const descs = getOwnPropertyDescriptors(obj); + if (!descs) { + return; + } + getOwnPropertyNames(obj).forEach(prop => beMutable(obj, prop, descs[prop])); + getOwnPropertySymbols(obj).forEach(prop => beMutable(obj, prop, descs[prop])); +} + +export function beMutableProperty(obj, prop) { + const desc = getOwnPropertyDescriptor(obj, prop); + beMutable(obj, prop, desc); +} + +/** + * These properties are subject to the override mistake + * and must be converted before freezing. + */ +export function repairDataProperties(intrinsics) { + const i = intrinsics; + + [ + i.ObjectPrototype, + i.ArrayPrototype, + i.BooleanPrototype, + i.DatePrototype, + i.NumberPrototype, + i.StringPrototype, + + i.FunctionPrototype, + i.GeneratorPrototype, + i.AsyncFunctionPrototype, + i.AsyncGeneratorPrototype, + + i.IteratorPrototype, + i.ArrayIteratorPrototype, + + i.PromisePrototype, + i.DataViewPrototype, + + i.TypedArray, + i.Int8ArrayPrototype, + i.Int16ArrayPrototype, + i.Int32ArrayPrototype, + i.Uint8Array, + i.Uint16Array, + i.Uint32Array, + + i.ErrorPrototype, + i.EvalErrorPrototype, + i.RangeErrorPrototype, + i.ReferenceErrorPrototype, + i.SyntaxErrorPrototype, + i.TypeErrorPrototype, + i.URIErrorPrototype + ].forEach(beMutableProperties); +} \ No newline at end of file From aa68ac8468ecabbdeccfb8ec3000180039f72f45 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 26 Aug 2019 12:02:17 +0800 Subject: [PATCH 2/9] repairDataProperties on intrinsics before harden --- src/bundle/createSES.js | 3 ++ src/bundle/mutable.js | 84 +++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/bundle/createSES.js b/src/bundle/createSES.js index 1b14d77..5553a4c 100644 --- a/src/bundle/createSES.js +++ b/src/bundle/createSES.js @@ -24,6 +24,8 @@ import getAllPrimordials from './getAllPrimordials'; import whitelist from './whitelist'; import makeConsole from './make-console'; import makeMakeRequire from './make-require'; +import { repairDataProperties } from './mutable'; + const FORWARDED_REALMS_OPTIONS = ['sloppyGlobals', 'transforms']; @@ -130,6 +132,7 @@ export function createSESWithRealmConstructor(creatorStrings, Realm) { r.global, anonIntrinsics, ); + repairDataProperties(allIntrinsics); harden(allIntrinsics); // build the makeRequire helper, glue it to the new Realm diff --git a/src/bundle/mutable.js b/src/bundle/mutable.js index 381876d..cc720d2 100644 --- a/src/bundle/mutable.js +++ b/src/bundle/mutable.js @@ -4,13 +4,12 @@ // https://github.com/google/caja/blob/master/src/com/google/caja/ses/repairES5.js import { - defineProperty, + defineProperties, getOwnPropertyDescriptor, getOwnPropertyDescriptors, - getOwnPropertyNames, - getOwnPropertySymbols, + ownKeys, objectHasOwnProperty -} from '../realms-shim/src/commons'; +} from '../../realms-shim/src/commons'; /** @@ -79,8 +78,7 @@ export function beMutableProperties(obj) { if (!descs) { return; } - getOwnPropertyNames(obj).forEach(prop => beMutable(obj, prop, descs[prop])); - getOwnPropertySymbols(obj).forEach(prop => beMutable(obj, prop, descs[prop])); + ownKeys(obj).forEach(prop => beMutable(obj, prop, descs[prop])); } export function beMutableProperty(obj, prop) { @@ -93,41 +91,47 @@ export function beMutableProperty(obj, prop) { * and must be converted before freezing. */ export function repairDataProperties(intrinsics) { - const i = intrinsics; + const { global: g, anonIntrinsics: a } = intrinsics; [ - i.ObjectPrototype, - i.ArrayPrototype, - i.BooleanPrototype, - i.DatePrototype, - i.NumberPrototype, - i.StringPrototype, - - i.FunctionPrototype, - i.GeneratorPrototype, - i.AsyncFunctionPrototype, - i.AsyncGeneratorPrototype, - - i.IteratorPrototype, - i.ArrayIteratorPrototype, - - i.PromisePrototype, - i.DataViewPrototype, - - i.TypedArray, - i.Int8ArrayPrototype, - i.Int16ArrayPrototype, - i.Int32ArrayPrototype, - i.Uint8Array, - i.Uint16Array, - i.Uint32Array, - - i.ErrorPrototype, - i.EvalErrorPrototype, - i.RangeErrorPrototype, - i.ReferenceErrorPrototype, - i.SyntaxErrorPrototype, - i.TypeErrorPrototype, - i.URIErrorPrototype + g.Object.prototype, + g.Array.prototype, + g.Boolean.prototype, + g.Date.prototype, + g.Number.prototype, + g.String.prototype, + + g.Function.prototype, + a.GeneratorFunction.prototype, + a.AsyncFunction.prototype, + a.AsyncGeneratorFunction.prototype, + + a.IteratorPrototype, + a.ArrayIteratorPrototype, + + g.Promise.prototype, + g.DataView.prototype, + + a.TypedArray, + g.Int8Array.prototype, + g.Int16Array.prototype, + g.Int32Array.prototype, + g.Uint8Array, + g.Uint16Array, + g.Uint32Array, + + g.Error.prototype, + g.EvalError.prototype, + g.RangeError.prototype, + g.ReferenceError.prototype, + g.SyntaxError.prototype, + g.TypeError.prototype, + g.URIError.prototype ].forEach(beMutableProperties); +} + +// Object.defineProperty is allowed to fail silently, +// wrap Object.defineProperties instead. +function defineProperty (obj, prop, desc) { + defineProperties(obj, { [prop]: desc }); } \ No newline at end of file From 014fda1b42d6198fe763390f89516060edc08be9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 26 Aug 2019 12:23:58 +0800 Subject: [PATCH 3/9] create repairDataProperties in SES via makeRepairDataProperties --- src/bundle/createSES.js | 6 +- src/bundle/mutable.js | 257 +++++++++++++++++++++------------------- 2 files changed, 139 insertions(+), 124 deletions(-) diff --git a/src/bundle/createSES.js b/src/bundle/createSES.js index 5553a4c..7e3042d 100644 --- a/src/bundle/createSES.js +++ b/src/bundle/createSES.js @@ -24,7 +24,7 @@ import getAllPrimordials from './getAllPrimordials'; import whitelist from './whitelist'; import makeConsole from './make-console'; import makeMakeRequire from './make-require'; -import { repairDataProperties } from './mutable'; +import makeRepairDataProperties from './mutable'; const FORWARDED_REALMS_OPTIONS = ['sloppyGlobals', 'transforms']; @@ -111,6 +111,9 @@ export function createSESWithRealmConstructor(creatorStrings, Realm) { const r = Realm.makeRootRealm({ ...realmsOptions, shims }); + const makeRepairDataPropertiesSrc = `(${makeRepairDataProperties})` + const repairDataProperties = r.evaluate(makeRepairDataPropertiesSrc)() + // Build a harden() with an empty fringe. It will be populated later when // we call harden(allIntrinsics). const makeHardenerSrc = `(${makeHardener})`; @@ -132,6 +135,7 @@ export function createSESWithRealmConstructor(creatorStrings, Realm) { r.global, anonIntrinsics, ); + repairDataProperties(allIntrinsics); harden(allIntrinsics); diff --git a/src/bundle/mutable.js b/src/bundle/mutable.js index cc720d2..c60413f 100644 --- a/src/bundle/mutable.js +++ b/src/bundle/mutable.js @@ -3,135 +3,146 @@ // https://github.com/google/caja/blob/master/src/com/google/caja/ses/startSES.js // https://github.com/google/caja/blob/master/src/com/google/caja/ses/repairES5.js -import { - defineProperties, - getOwnPropertyDescriptor, - getOwnPropertyDescriptors, - ownKeys, - objectHasOwnProperty -} from '../../realms-shim/src/commons'; - - -/** - * For a special set of properties (defined below), it ensures that the - * effect of freezing does not suppress the ability to override these - * properties on derived objects by simple assignment. - * - * Because of lack of sufficient foresight at the time, ES5 unfortunately - * specified that a simple assignment to a non-existent property must fail if - * it would override a non-writable data property of the same name. (In - * retrospect, this was a mistake, but it is now too late and we must live - * with the consequences.) As a result, simply freezing an object to make it - * tamper proof has the unfortunate side effect of breaking previously correct - * code that is considered to have followed JS best practices, if this - * previous code used assignment to override. - * - * To work around this mistake, deepFreeze(), prior to freezing, replaces - * selected configurable own data properties with accessor properties which - * simulate what we should have specified -- that assignments to derived - * objects succeed if otherwise possible. - */ -function beMutable(obj, prop, desc) { - if ('value' in desc && desc.configurable) { - const value = desc.value; - - // eslint-disable-next-line no-inner-declarations - function getter() { - return value; - } - - // Re-attach the data property on the object so - // it can be found by the deep-freeze traversal process. - getter.value = value; - - // eslint-disable-next-line no-inner-declarations - function setter(newValue) { - if (obj === this) { - throw new TypeError(`Cannot assign to read only property '${prop}' of object '${obj}'`); +export default function makeRepairDataProperties () { + + const { + defineProperties, + getOwnPropertyDescriptor, + getOwnPropertyDescriptors, + hasOwnProperty + } = Object; + const { ownKeys } = Reflect; + + /** + * For a special set of properties (defined below), it ensures that the + * effect of freezing does not suppress the ability to override these + * properties on derived objects by simple assignment. + * + * Because of lack of sufficient foresight at the time, ES5 unfortunately + * specified that a simple assignment to a non-existent property must fail if + * it would override a non-writable data property of the same name. (In + * retrospect, this was a mistake, but it is now too late and we must live + * with the consequences.) As a result, simply freezing an object to make it + * tamper proof has the unfortunate side effect of breaking previously correct + * code that is considered to have followed JS best practices, if this + * previous code used assignment to override. + * + * To work around this mistake, deepFreeze(), prior to freezing, replaces + * selected configurable own data properties with accessor properties which + * simulate what we should have specified -- that assignments to derived + * objects succeed if otherwise possible. + */ + function beMutable(obj, prop, desc) { + if ('value' in desc && desc.configurable) { + const value = desc.value; + + // eslint-disable-next-line no-inner-declarations + function getter() { + return value; } - if (objectHasOwnProperty.call(this, prop)) { - this[prop] = newValue; - } else { - defineProperty(this, prop, { - value: newValue, - writable: true, - enumerable: desc.enumerable, - configurable: desc.configurable - }); + + // Re-attach the data property on the object so + // it can be found by the deep-freeze traversal process. + getter.value = value; + + // eslint-disable-next-line no-inner-declarations + function setter(newValue) { + if (obj === this) { + throw new TypeError(`Cannot assign to read only property '${prop}' of object '${obj}'`); + } + if (hasOwnProperty.call(this, prop)) { + this[prop] = newValue; + } else { + defineProperty(this, prop, { + value: newValue, + writable: true, + enumerable: desc.enumerable, + configurable: desc.configurable + }); + } } + + defineProperty(obj, prop, { + get: getter, + set: setter, + enumerable: desc.enumerable, + configurable: desc.configurable + }); + } + } + + function beMutableProperties(obj) { + if (!obj) { + return; + } + const descs = getOwnPropertyDescriptors(obj); + if (!descs) { + return; } + ownKeys(obj).forEach(prop => beMutable(obj, prop, descs[prop])); + } - defineProperty(obj, prop, { - get: getter, - set: setter, - enumerable: desc.enumerable, - configurable: desc.configurable - }); + function beMutableProperty(obj, prop) { + const desc = getOwnPropertyDescriptor(obj, prop); + beMutable(obj, prop, desc); } -} -export function beMutableProperties(obj) { - if (!obj) { - return; + /** + * These properties are subject to the override mistake + * and must be converted before freezing. + */ + function repairDataProperties(intrinsics) { + const { global: g, anonIntrinsics: a } = intrinsics; + + const toBeRepaired = [ + g.Object.prototype, + g.Array.prototype, + g.Boolean.prototype, + g.Date.prototype, + g.Number.prototype, + g.String.prototype, + + g.Function.prototype, + a.GeneratorFunction.prototype, + a.AsyncFunction.prototype, + a.AsyncGeneratorFunction.prototype, + + a.IteratorPrototype, + a.ArrayIteratorPrototype, + + g.DataView.prototype, + + a.TypedArray, + g.Int8Array.prototype, + g.Int16Array.prototype, + g.Int32Array.prototype, + g.Uint8Array, + g.Uint16Array, + g.Uint32Array, + + g.Error.prototype, + g.EvalError.prototype, + g.RangeError.prototype, + g.ReferenceError.prototype, + g.SyntaxError.prototype, + g.TypeError.prototype, + g.URIError.prototype + ] + + // Promise may be removed from the whitelist + const PromisePrototype = g.Promise && g.Promise.prototype; + if (PromisePrototype) { + toBeRepaired.push(PromisePrototype) + } + + toBeRepaired.forEach(beMutableProperties); } - const descs = getOwnPropertyDescriptors(obj); - if (!descs) { - return; + + // Object.defineProperty is allowed to fail silently, + // wrap Object.defineProperties instead. + function defineProperty (obj, prop, desc) { + defineProperties(obj, { [prop]: desc }); } - ownKeys(obj).forEach(prop => beMutable(obj, prop, descs[prop])); -} - -export function beMutableProperty(obj, prop) { - const desc = getOwnPropertyDescriptor(obj, prop); - beMutable(obj, prop, desc); -} - -/** - * These properties are subject to the override mistake - * and must be converted before freezing. - */ -export function repairDataProperties(intrinsics) { - const { global: g, anonIntrinsics: a } = intrinsics; - - [ - g.Object.prototype, - g.Array.prototype, - g.Boolean.prototype, - g.Date.prototype, - g.Number.prototype, - g.String.prototype, - - g.Function.prototype, - a.GeneratorFunction.prototype, - a.AsyncFunction.prototype, - a.AsyncGeneratorFunction.prototype, - - a.IteratorPrototype, - a.ArrayIteratorPrototype, - - g.Promise.prototype, - g.DataView.prototype, - - a.TypedArray, - g.Int8Array.prototype, - g.Int16Array.prototype, - g.Int32Array.prototype, - g.Uint8Array, - g.Uint16Array, - g.Uint32Array, - - g.Error.prototype, - g.EvalError.prototype, - g.RangeError.prototype, - g.ReferenceError.prototype, - g.SyntaxError.prototype, - g.TypeError.prototype, - g.URIError.prototype - ].forEach(beMutableProperties); -} - -// Object.defineProperty is allowed to fail silently, -// wrap Object.defineProperties instead. -function defineProperty (obj, prop, desc) { - defineProperties(obj, { [prop]: desc }); + + return repairDataProperties; } \ No newline at end of file From 3108ad88de20442119df3e73f2f33fee972b381e Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 26 Aug 2019 12:46:53 +0800 Subject: [PATCH 4/9] lint fix --- src/bundle/createSES.js | 5 ++--- src/bundle/mutable.js | 41 ++++++++++++++++++----------------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/bundle/createSES.js b/src/bundle/createSES.js index 7e3042d..5ab9014 100644 --- a/src/bundle/createSES.js +++ b/src/bundle/createSES.js @@ -26,7 +26,6 @@ import makeConsole from './make-console'; import makeMakeRequire from './make-require'; import makeRepairDataProperties from './mutable'; - const FORWARDED_REALMS_OPTIONS = ['sloppyGlobals', 'transforms']; export function createSESWithRealmConstructor(creatorStrings, Realm) { @@ -111,8 +110,8 @@ export function createSESWithRealmConstructor(creatorStrings, Realm) { const r = Realm.makeRootRealm({ ...realmsOptions, shims }); - const makeRepairDataPropertiesSrc = `(${makeRepairDataProperties})` - const repairDataProperties = r.evaluate(makeRepairDataPropertiesSrc)() + const makeRepairDataPropertiesSrc = `(${makeRepairDataProperties})`; + const repairDataProperties = r.evaluate(makeRepairDataPropertiesSrc)(); // Build a harden() with an empty fringe. It will be populated later when // we call harden(allIntrinsics). diff --git a/src/bundle/mutable.js b/src/bundle/mutable.js index c60413f..12a92f1 100644 --- a/src/bundle/mutable.js +++ b/src/bundle/mutable.js @@ -3,16 +3,20 @@ // https://github.com/google/caja/blob/master/src/com/google/caja/ses/startSES.js // https://github.com/google/caja/blob/master/src/com/google/caja/ses/repairES5.js -export default function makeRepairDataProperties () { - +export default function makeRepairDataProperties() { const { defineProperties, - getOwnPropertyDescriptor, getOwnPropertyDescriptors, - hasOwnProperty + hasOwnProperty, } = Object; const { ownKeys } = Reflect; + // Object.defineProperty is allowed to fail silently, + // wrap Object.defineProperties instead. + function defineProperty(obj, prop, desc) { + defineProperties(obj, { [prop]: desc }); + } + /** * For a special set of properties (defined below), it ensures that the * effect of freezing does not suppress the ability to override these @@ -34,7 +38,7 @@ export default function makeRepairDataProperties () { */ function beMutable(obj, prop, desc) { if ('value' in desc && desc.configurable) { - const value = desc.value; + const { value } = desc; // eslint-disable-next-line no-inner-declarations function getter() { @@ -48,7 +52,9 @@ export default function makeRepairDataProperties () { // eslint-disable-next-line no-inner-declarations function setter(newValue) { if (obj === this) { - throw new TypeError(`Cannot assign to read only property '${prop}' of object '${obj}'`); + throw new TypeError( + `Cannot assign to read only property '${prop}' of object '${obj}'`, + ); } if (hasOwnProperty.call(this, prop)) { this[prop] = newValue; @@ -57,7 +63,7 @@ export default function makeRepairDataProperties () { value: newValue, writable: true, enumerable: desc.enumerable, - configurable: desc.configurable + configurable: desc.configurable, }); } } @@ -66,7 +72,7 @@ export default function makeRepairDataProperties () { get: getter, set: setter, enumerable: desc.enumerable, - configurable: desc.configurable + configurable: desc.configurable, }); } } @@ -82,11 +88,6 @@ export default function makeRepairDataProperties () { ownKeys(obj).forEach(prop => beMutable(obj, prop, descs[prop])); } - function beMutableProperty(obj, prop) { - const desc = getOwnPropertyDescriptor(obj, prop); - beMutable(obj, prop, desc); - } - /** * These properties are subject to the override mistake * and must be converted before freezing. @@ -126,23 +127,17 @@ export default function makeRepairDataProperties () { g.ReferenceError.prototype, g.SyntaxError.prototype, g.TypeError.prototype, - g.URIError.prototype - ] + g.URIError.prototype, + ]; // Promise may be removed from the whitelist const PromisePrototype = g.Promise && g.Promise.prototype; if (PromisePrototype) { - toBeRepaired.push(PromisePrototype) + toBeRepaired.push(PromisePrototype); } toBeRepaired.forEach(beMutableProperties); } - // Object.defineProperty is allowed to fail silently, - // wrap Object.defineProperties instead. - function defineProperty (obj, prop, desc) { - defineProperties(obj, { [prop]: desc }); - } - return repairDataProperties; -} \ No newline at end of file +} From 25d136985e75fab3ab04185daaef4b81fed797ad Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 26 Aug 2019 16:28:45 +0800 Subject: [PATCH 5/9] repairDataProperties - add TypedArray.prototype --- src/bundle/mutable.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bundle/mutable.js b/src/bundle/mutable.js index 12a92f1..96625b5 100644 --- a/src/bundle/mutable.js +++ b/src/bundle/mutable.js @@ -114,6 +114,7 @@ export default function makeRepairDataProperties() { g.DataView.prototype, a.TypedArray, + a.TypedArray.prototype, g.Int8Array.prototype, g.Int16Array.prototype, g.Int32Array.prototype, From 2fa711d64a0cff9b992b4bb341f3974be39d181e Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Aug 2019 10:44:06 +0800 Subject: [PATCH 6/9] rename mutable to makeRepairDataProperties + beMutable to enableDerivedOverride --- src/bundle/createSES.js | 2 +- ...mutable.js => makeRepairDataProperties.js} | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) rename src/bundle/{mutable.js => makeRepairDataProperties.js} (89%) diff --git a/src/bundle/createSES.js b/src/bundle/createSES.js index a6ad5a9..7bf84fd 100644 --- a/src/bundle/createSES.js +++ b/src/bundle/createSES.js @@ -24,7 +24,7 @@ import getAllPrimordials from './getAllPrimordials'; import whitelist from './whitelist'; import makeConsole from './make-console'; import makeMakeRequire from './make-require'; -import makeRepairDataProperties from './mutable'; +import makeRepairDataProperties from './makeRepairDataProperties'; const FORWARDED_REALMS_OPTIONS = ['transforms']; diff --git a/src/bundle/mutable.js b/src/bundle/makeRepairDataProperties.js similarity index 89% rename from src/bundle/mutable.js rename to src/bundle/makeRepairDataProperties.js index 96625b5..61e4a11 100644 --- a/src/bundle/mutable.js +++ b/src/bundle/makeRepairDataProperties.js @@ -36,7 +36,7 @@ export default function makeRepairDataProperties() { * simulate what we should have specified -- that assignments to derived * objects succeed if otherwise possible. */ - function beMutable(obj, prop, desc) { + function enableDerivedOverride(obj, prop, desc) { if ('value' in desc && desc.configurable) { const { value } = desc; @@ -77,17 +77,6 @@ export default function makeRepairDataProperties() { } } - function beMutableProperties(obj) { - if (!obj) { - return; - } - const descs = getOwnPropertyDescriptors(obj); - if (!descs) { - return; - } - ownKeys(obj).forEach(prop => beMutable(obj, prop, descs[prop])); - } - /** * These properties are subject to the override mistake * and must be converted before freezing. @@ -132,12 +121,26 @@ export default function makeRepairDataProperties() { ]; // Promise may be removed from the whitelist + // TODO: the toBeRepaired list should be prepared + // externally and provided to repairDataProperties const PromisePrototype = g.Promise && g.Promise.prototype; if (PromisePrototype) { toBeRepaired.push(PromisePrototype); } - toBeRepaired.forEach(beMutableProperties); + // repair each entry + toBeRepaired.forEach(obj => { + if (!obj) { + return; + } + const descs = getOwnPropertyDescriptors(obj); + if (!descs) { + return; + } + ownKeys(obj).forEach(prop => + enableDerivedOverride(obj, prop, descs[prop]), + ); + }); } return repairDataProperties; From 31ea20953b5f6d842af221fd1151e3524659d074 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Aug 2019 10:53:38 +0800 Subject: [PATCH 7/9] adjust toBeRepaired set for repairDataProperties --- src/bundle/makeRepairDataProperties.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bundle/makeRepairDataProperties.js b/src/bundle/makeRepairDataProperties.js index 61e4a11..800c425 100644 --- a/src/bundle/makeRepairDataProperties.js +++ b/src/bundle/makeRepairDataProperties.js @@ -91,6 +91,7 @@ export default function makeRepairDataProperties() { g.Date.prototype, g.Number.prototype, g.String.prototype, + g.RegExp.prototype, g.Function.prototype, a.GeneratorFunction.prototype, @@ -102,14 +103,13 @@ export default function makeRepairDataProperties() { g.DataView.prototype, - a.TypedArray, a.TypedArray.prototype, g.Int8Array.prototype, g.Int16Array.prototype, g.Int32Array.prototype, - g.Uint8Array, - g.Uint16Array, - g.Uint32Array, + g.Uint8Array.prototype, + g.Uint16Array.prototype, + g.Uint32Array.prototype, g.Error.prototype, g.EvalError.prototype, From 39a7372122ff45b03eed95309cfa784dd26ebd8d Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Aug 2019 11:08:24 +0800 Subject: [PATCH 8/9] add basic tests for repairDataProperties --- test/test-repairDataProperties.js | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 test/test-repairDataProperties.js diff --git a/test/test-repairDataProperties.js b/test/test-repairDataProperties.js new file mode 100644 index 0000000..2c5cb93 --- /dev/null +++ b/test/test-repairDataProperties.js @@ -0,0 +1,53 @@ +import test from 'tape'; +import SES from '../src/index'; + +test('Can assign "toString" of constructor prototype', t => { + const s = SES.makeSESRootRealm(); + function testContent() { + function Animal() {} + Animal.prototype.toString = () => 'moo'; + const animal = new Animal(); + return animal.toString(); + } + try { + const result = s.evaluate(`(${testContent})`)(); + t.equal(result, 'moo'); + } catch (err) { + t.fail(err); + } + t.end(); +}); + +test('Can assign "toString" of class prototype', t => { + const s = SES.makeSESRootRealm(); + function testContent() { + class Animal {} + Animal.prototype.toString = () => 'moo'; + const animal = new Animal(); + return animal.toString(); + } + try { + const result = s.evaluate(`(${testContent})`)(); + t.equal(result, 'moo'); + } catch (err) { + t.fail(err); + } + t.end(); +}); + +test('Can assign "slice" of Array-inherited class prototype', t => { + const s = SES.makeSESRootRealm(); + function testContent() { + class Pizza extends Array {} + Pizza.prototype.slice = () => ['yum']; + const pizza = new Pizza(); + return pizza.slice(); + } + try { + const result = s.evaluate(`(${testContent})`)(); + t.deepEqual(result, ['yum']); + } catch (err) { + t.fail(err); + } + t.end(); +}); From c962e271587d9e6b6728023054bdc55881832540 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Aug 2019 12:43:55 +0800 Subject: [PATCH 9/9] minimize toBeRepaired list for repairDataProperties --- src/bundle/makeRepairDataProperties.js | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/bundle/makeRepairDataProperties.js b/src/bundle/makeRepairDataProperties.js index 800c425..83b7f59 100644 --- a/src/bundle/makeRepairDataProperties.js +++ b/src/bundle/makeRepairDataProperties.js @@ -87,11 +87,11 @@ export default function makeRepairDataProperties() { const toBeRepaired = [ g.Object.prototype, g.Array.prototype, - g.Boolean.prototype, - g.Date.prototype, - g.Number.prototype, - g.String.prototype, - g.RegExp.prototype, + // g.Boolean.prototype, + // g.Date.prototype, + // g.Number.prototype, + // g.String.prototype, + // g.RegExp.prototype, g.Function.prototype, a.GeneratorFunction.prototype, @@ -99,25 +99,25 @@ export default function makeRepairDataProperties() { a.AsyncGeneratorFunction.prototype, a.IteratorPrototype, - a.ArrayIteratorPrototype, + // a.ArrayIteratorPrototype, - g.DataView.prototype, + // g.DataView.prototype, a.TypedArray.prototype, - g.Int8Array.prototype, - g.Int16Array.prototype, - g.Int32Array.prototype, - g.Uint8Array.prototype, - g.Uint16Array.prototype, - g.Uint32Array.prototype, + // g.Int8Array.prototype, + // g.Int16Array.prototype, + // g.Int32Array.prototype, + // g.Uint8Array.prototype, + // g.Uint16Array.prototype, + // g.Uint32Array.prototype, g.Error.prototype, - g.EvalError.prototype, - g.RangeError.prototype, - g.ReferenceError.prototype, - g.SyntaxError.prototype, - g.TypeError.prototype, - g.URIError.prototype, + // g.EvalError.prototype, + // g.RangeError.prototype, + // g.ReferenceError.prototype, + // g.SyntaxError.prototype, + // g.TypeError.prototype, + // g.URIError.prototype, ]; // Promise may be removed from the whitelist