Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: clean up webFrame implementation to use gin wrappers
The previous implementation of webFrame in the renderer process leaked sub-frame contexts and global objects across the context boundaries thus making it possible for apps to either maliciously or accidentally violate the contextIsolation boundary. This re-implementation binds all methods in native code directly to content::RenderFrame instances instead of relying on JS to provide a "window" with every method request. This is much more consistent with the rest of the Electron codebase and is substantially safer.
- Loading branch information
1 parent
55c66e3
commit f69ac0d
Showing
10 changed files
with
609 additions
and
646 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
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 |
---|---|---|
@@ -1,84 +1,3 @@ | ||
import { EventEmitter } from 'events'; | ||
import deprecate from '@electron/internal/common/api/deprecate'; | ||
const { mainFrame } = process._linkedBinding('electron_renderer_web_frame'); | ||
|
||
const binding = process._linkedBinding('electron_renderer_web_frame'); | ||
|
||
class WebFrame extends EventEmitter { | ||
constructor (public context: Window) { | ||
super(); | ||
|
||
// Lots of webview would subscribe to webFrame's events. | ||
this.setMaxListeners(0); | ||
} | ||
|
||
findFrameByRoutingId (routingId: number) { | ||
return getWebFrame(binding._findFrameByRoutingId(this.context, routingId)); | ||
} | ||
|
||
getFrameForSelector (selector: string) { | ||
return getWebFrame(binding._getFrameForSelector(this.context, selector)); | ||
} | ||
|
||
findFrameByName (name: string) { | ||
return getWebFrame(binding._findFrameByName(this.context, name)); | ||
} | ||
|
||
get opener () { | ||
return getWebFrame(binding._getOpener(this.context)); | ||
} | ||
|
||
get parent () { | ||
return getWebFrame(binding._getParent(this.context)); | ||
} | ||
|
||
get top () { | ||
return getWebFrame(binding._getTop(this.context)); | ||
} | ||
|
||
get firstChild () { | ||
return getWebFrame(binding._getFirstChild(this.context)); | ||
} | ||
|
||
get nextSibling () { | ||
return getWebFrame(binding._getNextSibling(this.context)); | ||
} | ||
|
||
get routingId () { | ||
return binding._getRoutingId(this.context); | ||
} | ||
} | ||
|
||
const contextIsolation = binding.getWebPreference(window, 'contextIsolation'); | ||
const worldSafeExecuteJavaScript = binding.getWebPreference(window, 'worldSafeExecuteJavaScript'); | ||
|
||
const worldSafeJS = worldSafeExecuteJavaScript || !contextIsolation; | ||
|
||
// Populate the methods. | ||
for (const name in binding) { | ||
if (!name.startsWith('_')) { // some methods are manually populated above | ||
// TODO(felixrieseberg): Once we can type web_frame natives, we could | ||
// use a neat `keyof` here | ||
(WebFrame as any).prototype[name] = function (...args: Array<any>) { | ||
if (!worldSafeJS && name.startsWith('executeJavaScript')) { | ||
deprecate.log(`Security Warning: webFrame.${name} was called without worldSafeExecuteJavaScript enabled. This is considered unsafe. worldSafeExecuteJavaScript will be enabled by default in Electron 12.`); | ||
} | ||
return (binding as any)[name](this.context, ...args); | ||
}; | ||
// TODO(MarshallOfSound): Remove once the above deprecation is removed | ||
if (name.startsWith('executeJavaScript')) { | ||
(WebFrame as any).prototype[`_${name}`] = function (...args: Array<any>) { | ||
return (binding as any)[name](this.context, ...args); | ||
}; | ||
} | ||
} | ||
} | ||
|
||
// Helper to return WebFrame or null depending on context. | ||
// TODO(zcbenz): Consider returning same WebFrame for the same frame. | ||
function getWebFrame (context: Window) { | ||
return context ? new WebFrame(context) : null; | ||
} | ||
|
||
const _webFrame = new WebFrame(window); | ||
|
||
export default _webFrame; | ||
export default mainFrame; |
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
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
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
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
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
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.