-
Notifications
You must be signed in to change notification settings - Fork 47.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor[devtools/extension]: refactored messaging logic across diffe…
…rent parts of the extension (#27417) 1. bvaughn@9fc04ea#diff-2c5e1f5e80e74154e65b2813cf1c3638f85034530e99dae24809ab4ad70d0143 introduced a vulnerability: we listen to `'fetch-file-with-cache'` event from `window` to fetch sources of the file, in which we want to parse hook names. We send this event via `window`, which means any page can also use this and manipulate the extension to perform some `fetch()` calls. With these changes, instead of transporting message via `window`, we have a distinct content script, which is responsible for fetching sources. It is notified via `chrome.runtime.sendMessage` api, so it can't be manipulated. 2. Consistent structure of messages `{source: string, payload: object}` in different parts of the extension 3. Added some wrappers around `chrome.scripting.executeScript` API in `packages/react-devtools-extensions/src/background/executeScript.js`, which support custom flow for Firefox, to simulate support of `ExecutionWorld.MAIN`.
- Loading branch information
Showing
14 changed files
with
406 additions
and
291 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
packages/react-devtools-extensions/src/background/executeScript.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* global chrome */ | ||
|
||
import {IS_FIREFOX} from '../utils'; | ||
|
||
// Firefox doesn't support ExecutionWorld.MAIN yet | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575 | ||
function executeScriptForFirefoxInMainWorld({target, files}) { | ||
return chrome.scripting.executeScript({ | ||
target, | ||
func: fileNames => { | ||
function injectScriptSync(src) { | ||
let code = ''; | ||
const request = new XMLHttpRequest(); | ||
request.addEventListener('load', function () { | ||
code = this.responseText; | ||
}); | ||
request.open('GET', src, false); | ||
request.send(); | ||
|
||
const script = document.createElement('script'); | ||
script.textContent = code; | ||
|
||
// This script runs before the <head> element is created, | ||
// so we add the script to <html> instead. | ||
if (document.documentElement) { | ||
document.documentElement.appendChild(script); | ||
} | ||
|
||
if (script.parentNode) { | ||
script.parentNode.removeChild(script); | ||
} | ||
} | ||
|
||
fileNames.forEach(file => injectScriptSync(chrome.runtime.getURL(file))); | ||
}, | ||
args: [files], | ||
}); | ||
} | ||
|
||
export function executeScriptInIsolatedWorld({target, files}) { | ||
return chrome.scripting.executeScript({ | ||
target, | ||
files, | ||
world: chrome.scripting.ExecutionWorld.ISOLATED, | ||
}); | ||
} | ||
|
||
export function executeScriptInMainWorld({target, files}) { | ||
if (IS_FIREFOX) { | ||
return executeScriptForFirefoxInMainWorld({target, files}); | ||
} | ||
|
||
return chrome.scripting.executeScript({ | ||
target, | ||
files, | ||
world: chrome.scripting.ExecutionWorld.MAIN, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 0 additions & 12 deletions
12
packages/react-devtools-extensions/src/background/injectProxy.js
This file was deleted.
Oops, something went wrong.
103 changes: 103 additions & 0 deletions
103
packages/react-devtools-extensions/src/background/messageHandlers.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* global chrome */ | ||
|
||
import setExtensionIconAndPopup from './setExtensionIconAndPopup'; | ||
import {executeScriptInMainWorld} from './executeScript'; | ||
|
||
import {EXTENSION_CONTAINED_VERSIONS} from '../utils'; | ||
|
||
export function handleReactDevToolsHookMessage(message, sender) { | ||
const {payload} = message; | ||
|
||
switch (payload?.type) { | ||
case 'react-renderer-attached': { | ||
setExtensionIconAndPopup(payload.reactBuildType, sender.tab.id); | ||
|
||
break; | ||
} | ||
} | ||
} | ||
|
||
export function handleBackendManagerMessage(message, sender) { | ||
const {payload} = message; | ||
|
||
switch (payload?.type) { | ||
case 'require-backends': { | ||
payload.versions.forEach(version => { | ||
if (EXTENSION_CONTAINED_VERSIONS.includes(version)) { | ||
executeScriptInMainWorld({ | ||
target: {tabId: sender.tab.id}, | ||
files: [`/build/react_devtools_backend_${version}.js`], | ||
}); | ||
} | ||
}); | ||
|
||
break; | ||
} | ||
} | ||
} | ||
|
||
export function handleDevToolsPageMessage(message) { | ||
const {payload} = message; | ||
|
||
switch (payload?.type) { | ||
// Proxy this message from DevTools page to content script via chrome.tabs.sendMessage | ||
case 'fetch-file-with-cache': { | ||
const { | ||
payload: {tabId, url}, | ||
} = message; | ||
|
||
if (!tabId) { | ||
throw new Error("Couldn't fetch file sources: tabId not specified"); | ||
} | ||
|
||
if (!url) { | ||
throw new Error("Couldn't fetch file sources: url not specified"); | ||
} | ||
|
||
chrome.tabs.sendMessage(tabId, { | ||
source: 'devtools-page', | ||
payload: { | ||
type: 'fetch-file-with-cache', | ||
url, | ||
}, | ||
}); | ||
|
||
break; | ||
} | ||
|
||
case 'inject-backend-manager': { | ||
const { | ||
payload: {tabId}, | ||
} = message; | ||
|
||
if (!tabId) { | ||
throw new Error("Couldn't inject backend manager: tabId not specified"); | ||
} | ||
|
||
executeScriptInMainWorld({ | ||
target: {tabId}, | ||
files: ['/build/backendManager.js'], | ||
}); | ||
|
||
break; | ||
} | ||
} | ||
} | ||
|
||
export function handleFetchResourceContentScriptMessage(message) { | ||
const {payload} = message; | ||
|
||
switch (payload?.type) { | ||
case 'fetch-file-with-cache-complete': | ||
case 'fetch-file-with-cache-error': | ||
// Forward the result of fetch-in-page requests back to the DevTools page. | ||
// We switch the source here because of inconsistency between Firefox and Chrome | ||
// In Chromium this message will be propagated from content script to DevTools page | ||
// For Firefox, only background script will get this message, so we need to forward it to DevTools page | ||
chrome.runtime.sendMessage({ | ||
source: 'react-devtools-background', | ||
payload, | ||
}); | ||
break; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
packages/react-devtools-extensions/src/contentScripts/fileFetcher.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* global chrome */ | ||
|
||
function fetchResource(url) { | ||
const reject = value => { | ||
chrome.runtime.sendMessage({ | ||
source: 'react-devtools-fetch-resource-content-script', | ||
payload: { | ||
type: 'fetch-file-with-cache-error', | ||
url, | ||
value, | ||
}, | ||
}); | ||
}; | ||
|
||
const resolve = value => { | ||
chrome.runtime.sendMessage({ | ||
source: 'react-devtools-fetch-resource-content-script', | ||
payload: { | ||
type: 'fetch-file-with-cache-complete', | ||
url, | ||
value, | ||
}, | ||
}); | ||
}; | ||
|
||
fetch(url, {cache: 'force-cache'}).then( | ||
response => { | ||
if (response.ok) { | ||
response | ||
.text() | ||
.then(text => resolve(text)) | ||
.catch(error => reject(null)); | ||
} else { | ||
reject(null); | ||
} | ||
}, | ||
error => reject(null), | ||
); | ||
} | ||
|
||
chrome.runtime.onMessage.addListener(message => { | ||
if ( | ||
message?.source === 'devtools-page' && | ||
message?.payload?.type === 'fetch-file-with-cache' | ||
) { | ||
fetchResource(message.payload.url); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.