-
Notifications
You must be signed in to change notification settings - Fork 0
[DevTools] Enable minimal support in pages with sandbox Content-Security-Policy
#207
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
Changes from all commits
99a1740
82984e5
0a383b7
c965371
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -97,6 +97,58 @@ export function handleDevToolsPageMessage(message) { | |
|
|
||
| break; | ||
| } | ||
|
|
||
| case 'eval-in-inspected-window': { | ||
| const { | ||
| payload: {tabId, requestId, scriptId, args}, | ||
| } = message; | ||
|
|
||
| chrome.tabs | ||
| .sendMessage(tabId, { | ||
| source: 'devtools-page-eval', | ||
| payload: { | ||
| scriptId, | ||
| args, | ||
| }, | ||
| }) | ||
| .then(response => { | ||
| if (!response) { | ||
| chrome.runtime.sendMessage({ | ||
| source: 'react-devtools-background', | ||
| payload: { | ||
| type: 'eval-in-inspected-window-response', | ||
| requestId, | ||
| result: null, | ||
| error: 'No response from content script', | ||
| }, | ||
| }); | ||
| return; | ||
| } | ||
| const {result, error} = response; | ||
| chrome.runtime.sendMessage({ | ||
| source: 'react-devtools-background', | ||
|
Comment on lines
+114
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/background/messageHandlers.js
Line: 114:129
Comment:
if `sendMessage` resolves with `undefined` (no listener on target tab), reports generic "No response" error. should distinguish between "no content script" vs actual errors
How can I resolve this? If you propose a fix, please make it concise. |
||
| payload: { | ||
| type: 'eval-in-inspected-window-response', | ||
| requestId, | ||
| result, | ||
| error, | ||
| }, | ||
| }); | ||
| }) | ||
| .catch(error => { | ||
| chrome.runtime.sendMessage({ | ||
| source: 'react-devtools-background', | ||
| payload: { | ||
| type: 'eval-in-inspected-window-response', | ||
| requestId, | ||
| result: null, | ||
| error: error?.message || String(error), | ||
| }, | ||
| }); | ||
| }); | ||
|
|
||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,35 @@ | ||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * This source code is licensed under the MIT license found in the | ||||||||||||||||||||||||
| * LICENSE file in the root directory of this source tree. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * @flow | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import {evalScripts} from '../evalScripts'; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| window.addEventListener('message', event => { | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: missing
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/contentScripts/fallbackEvalContext.js
Line: 12:12
Comment:
**logic:** missing `event.source` validation - other content scripts check `event.source !== window` to prevent malicious messages from iframes or other origins
```suggestion
if (event.source !== window || event.data?.source === 'react-devtools-content-script-eval') {
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security vulnerability: missing
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/contentScripts/fallbackEvalContext.js
Line: 12:12
Comment:
**Security vulnerability**: missing `event.source` validation allows malicious iframes to trigger arbitrary script execution. Any iframe can send a message with `source: 'react-devtools-content-script-eval'` and execute scripts from the `evalScripts` registry.
```suggestion
window.addEventListener('message', event => {
if (event.source !== window) return;
if (event.data?.source === 'react-devtools-content-script-eval') {
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||
| if (event.data?.source === 'react-devtools-content-script-eval') { | ||||||||||||||||||||||||
| const {scriptId, args, requestId} = event.data.payload; | ||||||||||||||||||||||||
| const response = {result: null, error: null}; | ||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||
| if (!evalScripts[scriptId]) { | ||||||||||||||||||||||||
| throw new Error(`No eval script with id "${scriptId}" exists.`); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Comment on lines
+16
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. caught error's stack trace is lost when only passing
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/contentScripts/fallbackEvalContext.js
Line: 16:19
Comment:
caught error's stack trace is lost when only passing `err.message`. better to serialize full error or include stack
```suggestion
try {
if (!evalScripts[scriptId]) {
throw new Error(`No eval script with id "${scriptId}" exists.`);
}
response.result = evalScripts[scriptId].fn.apply(null, args);
} catch (err) {
response.error = err.stack || err.message || String(err);
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||
| response.result = evalScripts[scriptId].fn.apply(null, args); | ||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||
| response.error = err.message; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| window.postMessage( | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| source: 'react-devtools-content-script-eval-response', | ||||||||||||||||||||||||
| payload: { | ||||||||||||||||||||||||
| requestId, | ||||||||||||||||||||||||
| response, | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| '*', | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -117,3 +117,49 @@ function connectPort() { | |||||||||
| // $FlowFixMe[incompatible-use] | ||||||||||
| port.onDisconnect.addListener(handleDisconnect); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| let evalRequestId = 0; | ||||||||||
| const evalRequestCallbacks = new Map<number, Function>(); | ||||||||||
|
Comment on lines
+121
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. memory leak: callbacks never cleaned up on extension unload or when responses are never received (e.g., if page unloads before response)
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/contentScripts/proxy.js
Line: 121:122
Comment:
memory leak: callbacks never cleaned up on extension unload or when responses are never received (e.g., if page unloads before response)
```suggestion
let evalRequestId = 0;
const evalRequestCallbacks = new Map<number, {callback: Function, timeout: TimeoutID}>();
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||
|
|
||||||||||
| chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { | ||||||||||
| switch (msg?.source) { | ||||||||||
| case 'devtools-page-eval': { | ||||||||||
| const {scriptId, args} = msg.payload; | ||||||||||
| const requestId = evalRequestId++; | ||||||||||
| window.postMessage( | ||||||||||
| { | ||||||||||
| source: 'react-devtools-content-script-eval', | ||||||||||
| payload: { | ||||||||||
| requestId, | ||||||||||
| scriptId, | ||||||||||
| args, | ||||||||||
| }, | ||||||||||
|
Comment on lines
+133
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should set timeout to clean up callback if response never arrives (e.g., page unloads). prevents memory leak in Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/contentScripts/proxy.js
Line: 133:136
Comment:
should set timeout to clean up callback if response never arrives (e.g., page unloads). prevents memory leak in `evalRequestCallbacks`
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||
| }, | ||||||||||
| '*', | ||||||||||
| ); | ||||||||||
| evalRequestCallbacks.set(requestId, sendResponse); | ||||||||||
| return true; // Indicate we will respond asynchronously | ||||||||||
| } | ||||||||||
| } | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| window.addEventListener('message', event => { | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security vulnerability: missing
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/contentScripts/proxy.js
Line: 146:146
Comment:
**Security vulnerability**: missing `event.source` validation allows malicious iframes to send fake eval responses. Should validate `event.source === window`.
```suggestion
window.addEventListener('message', event => {
if (event.source !== window) return;
if (event.data?.source === 'react-devtools-content-script-eval-response') {
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||
| if (event.data?.source === 'react-devtools-content-script-eval-response') { | ||||||||||
| const {requestId, response} = event.data.payload; | ||||||||||
| const callback = evalRequestCallbacks.get(requestId); | ||||||||||
| try { | ||||||||||
| if (!callback) | ||||||||||
| throw new Error( | ||||||||||
| `No eval request callback for id "${requestId}" exists.`, | ||||||||||
| ); | ||||||||||
| callback(response); | ||||||||||
| } catch (e) { | ||||||||||
| console.warn( | ||||||||||
| 'React DevTools Content Script eval response error occurred:', | ||||||||||
| e, | ||||||||||
| ); | ||||||||||
| } finally { | ||||||||||
| evalRequestCallbacks.delete(requestId); | ||||||||||
| } | ||||||||||
| } | ||||||||||
| }); | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| /** | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| * | ||
| * @flow | ||
| */ | ||
|
|
||
| export type EvalScriptIds = | ||
| | 'checkIfReactPresentInInspectedWindow' | ||
| | 'reload' | ||
| | 'setBrowserSelectionFromReact' | ||
| | 'setReactSelectionFromBrowser' | ||
| | 'viewAttributeSource' | ||
| | 'viewElementSource'; | ||
|
|
||
| /* | ||
| .fn for fallback in Content Script context | ||
| .code for chrome.devtools.inspectedWindow.eval() | ||
| */ | ||
| type EvalScriptEntry = { | ||
| fn: (...args: any[]) => any, | ||
| code: (...args: any[]) => string, | ||
| }; | ||
|
|
||
| /* | ||
| Can not access `Developer Tools Console API` (e.g., inspect(), $0) in this context. | ||
| So some fallback functions are no-op or throw error. | ||
| */ | ||
| export const evalScripts: {[key: EvalScriptIds]: EvalScriptEntry} = { | ||
| checkIfReactPresentInInspectedWindow: { | ||
| fn: () => | ||
| window.__REACT_DEVTOOLS_GLOBAL_HOOK__ && | ||
| window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.size > 0, | ||
| code: () => | ||
| 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__ &&' + | ||
| 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.size > 0', | ||
| }, | ||
| reload: { | ||
| fn: () => window.location.reload(), | ||
| code: () => 'window.location.reload();', | ||
| }, | ||
| setBrowserSelectionFromReact: { | ||
| fn: () => { | ||
| throw new Error('Not supported in fallback eval context'); | ||
| }, | ||
| code: () => | ||
| '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 !== $0) ?' + | ||
| '(inspect(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0), true) :' + | ||
| 'false', | ||
| }, | ||
| setReactSelectionFromBrowser: { | ||
| fn: () => { | ||
| throw new Error('Not supported in fallback eval context'); | ||
| }, | ||
| code: () => | ||
| '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__ && window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 !== $0) ?' + | ||
| '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 = $0, true) :' + | ||
| 'false', | ||
| }, | ||
| viewAttributeSource: { | ||
| fn: ({rendererID, elementID, path}) => { | ||
|
Comment on lines
+62
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. returning Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/evalScripts.js
Line: 62:63
Comment:
returning `false` silently makes it unclear whether feature is unsupported or operation failed legitimately. should throw error or return distinguishable value
How can I resolve this? If you propose a fix, please make it concise. |
||
| return false; // Not supported in fallback eval context | ||
| }, | ||
| code: ({rendererID, elementID, path}) => | ||
| '{' + // The outer block is important because it means we can declare local variables. | ||
| 'const renderer = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.get(' + | ||
| JSON.stringify(rendererID) + | ||
| ');' + | ||
| 'if (renderer) {' + | ||
| ' const value = renderer.getElementAttributeByPath(' + | ||
| JSON.stringify(elementID) + | ||
| ',' + | ||
| JSON.stringify(path) + | ||
| ');' + | ||
| ' if (value) {' + | ||
| ' inspect(value);' + | ||
| ' true;' + | ||
| ' } else {' + | ||
| ' false;' + | ||
| ' }' + | ||
| '} else {' + | ||
| ' false;' + | ||
| '}' + | ||
| '}', | ||
| }, | ||
| viewElementSource: { | ||
| fn: ({rendererID, elementID}) => { | ||
| return false; // Not supported in fallback eval context | ||
|
Comment on lines
+89
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. returning Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/react-devtools-extensions/src/evalScripts.js
Line: 89:90
Comment:
returning `false` silently makes it unclear whether feature is unsupported or operation failed legitimately. should throw error or return distinguishable value
How can I resolve this? If you propose a fix, please make it concise. |
||
| }, | ||
| code: ({rendererID, elementID}) => | ||
| '{' + // The outer block is important because it means we can declare local variables. | ||
| 'const renderer = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.get(' + | ||
| JSON.stringify(rendererID) + | ||
| ');' + | ||
| 'if (renderer) {' + | ||
| ' const value = renderer.getElementSourceFunctionById(' + | ||
| JSON.stringify(elementID) + | ||
| ');' + | ||
| ' if (value) {' + | ||
| ' inspect(value);' + | ||
| ' true;' + | ||
| ' } else {' + | ||
| ' false;' + | ||
| ' }' + | ||
| '} else {' + | ||
| ' false;' + | ||
| '}' + | ||
| '}', | ||
| }, | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing validation that message is from a legitimate devtools page. should verify sender is from extension context
Prompt To Fix With AI