Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: non-security mode for create-react-scripts compat. (KLUDGE) #642

Merged
merged 8 commits into from
Mar 26, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion packages/ses/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,20 @@ User-visible changes in SES:

## Next release

- No changes yet
- We temporarily introduced a new `__unsafeKludgeForReact__` option whose
`'unsafe'` setting that unsafely allows React to work under SES in the browser
even before React is fixed. Once React is fixed, this option will disappear.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I shy away from future tense. I tend toward "We plan to remove this once React is fixed." And I would much prefer to have an open issue to represent this plan.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo fixed. Creating the issue next.


As the name indicates, this is a temporary kludge that sacrifies safety
to get the current version of React working under SES in the browser by any
means necessary. What seems to work is to skip the hardening of the
primordials during `lockdown`, but to nevertheless enable `harden` to
work. Almost all objects inherit from primordial objects, and `harden`
is transitively contaigious across both inheritance and own property
traversal, so hardening almost any object will still harden those
primordials reachable from there. But this avoids or postpones enough
primordial freezing that React seems to be the unsafe monkey patching
erights marked this conversation as resolved.
Show resolved Hide resolved
of the primordials before it is too late.

## Release 0.12.5 (25-Mar-2021)

Expand Down
18 changes: 18 additions & 0 deletions packages/ses/lockdown-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Each option is explained in its own section below.
| `errorTaming` | `'safe'` | `'unsafe'` | `errorInstance.stack` |
| `stackFiltering` | `'concise'` | `'verbose'` | deep stacks signal/noise |
| `overrideTaming` | `'moderate'` | `'min'` or `'severe'` | override mistake antidote |
| `__unsafeKludgeForReact__` | `'safe'` | `'unsafe'` | sacrifice safety until react is fixed

## `regExpTaming` Options

Expand Down Expand Up @@ -487,3 +488,20 @@ by our override mitigation.

![overrideTaming: 'severe' vscode inspector display](docs/images/override-taming-star-inspector.png)
</details>

## `__unsafeKludgeForReact__` Options

We temporarily introduced a new `__unsafeKludgeForReact__` option whose
`'unsafe'` setting that unsafely allows React to work under SES in the browser
even before React is fixed. Once React is fixed, this option will disappear.

As the name indicates, this is a temporary kludge that sacrifies safety
to get the current version of React working under SES in the browser by any
means necessary. What seems to work is to skip the hardening of the
primordials during `lockdown`, but to nevertheless enable `harden` to
work. Almost all objects inherit from primordial objects, and `harden`
is transitively contaigious across both inheritance and own property
traversal, so hardening almost any object will still harden those
primordials reachable from there. But this avoids or postpones enough
primordial freezing that React seems to be the unsafe monkey patching
of the primordials before it is too late.
14 changes: 11 additions & 3 deletions packages/ses/src/lockdown-shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { assert, makeAssert } from './error/assert.js';
* consoleTaming?: 'safe' | 'unsafe',
* overrideTaming?: 'min' | 'moderate' | 'severe',
* stackFiltering?: 'concise' | 'verbose',
* __unsafeKludgeForReact__?: 'safe' | 'unsafe',
* }} LockdownOptions
*/

Expand Down Expand Up @@ -140,6 +141,7 @@ export function repairIntrinsics(
consoleTaming = 'safe',
overrideTaming = 'moderate',
stackFiltering = 'concise',
__unsafeKludgeForReact__ = 'safe',

...extraOptions
} = options;
Expand Down Expand Up @@ -172,6 +174,7 @@ export function repairIntrinsics(
consoleTaming,
overrideTaming,
stackFiltering,
__unsafeKludgeForReact__,
};

/**
Expand Down Expand Up @@ -249,11 +252,16 @@ export function repairIntrinsics(

function hardenIntrinsics() {
// Circumvent the override mistake.
// TODO consider moving this to the end of the repair phase, and
// therefore before vetted shims rather than afterwards. It is not
// clear yet which is better.
enablePropertyOverrides(intrinsics, overrideTaming);

// Finally register and optionally freeze all the intrinsics. This
// must be the operation that modifies the intrinsics.
lockdownHarden(intrinsics);
if (__unsafeKludgeForReact__ !== 'unsafe') {
// Finally register and optionally freeze all the intrinsics. This
// must be the operation that modifies the intrinsics.
lockdownHarden(intrinsics);
}

// Having completed lockdown without failing, the user may now
// call `harden` and expect the object's transitively accessible properties
Expand Down
32 changes: 32 additions & 0 deletions packages/ses/test/test-unsafe-kludge-for-react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import test from 'ava';
import '../lockdown.js';

lockdown({
__unsafeKludgeForReact__: 'unsafe',
});

test('Unsafe kludge for react', t => {
t.false(Object.isFrozen(Object.prototype));

const x = {};
x.toString = () => 'foo';
x.constructor = 'Foo';
t.is(`${x}`, 'foo');
t.is(x.constructor, 'Foo');

harden(x);

t.true(Object.isFrozen(Object.prototype));

const y = {};
y.toString = () => 'bar';
t.throws(
() => {
y.constructor = 'Bar';
},
undefined,
'Override should not be enabled for "constructor".',
);
t.is(`${y}`, 'bar');
t.is(y.constructor, Object);
});