Merge branch 'master' into certificate-addition-windows

This commit is contained in:
Brendan Forster 2017-04-27 14:47:50 +10:00
Родитель 80212c0ab4 dafd0b6c3c
Коммит 50af70a0e8
23 изменённых файлов: 279 добавлений и 80 удалений

Просмотреть файл

@ -7,6 +7,7 @@
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/node_includes.h"
#include "base/time/time.h"
@ -47,7 +48,9 @@ void AutoUpdater::OnError(const std::string& message) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
EmitCustomEvent(
mate::EmitEvent(
isolate(),
GetWrapper(),
"error",
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
// Message is also emitted to keep compatibility with old code.

Просмотреть файл

@ -191,6 +191,10 @@ void Window::OnWindowClosed() {
FROM_HERE, GetDestroyClosure());
}
void Window::OnWindowEndSession() {
Emit("session-end");
}
void Window::OnWindowBlur() {
Emit("blur");
}

Просмотреть файл

@ -63,6 +63,7 @@ class Window : public mate::TrackableObject<Window>,
void WillCloseWindow(bool* prevent_default) override;
void WillDestroyNativeObject() override;
void OnWindowClosed() override;
void OnWindowEndSession() override;
void OnWindowBlur() override;
void OnWindowFocus() override;
void OnWindowShow() override;

Просмотреть файл

@ -474,6 +474,11 @@ void NativeWindow::NotifyWindowClosed() {
observer.OnWindowClosed();
}
void NativeWindow::NotifyWindowEndSession() {
for (NativeWindowObserver& observer : observers_)
observer.OnWindowEndSession();
}
void NativeWindow::NotifyWindowBlur() {
for (NativeWindowObserver& observer : observers_)
observer.OnWindowBlur();

Просмотреть файл

@ -218,6 +218,7 @@ class NativeWindow : public base::SupportsUserData,
// Public API used by platform-dependent delegates and observers to send UI
// related notifications.
void NotifyWindowClosed();
void NotifyWindowEndSession();
void NotifyWindowBlur();
void NotifyWindowFocus();
void NotifyWindowShow();

Просмотреть файл

@ -40,6 +40,9 @@ class NativeWindowObserver {
// Called when the window is closed.
virtual void OnWindowClosed() {}
// Called when Windows sends WM_ENDSESSION message
virtual void OnWindowEndSession() {}
// Called when window loses focus.
virtual void OnWindowBlur() {}

Просмотреть файл

@ -147,6 +147,11 @@ bool NativeWindowViews::PreHandleMSG(
}
return false;
}
case WM_ENDSESSION: {
if (w_param) {
NotifyWindowEndSession();
}
}
default:
return false;
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

45
default_app/renderer.js Normal file
Просмотреть файл

@ -0,0 +1,45 @@
const {remote, shell} = require('electron')
const {execFile} = require('child_process')
const {execPath} = remote.process
document.onclick = function (e) {
e.preventDefault()
if (e.target.tagName === 'A') {
shell.openExternal(e.target.href)
}
return false
}
document.ondragover = document.ondrop = function (e) {
e.preventDefault()
return false
}
const holder = document.getElementById('holder')
holder.ondragover = function () {
this.className = 'hover'
return false
}
holder.ondragleave = holder.ondragend = function () {
this.className = ''
return false
}
holder.ondrop = function (e) {
this.className = ''
e.preventDefault()
const file = e.dataTransfer.files[0]
execFile(execPath, [file.path], {
detached: true, stdio: 'ignore'
}).unref()
return false
}
const version = process.versions.electron
document.querySelector('.header-version').innerText = version
document.querySelector('.command-example').innerText = `${execPath} path-to-your-app`
document.querySelector('.quick-start-link').href = `https://github.com/electron/electron/blob/v${version}/docs/tutorial/quick-start.md`
document.querySelector('.docs-link').href = `https://github.com/electron/electron/tree/v${version}/docs#readme`

Просмотреть файл

@ -376,6 +376,11 @@ window.onbeforeunload = (e) => {
Emitted when the window is closed. After you have received this event you should
remove the reference to the window and avoid using it any more.
#### Event: 'session-end' _Windows_
Emitted when window session is going to end due to force shutdown or machine restart
or session log off.
#### Event: 'unresponsive'
Emitted when the web page becomes unresponsive.

Просмотреть файл

@ -100,6 +100,8 @@ Returns `Boolean` - Whether the download is paused.
Resumes the download that has been paused.
**Note:** To enable resumable downloads the server you are downloading from must support range requests and provide both `Last-Modified` and `ETag` header values. Otherwise `resume()` will dismiss previously received bytes and restart the download from the beginning.
#### `downloadItem.canResume()`
Resumes `Boolean` - Whether the download can resume.

Просмотреть файл

@ -70,7 +70,7 @@ The `role` property can have following values:
* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.)
* `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.)
The following additional roles are avaiable on macOS:
The following additional roles are available on macOS:
* `about` - Map to the `orderFrontStandardAboutPanel` action
* `hide` - Map to the `hide` action
@ -120,4 +120,4 @@ A String representing the menu items visible label
#### `menuItem.click`
A Function that is fired when the MenuItem recieves a click event
A Function that is fired when the MenuItem receives a click event

Просмотреть файл

@ -30,6 +30,10 @@ has to be a field of `BrowserWindow`'s options.
* Node integration will always be disabled in the opened `window` if it is
disabled on the parent window.
* Context isolation will always be enabled in the opened `window` if it is
enabled on the parent window.
* JavaScript will always be disabled in the opened `window` if it is disabled on
the parent window.
* Non-standard features (that are not handled by Chromium or Electron) given in
`features` will be passed to any registered `webContent`'s `new-window` event
handler in the `additionalFeatures` argument.

Просмотреть файл

@ -148,7 +148,7 @@ npm uninstall electron
npm uninstall -g electron
```
However if your are using the built-in module but still getting this error, it
However if you are using the built-in module but still getting this error, it
is very likely you are using the module in the wrong process. For example
`electron.app` can only be used in the main process, while `electron.webFrame`
is only available in renderer processes.

Просмотреть файл

@ -36,8 +36,8 @@ are fine differences.
* On Windows 8.1 and Windows 8, a shortcut to your app, with a [Application User
Model ID][app-user-model-id], must be installed to the Start screen. Note,
however, that it does not need to be pinned to the Start screen.
* On Windows 7, notifications are not supported. You can however send
"balloon notifications" using the [Tray API][tray-balloon].
* On Windows 7, notifications work via a custom implemetation which visually
resembles the native one on newer systems.
Furthermore, the maximum length for the notification body is 250 characters,
with the Windows team recommending that notifications should be kept to 200

Просмотреть файл

@ -89,6 +89,7 @@
'default_app/index.html',
'default_app/main.js',
'default_app/package.json',
'default_app/renderer.js',
],
'lib_sources': [
'atom/app/atom_content_client.cc',

Просмотреть файл

@ -5,7 +5,7 @@ const {isSameOrigin} = process.atomBinding('v8_util')
const parseFeaturesString = require('../common/parse-features-string')
const hasProp = {}.hasOwnProperty
const frameToGuest = {}
const frameToGuest = new Map()
// Copy attribute of |parent| to |child| if it is not defined in |child|.
const mergeOptions = function (child, parent, visited) {
@ -48,11 +48,16 @@ const mergeBrowserWindowOptions = function (embedder, options) {
options.webPreferences.nodeIntegration = false
}
// Enable context isolation on child window if enable on parent window
// Enable context isolation on child window if enabled on parent window
if (embedder.getWebPreferences().contextIsolation === true) {
options.webPreferences.contextIsolation = true
}
// Disable JavaScript on child window if disabled on parent window
if (embedder.getWebPreferences().javascript === false) {
options.webPreferences.javascript = false
}
// Sets correct openerId here to give correct options to 'new-window' event handler
options.webPreferences.openerId = embedder.id
@ -87,10 +92,10 @@ const setupGuest = function (embedder, frameName, guest, options) {
guest.once('closed', closedByUser)
}
if (frameName) {
frameToGuest[frameName] = guest
frameToGuest.set(frameName, guest)
guest.frameName = frameName
guest.once('closed', function () {
delete frameToGuest[frameName]
frameToGuest.delete(frameName)
})
}
return guestId
@ -98,7 +103,7 @@ const setupGuest = function (embedder, frameName, guest, options) {
// Create a new guest created by |embedder| with |options|.
const createGuest = function (embedder, url, frameName, options, postData) {
let guest = frameToGuest[frameName]
let guest = frameToGuest.get(frameName)
if (frameName && (guest != null)) {
guest.loadURL(url)
return guest.webContents.id
@ -186,7 +191,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName,
const options = {}
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload']
const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload', 'javascript', 'contextIsolation']
const disposition = 'new-window'
// Used to store additional features
@ -197,6 +202,10 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName,
if (value === undefined) {
additionalFeatures.push(key)
} else {
// Don't allow webPreferences to be set since it must be an object
// that cannot be directly overridden
if (key === 'webPreferences') return
if (webPreferences.includes(key)) {
if (options.webPreferences == null) {
options.webPreferences = {}

Просмотреть файл

@ -78,7 +78,7 @@ for (let arg of process.argv) {
if (window.location.protocol === 'chrome-devtools:') {
// Override some inspector APIs.
require('./inspector')
nodeIntegration = 'true'
nodeIntegration = 'false'
} else if (window.location.protocol === 'chrome-extension:') {
// Add implementations of chrome API.
require('./chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)

Просмотреть файл

@ -32,6 +32,13 @@ const resolveURL = function (url) {
return a.href
}
// Use this method to ensure values expected as strings in the main process
// are convertible to strings in the renderer process. This ensures exceptions
// converting values to strings are thrown in this process.
const toString = (value) => {
return value != null ? `${value}` : value
}
const windowProxies = {}
const getOrCreateProxy = (ipcRenderer, guestId) => {
@ -82,7 +89,7 @@ function BrowserWindowProxy (ipcRenderer, guestId) {
}
this.postMessage = (message, targetOrigin) => {
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, targetOrigin, window.location.origin)
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, toString(targetOrigin), window.location.origin)
}
this.eval = (...args) => {
@ -112,7 +119,7 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => {
if (url != null && url !== '') {
url = resolveURL(url)
}
const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, features)
const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, toString(frameName), toString(features))
if (guestId != null) {
return getOrCreateProxy(ipcRenderer, guestId)
} else {
@ -121,11 +128,11 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => {
}
window.alert = function (message, title) {
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', toString(message), toString(title))
}
window.confirm = function (message, title) {
return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', toString(message), toString(title))
}
// But we do not support prompt().
@ -157,7 +164,7 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => {
}
window.history.go = function (offset) {
sendHistoryOperation(ipcRenderer, 'goToOffset', offset)
sendHistoryOperation(ipcRenderer, 'goToOffset', +offset)
}
defineProperty(window.history, 'length', {

Просмотреть файл

@ -1,6 +1,6 @@
const assert = require('assert')
const autoUpdater = require('electron').remote.autoUpdater
const ipcRenderer = require('electron').ipcRenderer
const {autoUpdater} = require('electron').remote
const {ipcRenderer} = require('electron')
// Skip autoUpdater tests in MAS build.
if (!process.mas) {
@ -64,5 +64,25 @@ if (!process.mas) {
autoUpdater.quitAndInstall()
})
})
describe('error event', function () {
it('serializes correctly over the remote module', function (done) {
if (process.platform === 'linux') {
return done()
}
autoUpdater.once('error', function (error) {
assert.equal(error instanceof Error, true)
assert.deepEqual(Object.getOwnPropertyNames(error), ['stack', 'message', 'name'])
done()
})
autoUpdater.setFeedURL('')
if (process.platform === 'win32') {
autoUpdater.checkForUpdates()
}
})
})
})
}

Просмотреть файл

@ -229,6 +229,45 @@ describe('chromium feature', function () {
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
})
it('disables node integration when it is disabled on the parent window for chrome devtools URLs', function (done) {
var b
app.once('web-contents-created', (event, contents) => {
contents.once('did-finish-load', () => {
contents.executeJavaScript('typeof process').then((typeofProcessGlobal) => {
assert.equal(typeofProcessGlobal, 'undefined')
b.close()
done()
}).catch(done)
})
})
b = window.open('chrome-devtools://devtools/bundled/inspector.html', '', 'nodeIntegration=no,show=no')
})
it('disables JavaScript when it is disabled on the parent window', function (done) {
var b
app.once('web-contents-created', (event, contents) => {
contents.once('did-finish-load', () => {
app.once('browser-window-created', (event, window) => {
const preferences = window.webContents.getWebPreferences()
assert.equal(preferences.javascript, false)
window.destroy()
b.close()
done()
})
// Click link on page
contents.sendInputEvent({type: 'mouseDown', clickCount: 1, x: 1, y: 1})
contents.sendInputEvent({type: 'mouseUp', clickCount: 1, x: 1, y: 1})
})
})
var windowUrl = require('url').format({
pathname: `${fixtures}/pages/window-no-javascript.html`,
protocol: 'file',
slashes: true
})
b = window.open(windowUrl, '', 'javascript=no,show=no')
})
it('does not override child options', function (done) {
var b, size
size = {
@ -322,6 +361,44 @@ describe('chromium feature', function () {
})
b = window.open()
})
it('throws an exception when the arguments cannot be converted to strings', function () {
assert.throws(function () {
window.open('', {toString: null})
}, /Cannot convert object to primitive value/)
assert.throws(function () {
window.open('', '', {toString: 3})
}, /Cannot convert object to primitive value/)
})
it('sets the window title to the specified frameName', function (done) {
let b
app.once('browser-window-created', (event, createdWindow) => {
assert.equal(createdWindow.getTitle(), 'hello')
b.close()
done()
})
b = window.open('', 'hello')
})
it('does not throw an exception when the frameName is a built-in object property', function (done) {
let b
app.once('browser-window-created', (event, createdWindow) => {
assert.equal(createdWindow.getTitle(), '__proto__')
b.close()
done()
})
b = window.open('', '__proto__')
})
it('does not throw an exception when the features include webPreferences', function () {
let b
assert.doesNotThrow(function () {
b = window.open('', '', 'webPreferences=')
})
b.close()
})
})
describe('window.opener', function () {
@ -499,6 +576,14 @@ describe('chromium feature', function () {
})
b = window.open('file://' + fixtures + '/pages/window-open-postMessage.html', '', 'show=no')
})
it('throws an exception when the targetOrigin cannot be converted to a string', function () {
var b = window.open('')
assert.throws(function () {
b.postMessage('test', {toString: null})
}, /Cannot convert object to primitive value/)
b.close()
})
})
describe('window.opener.postMessage', function () {
@ -880,4 +965,36 @@ describe('chromium feature', function () {
})
})
})
describe('window.alert(message, title)', function () {
it('throws an exception when the arguments cannot be converted to strings', function () {
assert.throws(function () {
window.alert({toString: null})
}, /Cannot convert object to primitive value/)
assert.throws(function () {
window.alert('message', {toString: 3})
}, /Cannot convert object to primitive value/)
})
})
describe('window.confirm(message, title)', function () {
it('throws an exception when the arguments cannot be converted to strings', function () {
assert.throws(function () {
window.confirm({toString: null}, 'title')
}, /Cannot convert object to primitive value/)
assert.throws(function () {
window.confirm('message', {toString: 3})
}, /Cannot convert object to primitive value/)
})
})
describe('window.history.go(offset)', function () {
it('throws an exception when the argumnet cannot be converted to a string', function () {
assert.throws(function () {
window.history.go({toString: null})
}, /Cannot convert object to primitive value/)
})
})
})

12
spec/fixtures/pages/window-no-javascript.html поставляемый Normal file
Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<style>
* {
padding: 0;
margin: 0;
}
</style>
<body>
<a href="about:blank>" target="_blank">CLICK</a>
</body>
</html>

Просмотреть файл

@ -2,20 +2,15 @@
process.throwDeprecation = true
const electron = require('electron')
const app = electron.app
const crashReporter = electron.crashReporter
const ipcMain = electron.ipcMain
const dialog = electron.dialog
const BrowserWindow = electron.BrowserWindow
const protocol = electron.protocol
const webContents = electron.webContents
const v8 = require('v8')
const {app, BrowserWindow, crashReporter, dialog, ipcMain, protocol, webContents} = electron
const {Coverage} = require('electabul')
const Coverage = require('electabul').Coverage
const fs = require('fs')
const path = require('path')
const url = require('url')
const util = require('util')
const v8 = require('v8')
var argv = require('yargs')
.boolean('ci')
@ -103,6 +98,12 @@ app.on('window-all-closed', function () {
app.quit()
})
app.on('web-contents-created', (event, contents) => {
contents.on('crashed', (event, killed) => {
console.log(`webContents ${contents.id} crashed: ${contents.getURL()} (killed=${killed})`)
})
})
app.on('ready', function () {
// Test if using protocol module would crash.
electron.protocol.registerStringProtocol('test-if-crashes', function () {})