createSES: allow options.dataPropertiesToRepair to override repair plan
MODIFY
src/bundle/createSES.js
src/bundle/createSES.js
@@ -36,6 +36,7 @@ export function createSESWithRealmConstructor(creatorStrings, Realm) {
const shims = [];
const {
+ dataPropertiesToRepair: optDataPropertiesToRepair,
shims: optionalShims,
sloppyGlobals,
whitelist: optWhitelist,
@@ -137,15 +138,22 @@ You probably want a Compartment instead, like:
r.global.console = r.evaluate(s)(console);
}
- // Finally freeze all the primordials, and the global object. This must
- // be the last thing we do that modifies the Realm's globals.
+ // Gather the primordials and global.
const anonIntrinsics = r.evaluate(`(${getAnonIntrinsics})`)(r.global);
const allIntrinsics = r.evaluate(`(${getAllPrimordials})`)(
r.global,
anonIntrinsics,
);
- repairDataProperties(allIntrinsics, dataPropertiesToRepair);
+ // Repair the override mistake on the primordials and global.
+ const repairPlan =
+ optDataPropertiesToRepair !== undefined
+ ? optDataPropertiesToRepair
+ : dataPropertiesToRepair;
+ repairDataProperties(allIntrinsics, repairPlan);
+
+ // Finally freeze all the primordials, and the global object. This must
+ // be the last thing we do that modifies the Realm's globals.
harden(allIntrinsics);
// build the makeRequire helper, glue it to the new Realm

MODIFY
src/bundle/makeRepairDataProperties.js
src/bundle/makeRepairDataProperties.js
@@ -88,6 +88,9 @@ export default function makeRepairDataProperties() {
}
function repairAllProperties(obj) {
+ if (!obj) {
+ return;
+ }
const descs = getOwnPropertyDescriptors(obj);
if (!descs) {
return;

MODIFY
test/test-repairDataProperties.js
test/test-repairDataProperties.js
@@ -35,6 +35,51 @@ test('Can assign "toString" of class prototype', t => {
t.end();
});
+test('override options.dataPropertiesToRepair', t => {
+ try {
+ // eslint-disable-next-line no-inner-declarations
+ function testContent() {
+ class Pizza extends Array {}
+ Pizza.prototype.slice = () => ['yum'];
+ const pizza = new Pizza();
+ return pizza.slice();
+ }
+
+ const sesNone = SES.makeSESRootRealm({ dataPropertiesToRepair: false });
+ t.throws(
+ () => sesNone.evaluate(`(${testContent})`)(),
+ sesNone.global.TypeError,
+ 'cannot override unrepaired Array.slice',
+ );
+
+ const sesSingle = SES.makeSESRootRealm({
+ dataPropertiesToRepair: {
+ global: { Array: { prototype: { slice: true } } },
+ },
+ });
+ t.deepEqual(
+ sesSingle.evaluate(`(${testContent})`)(),
+ ['yum'],
+ 'can override single Array.slice repair',
+ );
+
+ const sesProto = SES.makeSESRootRealm({
+ dataPropertiesToRepair: {
+ global: { Array: { prototype: '*' } },
+ },
+ });
+ t.deepEqual(
+ sesProto.evaluate(`(${testContent})`)(),
+ ['yum'],
+ 'can override Array.prototype.* repair',
+ );
+ } catch (e) {
+ t.isNot(e, e, 'unexpected exception');
+ } finally {
+ t.end();
+ }
+});
+
test('Can assign "slice" of Array-inherited class prototype', t => {
const s = SES.makeSESRootRealm();
function testContent() {

createSES: allow options.dataPropertiesToRepair to override repair plan