Merge pull request #7631 from beakerbrowser/webview-policy-flags2
Add 'webpreferences' attribute to webview
This commit is contained in:
commit
39a5c7dab9
8 changed files with 91 additions and 14 deletions
|
@ -194,6 +194,20 @@ value will fail with a DOM exception.
|
||||||
|
|
||||||
If "on", the guest page will be allowed to open new windows.
|
If "on", the guest page will be allowed to open new windows.
|
||||||
|
|
||||||
|
### `webpreferences`
|
||||||
|
|
||||||
|
```html
|
||||||
|
<webview src="https://github.com" webpreferences="allowDisplayingInsecureContent, javascript=no"></webview>
|
||||||
|
```
|
||||||
|
|
||||||
|
A list of strings which specifies the web preferences to be set on the webview, separated by `,`.
|
||||||
|
The full list of supported preference strings can be found in [BrowserWindow](browser-window.md#new-browserwindowoptions).
|
||||||
|
|
||||||
|
The string follows the same format as the features string in `window.open`.
|
||||||
|
A name by itself is given a `true` boolean value.
|
||||||
|
A preference can be set to another value by including an `=`, followed by the value.
|
||||||
|
Special values `yes` and `1` are interpreted as `true`, while `no` and `0` are interpreted as `false`.
|
||||||
|
|
||||||
### `blinkfeatures`
|
### `blinkfeatures`
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
'lib/common/api/native-image.js',
|
'lib/common/api/native-image.js',
|
||||||
'lib/common/api/shell.js',
|
'lib/common/api/shell.js',
|
||||||
'lib/common/init.js',
|
'lib/common/init.js',
|
||||||
|
'lib/common/parse-features-string.js',
|
||||||
'lib/common/reset-search-paths.js',
|
'lib/common/reset-search-paths.js',
|
||||||
'lib/renderer/chrome-api.js',
|
'lib/renderer/chrome-api.js',
|
||||||
'lib/renderer/content-scripts-injector.js',
|
'lib/renderer/content-scripts-injector.js',
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
const ipcMain = require('electron').ipcMain
|
const ipcMain = require('electron').ipcMain
|
||||||
const webContents = require('electron').webContents
|
const webContents = require('electron').webContents
|
||||||
|
const parseFeaturesString = require('../common/parse-features-string')
|
||||||
|
|
||||||
// Doesn't exist in early initialization.
|
// Doesn't exist in early initialization.
|
||||||
let webViewManager = null
|
let webViewManager = null
|
||||||
|
@ -184,6 +185,18 @@ const attachGuest = function (embedder, elementInstanceId, guestInstanceId, para
|
||||||
disableBlinkFeatures: params.disableblinkfeatures
|
disableBlinkFeatures: params.disableblinkfeatures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse the 'webpreferences' attribute string, if set
|
||||||
|
// this uses the same parsing rules as window.open uses for its features
|
||||||
|
if (typeof params.webpreferences === 'string') {
|
||||||
|
parseFeaturesString(params.webpreferences, function (key, value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
// no value was specified, default it to true
|
||||||
|
value = true
|
||||||
|
}
|
||||||
|
webPreferences[key] = value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (params.preload) {
|
if (params.preload) {
|
||||||
webPreferences.preloadURL = params.preload
|
webPreferences.preloadURL = params.preload
|
||||||
}
|
}
|
||||||
|
|
18
lib/common/parse-features-string.js
Normal file
18
lib/common/parse-features-string.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// parses a feature string that has the format used in window.open()
|
||||||
|
// - `features` input string
|
||||||
|
// - `emit` function(key, value) - called for each parsed KV
|
||||||
|
module.exports = function parseFeaturesString (features, emit) {
|
||||||
|
// split the string by ','
|
||||||
|
features.split(/,\s*/).forEach((feature) => {
|
||||||
|
// expected form is either a key by itself or a key/value pair in the form of
|
||||||
|
// 'key=value'
|
||||||
|
let [key, value] = feature.split(/\s*=/)
|
||||||
|
if (!key) return
|
||||||
|
|
||||||
|
// interpret the value as a boolean, if possible
|
||||||
|
value = (value === 'yes' || value === '1') ? true : (value === 'no' || value === '0') ? false : value
|
||||||
|
|
||||||
|
// emit the parsed pair
|
||||||
|
emit(key, value)
|
||||||
|
})
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
const ipcRenderer = require('electron').ipcRenderer
|
const ipcRenderer = require('electron').ipcRenderer
|
||||||
const remote = require('electron').remote
|
const remote = require('electron').remote
|
||||||
|
const parseFeaturesString = require('../common/parse-features-string')
|
||||||
|
|
||||||
// Helper function to resolve relative url.
|
// Helper function to resolve relative url.
|
||||||
var a = window.top.document.createElement('a')
|
var a = window.top.document.createElement('a')
|
||||||
|
@ -88,7 +89,7 @@ if (process.guestInstanceId == null) {
|
||||||
|
|
||||||
// Make the browser window or guest view emit "new-window" event.
|
// Make the browser window or guest view emit "new-window" event.
|
||||||
window.open = function (url, frameName, features) {
|
window.open = function (url, frameName, features) {
|
||||||
var feature, guestId, i, j, len, len1, name, options, ref1, ref2, value, additionalFeatures
|
var guestId, j, len1, name, options, additionalFeatures
|
||||||
if (frameName == null) {
|
if (frameName == null) {
|
||||||
frameName = ''
|
frameName = ''
|
||||||
}
|
}
|
||||||
|
@ -104,27 +105,21 @@ window.open = function (url, frameName, features) {
|
||||||
// Used to store additional features
|
// Used to store additional features
|
||||||
additionalFeatures = []
|
additionalFeatures = []
|
||||||
|
|
||||||
// Make sure to get rid of excessive whitespace in the property name
|
// Parse the features
|
||||||
ref1 = features.split(/,\s*/)
|
parseFeaturesString(features, function (key, value) {
|
||||||
for (i = 0, len = ref1.length; i < len; i++) {
|
|
||||||
feature = ref1[i]
|
|
||||||
ref2 = feature.split(/\s*=/)
|
|
||||||
name = ref2[0]
|
|
||||||
value = ref2[1]
|
|
||||||
value = value === 'yes' || value === '1' ? true : value === 'no' || value === '0' ? false : value
|
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
additionalFeatures.push(feature)
|
additionalFeatures.push(key)
|
||||||
} else {
|
} else {
|
||||||
if (webPreferences.includes(name)) {
|
if (webPreferences.includes(key)) {
|
||||||
if (options.webPreferences == null) {
|
if (options.webPreferences == null) {
|
||||||
options.webPreferences = {}
|
options.webPreferences = {}
|
||||||
}
|
}
|
||||||
options.webPreferences[name] = value
|
options.webPreferences[key] = value
|
||||||
} else {
|
} else {
|
||||||
options[name] = value
|
options[key] = value
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
if (options.left) {
|
if (options.left) {
|
||||||
if (options.x == null) {
|
if (options.x == null) {
|
||||||
options.x = options.left
|
options.x = options.left
|
||||||
|
|
|
@ -312,6 +312,13 @@ class DisableBlinkFeaturesAttribute extends WebViewAttribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attribute that specifies the web preferences to be enabled.
|
||||||
|
class WebPreferencesAttribute extends WebViewAttribute {
|
||||||
|
constructor (webViewImpl) {
|
||||||
|
super(webViewConstants.ATTRIBUTE_WEBPREFERENCES, webViewImpl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sets up all of the webview attributes.
|
// Sets up all of the webview attributes.
|
||||||
WebViewImpl.prototype.setupWebViewAttributes = function () {
|
WebViewImpl.prototype.setupWebViewAttributes = function () {
|
||||||
this.attributes = {}
|
this.attributes = {}
|
||||||
|
@ -328,6 +335,7 @@ WebViewImpl.prototype.setupWebViewAttributes = function () {
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_BLINKFEATURES] = new BlinkFeaturesAttribute(this)
|
this.attributes[webViewConstants.ATTRIBUTE_BLINKFEATURES] = new BlinkFeaturesAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES] = new DisableBlinkFeaturesAttribute(this)
|
this.attributes[webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES] = new DisableBlinkFeaturesAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_GUESTINSTANCE] = new GuestInstanceAttribute(this)
|
this.attributes[webViewConstants.ATTRIBUTE_GUESTINSTANCE] = new GuestInstanceAttribute(this)
|
||||||
|
this.attributes[webViewConstants.ATTRIBUTE_WEBPREFERENCES] = new WebPreferencesAttribute(this)
|
||||||
|
|
||||||
const autosizeAttributes = [webViewConstants.ATTRIBUTE_MAXHEIGHT, webViewConstants.ATTRIBUTE_MAXWIDTH, webViewConstants.ATTRIBUTE_MINHEIGHT, webViewConstants.ATTRIBUTE_MINWIDTH]
|
const autosizeAttributes = [webViewConstants.ATTRIBUTE_MAXHEIGHT, webViewConstants.ATTRIBUTE_MAXWIDTH, webViewConstants.ATTRIBUTE_MINHEIGHT, webViewConstants.ATTRIBUTE_MINWIDTH]
|
||||||
autosizeAttributes.forEach((attribute) => {
|
autosizeAttributes.forEach((attribute) => {
|
||||||
|
|
|
@ -18,6 +18,7 @@ module.exports = {
|
||||||
ATTRIBUTE_BLINKFEATURES: 'blinkfeatures',
|
ATTRIBUTE_BLINKFEATURES: 'blinkfeatures',
|
||||||
ATTRIBUTE_DISABLEBLINKFEATURES: 'disableblinkfeatures',
|
ATTRIBUTE_DISABLEBLINKFEATURES: 'disableblinkfeatures',
|
||||||
ATTRIBUTE_GUESTINSTANCE: 'guestinstance',
|
ATTRIBUTE_GUESTINSTANCE: 'guestinstance',
|
||||||
|
ATTRIBUTE_WEBPREFERENCES: 'webpreferences',
|
||||||
|
|
||||||
// Internal attribute.
|
// Internal attribute.
|
||||||
ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid',
|
ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid',
|
||||||
|
|
|
@ -406,6 +406,33 @@ describe('<webview> tag', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('webpreferences attribute', function () {
|
||||||
|
it('can enable nodeintegration', function (done) {
|
||||||
|
webview.addEventListener('console-message', function (e) {
|
||||||
|
assert.equal(e.message, 'function object object')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
webview.setAttribute('webpreferences', 'nodeIntegration')
|
||||||
|
webview.src = 'file://' + fixtures + '/pages/d.html'
|
||||||
|
document.body.appendChild(webview)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can disables web security and enable nodeintegration', function (done) {
|
||||||
|
var jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js')
|
||||||
|
var src = `<script src='file://${jqueryPath}'></script> <script>console.log('ok '+(typeof require));</script>`
|
||||||
|
var encoded = btoa(unescape(encodeURIComponent(src)))
|
||||||
|
var listener = function (e) {
|
||||||
|
assert.equal(e.message, 'ok function')
|
||||||
|
webview.removeEventListener('console-message', listener)
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
webview.addEventListener('console-message', listener)
|
||||||
|
webview.setAttribute('webpreferences', 'webSecurity=no, nodeIntegration=yes')
|
||||||
|
webview.src = 'data:text/html;base64,' + encoded
|
||||||
|
document.body.appendChild(webview)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('new-window event', function () {
|
describe('new-window event', function () {
|
||||||
if (process.env.TRAVIS === 'true' && process.platform === 'darwin') {
|
if (process.env.TRAVIS === 'true' && process.platform === 'darwin') {
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue