Set appropriate defaults for webview options (#12271)
* Persist defaults to webPreferences object to JS land can read the inferred values instead of just user defined values * Test inherited default propogation * Refactor to remove coupling from fetching values and defaults * Test description type * Fix up tests
This commit is contained in:
parent
f54c94d6c9
commit
c2673aa970
11 changed files with 110 additions and 11 deletions
|
@ -1825,6 +1825,14 @@ v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
|
||||||
return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
|
return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> WebContents::GetLastWebPreferences(v8::Isolate* isolate) {
|
||||||
|
WebContentsPreferences* web_preferences =
|
||||||
|
WebContentsPreferences::FromWebContents(web_contents());
|
||||||
|
if (!web_preferences)
|
||||||
|
return v8::Null(isolate);
|
||||||
|
return mate::ConvertToV8(isolate, *web_preferences->last_web_preferences());
|
||||||
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
|
v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
|
||||||
if (owner_window())
|
if (owner_window())
|
||||||
return BrowserWindow::From(isolate(), owner_window());
|
return BrowserWindow::From(isolate(), owner_window());
|
||||||
|
@ -1976,6 +1984,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("_getZoomFactor", &WebContents::GetZoomFactor)
|
.SetMethod("_getZoomFactor", &WebContents::GetZoomFactor)
|
||||||
.SetMethod("getType", &WebContents::GetType)
|
.SetMethod("getType", &WebContents::GetType)
|
||||||
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
|
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
|
||||||
|
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
|
||||||
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
||||||
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
||||||
.SetMethod("unregisterServiceWorker",
|
.SetMethod("unregisterServiceWorker",
|
||||||
|
|
|
@ -224,6 +224,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
|
|
||||||
// Returns the web preferences of current WebContents.
|
// Returns the web preferences of current WebContents.
|
||||||
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
|
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
|
||||||
|
v8::Local<v8::Value> GetLastWebPreferences(v8::Isolate* isolate);
|
||||||
|
|
||||||
// Returns the owner window.
|
// Returns the owner window.
|
||||||
v8::Local<v8::Value> GetOwnerBrowserWindow();
|
v8::Local<v8::Value> GetOwnerBrowserWindow();
|
||||||
|
|
|
@ -48,6 +48,28 @@ WebContentsPreferences::WebContentsPreferences(
|
||||||
web_contents->SetUserData(UserDataKey(), base::WrapUnique(this));
|
web_contents->SetUserData(UserDataKey(), base::WrapUnique(this));
|
||||||
|
|
||||||
instances_.push_back(this);
|
instances_.push_back(this);
|
||||||
|
|
||||||
|
// Set WebPreferences defaults onto the JS object
|
||||||
|
SetDefaultBoolIfUndefined("plugins", false);
|
||||||
|
SetDefaultBoolIfUndefined(options::kExperimentalFeatures, false);
|
||||||
|
SetDefaultBoolIfUndefined(options::kExperimentalCanvasFeatures, false);
|
||||||
|
bool node = SetDefaultBoolIfUndefined(options::kNodeIntegration, true);
|
||||||
|
SetDefaultBoolIfUndefined(options::kNodeIntegrationInWorker, false);
|
||||||
|
SetDefaultBoolIfUndefined(options::kWebviewTag, node);
|
||||||
|
SetDefaultBoolIfUndefined("sandbox", false);
|
||||||
|
SetDefaultBoolIfUndefined("nativeWindowOpen", false);
|
||||||
|
SetDefaultBoolIfUndefined(options::kContextIsolation, false);
|
||||||
|
SetDefaultBoolIfUndefined("javascript", true);
|
||||||
|
SetDefaultBoolIfUndefined("images", true);
|
||||||
|
SetDefaultBoolIfUndefined("textAreasAreResizable", true);
|
||||||
|
SetDefaultBoolIfUndefined("webgl", true);
|
||||||
|
SetDefaultBoolIfUndefined("webSecurity", true);
|
||||||
|
SetDefaultBoolIfUndefined("allowRunningInsecureContent", false);
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
SetDefaultBoolIfUndefined(options::kScrollBounce, false);
|
||||||
|
#endif
|
||||||
|
SetDefaultBoolIfUndefined("offscreen", false);
|
||||||
|
last_web_preferences_.MergeDictionary(&web_preferences_);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebContentsPreferences::~WebContentsPreferences() {
|
WebContentsPreferences::~WebContentsPreferences() {
|
||||||
|
@ -56,6 +78,16 @@ WebContentsPreferences::~WebContentsPreferences() {
|
||||||
instances_.end());
|
instances_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebContentsPreferences::SetDefaultBoolIfUndefined(const std::string key,
|
||||||
|
bool val) {
|
||||||
|
bool existing;
|
||||||
|
if (!web_preferences_.GetBoolean(key, &existing)) {
|
||||||
|
web_preferences_.SetBoolean(key, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
void WebContentsPreferences::Merge(const base::DictionaryValue& extend) {
|
void WebContentsPreferences::Merge(const base::DictionaryValue& extend) {
|
||||||
web_preferences_.MergeDictionary(&extend);
|
web_preferences_.MergeDictionary(&extend);
|
||||||
}
|
}
|
||||||
|
@ -80,6 +112,12 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
|
||||||
|
|
||||||
base::DictionaryValue& web_preferences = self->web_preferences_;
|
base::DictionaryValue& web_preferences = self->web_preferences_;
|
||||||
|
|
||||||
|
// We are appending args to a webContents so let's save the current state
|
||||||
|
// of our preferences object so that during the lifetime of the WebContents
|
||||||
|
// we can fetch the options used to initally configure the WebContents
|
||||||
|
self->last_web_preferences_.Clear();
|
||||||
|
self->last_web_preferences_.MergeDictionary(&web_preferences);
|
||||||
|
|
||||||
bool b;
|
bool b;
|
||||||
// Check if plugins are enabled.
|
// Check if plugins are enabled.
|
||||||
if (web_preferences.GetBoolean("plugins", &b) && b)
|
if (web_preferences.GetBoolean("plugins", &b) && b)
|
||||||
|
|
|
@ -57,10 +57,16 @@ class WebContentsPreferences
|
||||||
|
|
||||||
// Returns the web preferences.
|
// Returns the web preferences.
|
||||||
base::DictionaryValue* web_preferences() { return &web_preferences_; }
|
base::DictionaryValue* web_preferences() { return &web_preferences_; }
|
||||||
|
base::DictionaryValue* last_web_preferences() {
|
||||||
|
return &last_web_preferences_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class content::WebContentsUserData<WebContentsPreferences>;
|
friend class content::WebContentsUserData<WebContentsPreferences>;
|
||||||
|
|
||||||
|
// Set preference value to given bool if user did not provide value
|
||||||
|
bool SetDefaultBoolIfUndefined(const std::string key, bool val);
|
||||||
|
|
||||||
// Get preferences value as integer possibly coercing it from a string
|
// Get preferences value as integer possibly coercing it from a string
|
||||||
bool GetInteger(const std::string& attributeName, int* intValue);
|
bool GetInteger(const std::string& attributeName, int* intValue);
|
||||||
|
|
||||||
|
@ -68,6 +74,7 @@ class WebContentsPreferences
|
||||||
|
|
||||||
content::WebContents* web_contents_;
|
content::WebContents* web_contents_;
|
||||||
base::DictionaryValue web_preferences_;
|
base::DictionaryValue web_preferences_;
|
||||||
|
base::DictionaryValue last_web_preferences_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(WebContentsPreferences);
|
DISALLOW_COPY_AND_ASSIGN(WebContentsPreferences);
|
||||||
};
|
};
|
||||||
|
|
|
@ -156,7 +156,7 @@ const createGuest = function (embedder, params) {
|
||||||
// Forward internal web contents event to embedder to handle
|
// Forward internal web contents event to embedder to handle
|
||||||
// native window.open setup
|
// native window.open setup
|
||||||
guest.on('-add-new-contents', (...args) => {
|
guest.on('-add-new-contents', (...args) => {
|
||||||
if (guest.getWebPreferences().nativeWindowOpen === true) {
|
if (guest.getLastWebPreferences().nativeWindowOpen === true) {
|
||||||
const embedder = getEmbedder(guestInstanceId)
|
const embedder = getEmbedder(guestInstanceId)
|
||||||
if (embedder != null) {
|
if (embedder != null) {
|
||||||
embedder.emit('-add-new-contents', ...args)
|
embedder.emit('-add-new-contents', ...args)
|
||||||
|
@ -164,7 +164,7 @@ const createGuest = function (embedder, params) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
guest.on('-web-contents-created', (...args) => {
|
guest.on('-web-contents-created', (...args) => {
|
||||||
if (guest.getWebPreferences().nativeWindowOpen === true) {
|
if (guest.getLastWebPreferences().nativeWindowOpen === true) {
|
||||||
const embedder = getEmbedder(guestInstanceId)
|
const embedder = getEmbedder(guestInstanceId)
|
||||||
if (embedder != null) {
|
if (embedder != null) {
|
||||||
embedder.emit('-web-contents-created', ...args)
|
embedder.emit('-web-contents-created', ...args)
|
||||||
|
|
|
@ -59,12 +59,12 @@ const mergeBrowserWindowOptions = function (embedder, options) {
|
||||||
mergeOptions(options, parentOptions)
|
mergeOptions(options, parentOptions)
|
||||||
} else {
|
} else {
|
||||||
// Or only inherit webPreferences if it is a webview.
|
// Or only inherit webPreferences if it is a webview.
|
||||||
mergeOptions(options.webPreferences, embedder.getWebPreferences())
|
mergeOptions(options.webPreferences, embedder.getLastWebPreferences())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inherit certain option values from parent window
|
// Inherit certain option values from parent window
|
||||||
for (const [name, value] of inheritedWebPreferences) {
|
for (const [name, value] of inheritedWebPreferences) {
|
||||||
if (embedder.getWebPreferences()[name] === value) {
|
if (embedder.getLastWebPreferences()[name] === value) {
|
||||||
options.webPreferences[name] = value
|
options.webPreferences[name] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,8 +177,8 @@ const getGuestWindow = function (guestContents) {
|
||||||
// The W3C does not have anything on this, but from my understanding of the
|
// The W3C does not have anything on this, but from my understanding of the
|
||||||
// security model of |window.opener|, this should be fine.
|
// security model of |window.opener|, this should be fine.
|
||||||
const canAccessWindow = function (sender, target) {
|
const canAccessWindow = function (sender, target) {
|
||||||
return (target.getWebPreferences().openerId === sender.id) ||
|
return (target.getLastWebPreferences().openerId === sender.id) ||
|
||||||
(sender.getWebPreferences().nodeIntegration === true) ||
|
(sender.getLastWebPreferences().nodeIntegration === true) ||
|
||||||
isSameOrigin(sender.getURL(), target.getURL())
|
isSameOrigin(sender.getURL(), target.getURL())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ const getWebPreferences = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
webPreferences = remote.getCurrentWebContents().getWebPreferences()
|
webPreferences = remote.getCurrentWebContents().getLastWebPreferences()
|
||||||
return webPreferences
|
return webPreferences
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -2999,7 +2999,7 @@ describe('BrowserWindow module', () => {
|
||||||
})
|
})
|
||||||
it('enables context isolation on child windows', (done) => {
|
it('enables context isolation on child windows', (done) => {
|
||||||
app.once('browser-window-created', (event, window) => {
|
app.once('browser-window-created', (event, window) => {
|
||||||
assert.equal(window.webContents.getWebPreferences().contextIsolation, true)
|
assert.equal(window.webContents.getLastWebPreferences().contextIsolation, true)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
w.loadURL(`file://${fixtures}/pages/window-open.html`)
|
w.loadURL(`file://${fixtures}/pages/window-open.html`)
|
||||||
|
|
|
@ -268,6 +268,26 @@ describe('chromium feature', () => {
|
||||||
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
|
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('disables webviewTag when node integration is disabled on the parent window', (done) => {
|
||||||
|
let b
|
||||||
|
listener = (event) => {
|
||||||
|
assert.equal(event.data.isWebViewUndefined, true)
|
||||||
|
b.close()
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
window.addEventListener('message', listener)
|
||||||
|
|
||||||
|
const windowUrl = require('url').format({
|
||||||
|
pathname: `${fixtures}/pages/window-opener-no-web-view-tag.html`,
|
||||||
|
protocol: 'file',
|
||||||
|
query: {
|
||||||
|
p: `${fixtures}/pages/window-opener-web-view.html`
|
||||||
|
},
|
||||||
|
slashes: true
|
||||||
|
})
|
||||||
|
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
|
||||||
|
})
|
||||||
|
|
||||||
it('disables node integration when it is disabled on the parent window for chrome devtools URLs', (done) => {
|
it('disables node integration when it is disabled on the parent window for chrome devtools URLs', (done) => {
|
||||||
let b
|
let b
|
||||||
app.once('web-contents-created', (event, contents) => {
|
app.once('web-contents-created', (event, contents) => {
|
||||||
|
@ -287,7 +307,7 @@ describe('chromium feature', () => {
|
||||||
app.once('web-contents-created', (event, contents) => {
|
app.once('web-contents-created', (event, contents) => {
|
||||||
contents.once('did-finish-load', () => {
|
contents.once('did-finish-load', () => {
|
||||||
app.once('browser-window-created', (event, window) => {
|
app.once('browser-window-created', (event, window) => {
|
||||||
const preferences = window.webContents.getWebPreferences()
|
const preferences = window.webContents.getLastWebPreferences()
|
||||||
assert.equal(preferences.javascript, false)
|
assert.equal(preferences.javascript, false)
|
||||||
window.destroy()
|
window.destroy()
|
||||||
b.close()
|
b.close()
|
||||||
|
@ -509,7 +529,7 @@ describe('chromium feature', () => {
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
window.addEventListener('message', listener)
|
window.addEventListener('message', listener)
|
||||||
w = window.open(url, '', 'show=no')
|
w = window.open(url, '', 'show=no,nodeIntegration=no')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('works when origin matches', (done) => {
|
it('works when origin matches', (done) => {
|
||||||
|
@ -518,7 +538,7 @@ describe('chromium feature', () => {
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
window.addEventListener('message', listener)
|
window.addEventListener('message', listener)
|
||||||
w = window.open(`file://${fixtures}/pages/window-opener-location.html`, '', 'show=no')
|
w = window.open(`file://${fixtures}/pages/window-opener-location.html`, '', 'show=no,nodeIntegration=no')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('works when origin does not match opener but has node integration', (done) => {
|
it('works when origin does not match opener but has node integration', (done) => {
|
||||||
|
|
15
spec/fixtures/pages/window-opener-no-web-view-tag.html
vendored
Normal file
15
spec/fixtures/pages/window-opener-no-web-view-tag.html
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
var windowUrl = decodeURIComponent(window.location.search.substring(3))
|
||||||
|
var opened = window.open('file://' + windowUrl, '', 'webviewTag=yes,show=no')
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
|
try {
|
||||||
|
opened.close()
|
||||||
|
} finally {
|
||||||
|
window.opener.postMessage(event.data, '*')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
9
spec/fixtures/pages/window-opener-web-view.html
vendored
Normal file
9
spec/fixtures/pages/window-opener-web-view.html
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
window.onload = () => {
|
||||||
|
window.opener.postMessage({isWebViewUndefined: typeof WebView === 'undefined'}, '*')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue