Allow re-invocation of lockdown()
MODIFY
packages/lockdown-shim/src/main.js
packages/lockdown-shim/src/main.js
@@ -26,6 +26,14 @@ import enablePropertyOverrides from '@agoric/enable-property-overrides';
import makeHardener from '@agoric/make-hardener';
import Compartment from '@agoric/compartment-shim';
+let previousOptions;
+
+function assert(condition, message) {
+ if (!condition) {
+ throw new TypeError(message);
+ }
+}
+
export function lockdown(options = {}) {
const {
noTameDate = false,
@@ -33,8 +41,41 @@ export function lockdown(options = {}) {
noTameMath = false,
noTameRegExp = false,
registerOnly = false,
+ ...extraOptions
} = options;
+ // Assert that only supported options were passed.
+
+ const extraOptionsNames = Object.keys(extraOptions);
+ assert(
+ extraOptionsNames.length === 0,
+ `lockdown(): non supported option ${extraOptionsNames.join(', ')}`,
+ );
+
+ // Asserts for multiple invocation of lockdown().
+
+ const currentOptions = {
+ noTameDate,
+ noTameError,
+ noTameMath,
+ noTameRegExp,
+ registerOnly,
+ };
+ if (previousOptions) {
+ // Assert that multiple invocation have the same value
+ Object.keys(currentOptions).forEach(name => {
+ assert(
+ currentOptions[name] === previousOptions[name],
+ `lockdown(): cannot re-invoke with different option ${name}`,
+ );
+ });
+
+ // Returning `false` indicates that lockdown() made no changes because it
+ // was invokes from SES with the same options.
+ return false;
+ }
+ previousOptions = currentOptions;
+
/**
* 1. TAME powers first.
*/
@@ -104,4 +145,7 @@ export function lockdown(options = {}) {
// must be the operation that modifies the intrinsics.
harden(intrinsics, registerOnly);
harden(detachedProperties, registerOnly);
+
+ // Returning `true` indicates that this is a JS to SES transition.
+ return true;
}

ADD
packages/lockdown-shim/test/lockdown-allow.test.js
+import test from 'tape';
+import { lockdown } from '../src/main.js';
+
+test('lockdown returns boolean or throws in downgraded SES', t => {
+ t.plan(7);
+
+ t.ok(
+ lockdown({
+ noTameDate: true,
+ noTameError: true,
+ noTameMath: true,
+ noTameRegExp: true,
+ }),
+ 'return true when called from JS with options',
+ );
+
+ t.notOk(
+ lockdown({
+ noTameDate: true,
+ noTameError: true,
+ noTameMath: true,
+ noTameRegExp: true,
+ }),
+ 'return false when called from SES with the same options',
+ );
+
+ t.throws(
+ () => lockdown(),
+ 'throws when when called from SES with different options',
+ );
+
+ t.throws(
+ () =>
+ lockdown({
+ noTameError: true,
+ noTameMath: true,
+ noTameRegExp: true,
+ }),
+ 'throws when attempting to tame Date',
+ );
+
+ t.throws(
+ () =>
+ lockdown({
+ noTameDate: true,
+ noTameMath: true,
+ noTameRegExp: true,
+ }),
+ 'throws when attempting to tame Error',
+ );
+
+ t.throws(
+ () =>
+ lockdown({
+ noTameDate: true,
+ noTameError: true,
+ noTameRegExp: true,
+ }),
+ 'throws when attempting to tame Math',
+ );
+
+ t.throws(
+ () =>
+ lockdown({
+ noTameDate: true,
+ noTameError: true,
+ noTameMath: true,
+ }),
+ 'throws when attempting to tame RegExp',
+ );
+});

ADD
packages/lockdown-shim/test/lockdown-options.test.js
+import test from 'tape';
+import { lockdown } from '../src/main.js';
+
+test('lockdown throws with non-recognized options', t => {
+ t.plan(2);
+
+ t.throws(
+ () => lockdown({ noTameMath: true, abc: true }),
+ 'throws with value true',
+ );
+ t.throws(
+ () => lockdown({ noTameMath: true, abc: false }),
+ 'throws with value false',
+ );
+});

ADD
packages/lockdown-shim/test/lockdown.test.js
+import test from 'tape';
+import { lockdown } from '../src/main.js';
+
+test('lockdown returns boolean or throws in SES', t => {
+ t.plan(6);
+
+ t.ok(lockdown(), 'return true when called from JS without options');
+ t.notOk(
+ lockdown(),
+ 'return false when called from SES with the same options',
+ );
+ t.throws(
+ () => lockdown({ noTameDate: true }),
+ 'throws when attempting to untame Date',
+ );
+ t.throws(
+ () => lockdown({ noTameError: true }),
+ 'throws when attempting to untame Error',
+ );
+ t.throws(
+ () => lockdown({ noTameMath: true }),
+ 'throws when attempting to untame Math',
+ );
+ t.throws(
+ () => lockdown({ noTameRegExp: true }),
+ 'throws when attempting to untame RegExp',
+ );
+});

Allow re-invocation of lockdown() (#198)