Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit f21aebd

Browse files
committed
Merge pull request #113 from facebook/save-native-object-create
fixes #104; makes the chrome ext immune to Object.create polyfills
2 parents 642c480 + 8200a10 commit f21aebd

File tree

5 files changed

+96
-5
lines changed

5 files changed

+96
-5
lines changed

shells/chrome/Readme.md

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,44 @@
33
To hack on the plugin:
44

55
- run `npm install`
6+
- run `webpack --config webpack.backend.js` in this directory
67
- run `webpack` or `webpack --watch` in this directory
78
- Go to `chrome://extensions`, check "developer mode", and click "Load
89
unpacked extension", and select this directory
910
- Hack away!
1011

11-
Generally, changes to the UI will auto-propagate (close devtools and re-open
12-
them). If you change the background script or injector, you'll have to reload
13-
the extension from the extensions page.
12+
Generally, changes to the UI will auto-propagate if you have `webpack --watch`
13+
on (close devtools and re-open them). If you change the background script or
14+
injector, you might have to reload the extension from the extensions page.
15+
16+
## Insulating the environment
17+
18+
React Devtools has part of the code (the backend + agent) running in the same
19+
javascript context as the inspected page, which makes the code vulnerable to
20+
environmental inconsistencies. For example, the backend uses the es6 `Map`
21+
class and normally expects it to be available in the global scope. If a user
22+
script has overridden this, the backend breaks.
23+
24+
To prevent this, the content script [`src/GlobalHook.js`](src/GlobalHook.js),
25+
which runs before any user js, saves the native values we depend on to the
26+
`__REACT_DEVTOOLS_GLOBAL_HOOK__` global. These are:
27+
28+
- Set
29+
- Map
30+
- WeakMap
31+
- Object.create
32+
33+
Then in `webpack.backend.js`, these saved values are substituted for the
34+
globally referenced name (e.g. `Map` gets replaced with
35+
`window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeMap`).
36+
37+
## Fixing document.create
38+
39+
React Native sets `document.createElement` to `null` in order to convince js
40+
libs that they are not running in a browser environment while `debug in
41+
chrome` is enabled.
42+
43+
To deal with this, [`src/inject.js`](src/inject.js) calls
44+
`document.constructor.prototype.createElement` when it needs to create a
45+
`<script>` tag.
1446

shells/chrome/src/GlobalHook.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
2222
}
2323
`;
2424

25+
var saveNativeValues = `
26+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeObjectCreate = Object.create;
27+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeMap = Map;
28+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeWeakMap = WeakMap;
29+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeSet = Set;
30+
`;
31+
2532
var js = (
2633
';(' + globalHook.toString() + '(window))'
2734
);
2835

2936
// This script runs before the <head> element is created, so we add the script
3037
// to <html> instead.
3138
var script = document.createElement('script');
32-
script.textContent = checkForOld + js;
39+
script.textContent = checkForOld + js + saveNativeValues;
3340
document.documentElement.appendChild(script);
3441
script.parentNode.removeChild(script);

shells/chrome/webpack.backend.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
'use strict';
11+
12+
var webpack = require('webpack');
13+
var fs = require('fs');
14+
15+
module.exports = {
16+
devtool: 'cheap-module-eval-source-map',
17+
entry: {
18+
backend: './src/backend.js',
19+
},
20+
output: {
21+
path: __dirname + '/build', // eslint-disable-line no-path-concat
22+
filename: '[name].js',
23+
},
24+
25+
module: {
26+
loaders: [{
27+
test: /\.jsx?$/,
28+
loader: 'babel-loader?stage=0',
29+
exclude: [
30+
'node_modules',
31+
'./helpers.js',
32+
],
33+
}]
34+
},
35+
36+
plugins: [new webpack.DefinePlugin({
37+
'Object.create': 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeObjectCreate',
38+
WeakMap: 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeWeakMap',
39+
Map: 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeMap',
40+
Set: 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeSet',
41+
})],
42+
};
43+
44+
45+

shells/chrome/webpack.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ module.exports = {
1313
devtool: 'cheap-module-eval-source-map',
1414
entry: {
1515
main: './src/main.js',
16-
backend: './src/backend.js',
1716
background: './src/background.js',
1817
inject: './src/GlobalHook.js',
1918
contentScript: './src/contentScript.js',

test/example/sink.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
</head>
77
<body>
88
<script src="build/sink.js"></script>
9+
<script>
10+
// Test to make sure the backend doesn't depend on Object.create
11+
// or ES6 globals
12+
Object.create = null;
13+
Map = null;
14+
Set = null;
15+
WeakMap = null;
16+
</script>
917
</body>
1018
</html>
1119

0 commit comments

Comments
 (0)