Skip to content

Commit

Permalink
fix(326): accept old and new taming options during transition (#327)
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed May 21, 2020
1 parent 86a373e commit 67eb6e8
Show file tree
Hide file tree
Showing 18 changed files with 91 additions and 69 deletions.
9 changes: 8 additions & 1 deletion packages/ses/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ User-visible changes in SES:
world, and also allows its `t.throws` assertion to work. `tape` (version
5.x) still has problems. [#293]

[#293]: https://github.com/Agoric/SES-shim/issues/293)
* Replaces the old `noTame*` options to `lockdown` with new `*Taming` options.
The old style had boolean values defaulting to `false`. In the new style,
each option supports at least the options `'safe'` and `'unsafe'` defaulting
to `'safe'`. As a transitional matter, this release still supports the
old style as well, as another way to say the same thing. [#326]

[#293]: https://github.com/Agoric/SES-shim/issues/293
[#326]: https://github.com/Agoric/SES-shim/issues/326

## Release 0.7.7 (27-Apr-2020)

Expand Down
11 changes: 6 additions & 5 deletions packages/ses/demos/challenge/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ import('../../dist/ses.esm.js').then(({ lockdown }) => {
// 1. We build the SES Realm.
// ********************

const noTameDate = window.location.search.includes('dateNow=enabled');
$('#dateNowStatus').textContent = noTameDate
? 'Date.now() enabled'
: 'Date.now() returns NaN';
lockdown({ noTameDate });
const dateTaming = window.location.search.includes('dateNow=enabled')
? 'unsafe'
: 'safe';
$('#dateNowStatus').textContent =
dateTaming === 'unsafe' ? 'Date.now() enabled' : 'Date.now() returns NaN';
lockdown({ dateTaming });

// ********************
// 2. We prepare APIs for the defender code.
Expand Down
32 changes: 23 additions & 9 deletions packages/ses/src/lockdown-shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,27 @@ export const harden = ref => {
};

export function lockdown(options = {}) {
// The noTame* option names are the old way.
// The *Taming option names are the new way.
// During the transition we support both to say the same thing.

const {
// deprecated
noTameDate = false,
noTameError = false,
noTameMath = false,
noTameRegExp = false,

// use deprecated to set non-deprecated
dateTaming = noTameDate ? 'unsafe' : 'safe',
errorTaming = noTameError ? 'unsafe' : 'safe',
mathTaming = noTameMath ? 'unsafe' : 'safe',
regExpTaming = noTameRegExp ? 'unsafe' : 'safe',

...extraOptions
} = options;

// Assert that only supported options were passed.

const extraOptionsNames = Object.keys(extraOptions);
assert(
extraOptionsNames.length === 0,
Expand All @@ -61,13 +72,16 @@ export function lockdown(options = {}) {
// Asserts for multiple invocation of lockdown().

const currentOptions = {
noTameDate,
noTameError,
noTameMath,
noTameRegExp,
dateTaming,
errorTaming,
mathTaming,
regExpTaming,
};
if (previousOptions) {
// Assert that multiple invocation have the same value
// TODO after deprecated noTame* options are removed:
// Only enforce agreement for options that are present.
// See https://github.com/Agoric/SES-shim/issues/326
Object.keys(currentOptions).forEach(name => {
assert(
currentOptions[name] === previousOptions[name],
Expand All @@ -86,10 +100,10 @@ export function lockdown(options = {}) {
*/
tameFunctionConstructors();

tameGlobalDateObject(noTameDate);
tameGlobalErrorObject(noTameError);
tameGlobalMathObject(noTameMath);
tameGlobalRegExpObject(noTameRegExp);
tameGlobalDateObject(dateTaming);
tameGlobalErrorObject(errorTaming);
tameGlobalMathObject(mathTaming);
tameGlobalRegExpObject(regExpTaming);

/**
* 2. WHITELIST to standardize the environment.
Expand Down
7 changes: 5 additions & 2 deletions packages/ses/src/tame-global-date-object.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const { defineProperties } = Object;

export default function tameGlobalDateObject(noTameDate = false) {
if (noTameDate) {
export default function tameGlobalDateObject(dateTaming = 'safe') {
if (dateTaming === 'unsafe') {
return;
}
if (dateTaming !== 'safe') {
throw new Error(`unrecognized dateTaming ${dateTaming}`);
}

const unsafeDate = Date;

Expand Down
11 changes: 7 additions & 4 deletions packages/ses/src/tame-global-error-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ export const NativeErrors = [
URIError,
];

export default function tameGlobalErrorObject(noTameError = false) {
export default function tameGlobalErrorObject(errorTaming = 'safe') {
if (errorTaming !== 'safe' && errorTaming !== 'unsafe') {
throw new Error(`unrecognized errorTaming ${errorTaming}`);
}
const unsafeError = Error;

const tamedError = function Error(...rest) {
Expand All @@ -23,7 +26,7 @@ export default function tameGlobalErrorObject(noTameError = false) {
// Use concise methods to obtain named functions without constructors.
const tamedMethods = {
captureStackTrace(error, optFn = undefined) {
if (noTameError && unsafeError.captureStackTrace) {
if (errorTaming === 'unsafe' && unsafeError.captureStackTrace) {
// unsafeError.captureStackTrace is only on v8
unsafeError.captureStackTrace(error, optFn);
return;
Expand All @@ -49,14 +52,14 @@ export default function tameGlobalErrorObject(noTameError = false) {
},
stackTraceLimit: {
get() {
if (noTameError && unsafeError.stackTraceLimit) {
if (errorTaming === 'unsafe' && unsafeError.stackTraceLimit) {
// unsafeError.stackTraceLimit is only on v8
return unsafeError.stackTraceLimit;
}
return 0;
},
set(newLimit) {
if (noTameError && unsafeError.stackTraceLimit) {
if (errorTaming === 'unsafe' && unsafeError.stackTraceLimit) {
// unsafeError.stackTraceLimit is only on v8
unsafeError.stackTraceLimit = newLimit;
// We place the useless return on the next line to ensure
Expand Down
8 changes: 6 additions & 2 deletions packages/ses/src/tame-global-math-object.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
const { defineProperties } = Object;

export default function tameGlobalMathObject(noTameMath = false) {
if (noTameMath) {
export default function tameGlobalMathObject(mathTaming = 'safe') {
if (mathTaming === 'unsafe') {
return;
}
if (mathTaming !== 'safe') {
throw new Error(`unrecognized mathTaming ${mathTaming}`);
}

// Tame the %Math% intrinsic.

// Use concise methods to obtain named functions without constructors.
Expand Down
7 changes: 5 additions & 2 deletions packages/ses/src/tame-global-reg-exp-object.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const { defineProperties, getOwnPropertyDescriptor } = Object;

export default function tameGlobalRegExpObject(noTameRegExp = false) {
if (noTameRegExp) {
export default function tameGlobalRegExpObject(regExpTaming = 'safe') {
if (regExpTaming === 'unsafe') {
return;
}
if (regExpTaming !== 'safe') {
throw new Error(`unrecognized regExpTaming ${regExpTaming}`);
}

const unsafeRegExp = RegExp;

Expand Down
39 changes: 13 additions & 26 deletions packages/ses/test/lockdown-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,56 @@ import test from 'tape';
import { lockdown } from '../src/lockdown-shim.js';

test('lockdown returns boolean or throws in downgraded SES', t => {
t.plan(7);
t.plan(6);

t.ok(
lockdown({
noTameDate: true,
noTameError: true,
noTameMath: true,
noTameRegExp: true,
dateTaming: 'unsafe',
errorTaming: 'unsafe',
mathTaming: 'unsafe',
regExpTaming: 'unsafe',
}),
'return true when called from JS with options',
);

t.notOk(
lockdown({
noTameDate: true,
noTameError: true,
noTameMath: true,
noTameRegExp: true,
dateTaming: 'unsafe',
errorTaming: 'unsafe',
mathTaming: 'unsafe',
regExpTaming: 'unsafe',
}),
'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,
dateTaming: 'safe',
}),
'throws when attempting to tame Date',
);

t.throws(
() =>
lockdown({
noTameDate: true,
noTameMath: true,
noTameRegExp: true,
errorTaming: 'safe',
}),
'throws when attempting to tame Error',
);

t.throws(
() =>
lockdown({
noTameDate: true,
noTameError: true,
noTameRegExp: true,
mathTaming: 'safe',
}),
'throws when attempting to tame Math',
);

t.throws(
() =>
lockdown({
noTameDate: true,
noTameError: true,
noTameMath: true,
regExpTaming: 'safe',
}),
'throws when attempting to tame RegExp',
);
Expand Down
4 changes: 2 additions & 2 deletions packages/ses/test/lockdown-options.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ test('lockdown throws with non-recognized options', t => {
t.plan(2);

t.throws(
() => lockdown({ noTameMath: true, abc: true }),
() => lockdown({ mathTaming: 'unsafe', abc: true }),
'throws with value true',
);
t.throws(
() => lockdown({ noTameMath: true, abc: false }),
() => lockdown({ mathTaming: 'unsafe', abc: false }),
'throws with value false',
);
});
8 changes: 4 additions & 4 deletions packages/ses/test/lockdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ test('lockdown returns boolean or throws in SES', t => {
'return false when called from SES with the same options',
);
t.throws(
() => lockdown({ noTameDate: true }),
() => lockdown({ dateTaming: 'unsafe' }),
'throws when attempting to untame Date',
);
t.throws(
() => lockdown({ noTameError: true }),
() => lockdown({ errorTaming: 'unsafe' }),
'throws when attempting to untame Error',
);
t.throws(
() => lockdown({ noTameMath: true }),
() => lockdown({ mathTaming: 'unsafe' }),
'throws when attempting to untame Math',
);
t.throws(
() => lockdown({ noTameRegExp: true }),
() => lockdown({ regExpTaming: 'unsafe' }),
'throws when attempting to untame RegExp',
);

Expand Down
2 changes: 1 addition & 1 deletion packages/ses/test/tame-date-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import test from 'tape';
import '../src/main.js';

lockdown({ noTameDate: true });
lockdown({ dateTaming: 'unsafe' });

function isDate(date) {
return (
Expand Down
2 changes: 1 addition & 1 deletion packages/ses/test/tame-error-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import test from 'tape';
import '../src/main.js';

lockdown({ noTameError: true });
lockdown({ errorTaming: 'unsafe' });

test('lockdown allow Error - Error is not tamed', t => {
const c = new Compartment();
Expand Down
6 changes: 3 additions & 3 deletions packages/ses/test/tame-global-date-object-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { test } = tap;

test('tameGlobalDateObject - constructor without argument', t => {
const restore = captureGlobals('Date');
tameGlobalDateObject(true);
tameGlobalDateObject('unsafe');

t.equal(Date.name, 'Date');

Expand All @@ -24,7 +24,7 @@ test('tameGlobalDateObject - constructor without argument', t => {

test('tameGlobalDateObject - now', t => {
const restore = captureGlobals('Date');
tameGlobalDateObject(true);
tameGlobalDateObject('unsafe');

t.equal(Date.now.name, 'now');

Expand All @@ -38,7 +38,7 @@ test('tameGlobalDateObject - now', t => {

test('tameGlobalObject - toLocaleString', t => {
const restore = captureGlobals('Date');
tameGlobalDateObject(true);
tameGlobalDateObject('unsafe');

t.equal(Date.prototype.toLocaleString.name, 'toLocaleString');
t.equal(Object.prototype.toLocaleString.name, 'toLocaleString');
Expand Down
2 changes: 1 addition & 1 deletion packages/ses/test/tame-global-error-object-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test('tameGlobalErrorObject', t => {
const restore = captureGlobals('Error');

try {
tameGlobalErrorObject(true);
tameGlobalErrorObject('unsafe');

t.equal(typeof Error.stackTraceLimit, 'number');
Error.stackTraceLimit = 11;
Expand Down
2 changes: 1 addition & 1 deletion packages/ses/test/tame-global-math-object-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { test } = tap;

test('tameGlobalMathObject - tamed properties', t => {
const restore = captureGlobals('Math');
tameGlobalMathObject(true);
tameGlobalMathObject('unsafe');

t.equal(Math.random.name, 'random');

Expand Down
6 changes: 3 additions & 3 deletions packages/ses/test/tame-global-reg-exp-object-allow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { test } = tap;

test('tameGlobalRegExpObject - unsafeRegExp denied', t => {
const restore = captureGlobals('RegExp');
tameGlobalRegExpObject(true);
tameGlobalRegExpObject('unsafe');

const regexp = /./;
t.ok(regexp.constructor === RegExp, 'tamed constructor not reached');
Expand All @@ -17,7 +17,7 @@ test('tameGlobalRegExpObject - unsafeRegExp denied', t => {

test('tameGlobalRegExpObject - undeniable prototype', t => {
const restore = captureGlobals('RegExp');
tameGlobalRegExpObject(true);
tameGlobalRegExpObject('unsafe');

// Don't try to deny the undeniable
// https://github.com/Agoric/SES-shim/issues/237
Expand Down Expand Up @@ -54,7 +54,7 @@ test('tameGlobalRegExpObject - undeniable prototype', t => {

test('tameGlobalRegExpObject - constructor', t => {
const restore = captureGlobals('RegExp');
tameGlobalRegExpObject(true);
tameGlobalRegExpObject('unsafe');

t.equal(RegExp.name, 'RegExp');
t.equal(RegExp.prototype.constructor, RegExp);
Expand Down
Loading

0 comments on commit 67eb6e8

Please sign in to comment.