Compare commits

...

16 Commits

Author SHA1 Message Date
Kevin Sawicki
cb9fdc45e6 Bump v1.3.9 2016-11-16 11:29:03 -08:00
Kevin Sawicki
2dafd845b9 Make scheme const 2016-11-16 11:29:03 -08:00
Kevin Sawicki
9017f90b57 Use sender.id instead of sender.webContents.id 2016-11-16 11:29:03 -08:00
Kevin Sawicki
b94638894e Don't log blocked messages when guestWindow is null 2016-11-16 11:29:03 -08:00
Kevin Sawicki
8a3288d791 Always call done callback in before block 2016-11-16 11:29:03 -08:00
Cheng Zhao
6f5336c63f Fix standard linting errors 2016-11-16 11:29:03 -08:00
Cheng Zhao
73c1fab423 Print error messages 2016-11-16 11:29:03 -08:00
Cheng Zhao
1e36ee918e Do permission check when calling guest window methods 2016-11-16 11:29:03 -08:00
Cheng Zhao
1f49da7a06 spec: Should check origin before accessing window.opener 2016-11-16 11:28:52 -08:00
Kevin Sawicki
037a458e1d Bump v1.3.8 2016-10-20 11:34:18 +09:00
Jacob Groundwater
03a274ee27 Fire a11y event on touch screens using screen readers 2016-10-18 13:52:05 +09:00
Paul Betts
c4bd516b77 Code Cleanup 2016-10-18 13:51:55 +09:00
Paul Betts
4c914c1277 Check harder before enabling Accessibility support 2016-10-18 13:51:34 +09:00
Cheng Zhao
e3688a8e9d Bump v1.3.7 2016-09-27 03:19:21 +00:00
Cheng Zhao
375534cf4a module search paths have changed 2016-09-27 03:00:08 +00:00
Cheng Zhao
397e5ad0ac Update to Node v6.5.0 2016-09-27 02:45:19 +00:00
16 changed files with 149 additions and 32 deletions

View File

@@ -138,7 +138,7 @@ NativeWindowViews::NativeWindowViews(
menu_bar_visible_(false),
menu_bar_alt_pressed_(false),
#if defined(OS_WIN)
enabled_a11y_support_(false),
checked_for_a11y_support_(false),
thick_frame_(true),
#endif
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),

View File

@@ -18,6 +18,8 @@
#include "atom/browser/ui/win/message_handler_delegate.h"
#include "atom/browser/ui/win/taskbar_host.h"
#include "base/win/scoped_gdi_object.h"
#include "ui/base/win/accessibility_misc_utils.h"
#include <UIAutomationCoreApi.h>
#endif
namespace views {
@@ -228,8 +230,8 @@ class NativeWindowViews : public NativeWindow,
// In charge of running taskbar related APIs.
TaskbarHost taskbar_host_;
// If true we have enabled a11y
bool enabled_a11y_support_;
// Memoized version of a11y check
bool checked_for_a11y_support_;
// Whether to show the WS_THICKFRAME style.
bool thick_frame_;

View File

@@ -72,6 +72,12 @@ const char* AppCommandToString(int command_id) {
}
}
bool IsScreenReaderActive() {
UINT screenReader = 0;
SystemParametersInfo(SPI_GETSCREENREADER, 0, &screenReader, 0);
return screenReader && UiaClientsAreListening();
}
} // namespace
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
@@ -91,16 +97,24 @@ bool NativeWindowViews::PreHandleMSG(
// because we still want Chromium to handle returning the actual
// accessibility object.
case WM_GETOBJECT: {
const DWORD obj_id = static_cast<DWORD>(l_param);
if (enabled_a11y_support_) return false;
if (checked_for_a11y_support_) return false;
if (obj_id == OBJID_CLIENT) {
const auto axState = content::BrowserAccessibilityState::GetInstance();
if (axState && !axState->IsAccessibleBrowser()) {
axState->OnScreenReaderDetected();
enabled_a11y_support_ = true;
Browser::Get()->OnAccessibilitySupportChanged();
}
const DWORD obj_id = static_cast<DWORD>(l_param);
if (obj_id != OBJID_CLIENT) {
return false;
}
if (!IsScreenReaderActive()) {
return false;
}
checked_for_a11y_support_ = true;
const auto axState = content::BrowserAccessibilityState::GetInstance();
if (axState && !axState->IsAccessibleBrowser()) {
axState->OnScreenReaderDetected();
Browser::Get()->OnAccessibilitySupportChanged();
}
return false;

View File

@@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>electron.icns</string>
<key>CFBundleVersion</key>
<string>1.3.6</string>
<string>1.3.9</string>
<key>CFBundleShortVersionString</key>
<string>1.3.6</string>
<string>1.3.9</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,3,6,0
PRODUCTVERSION 1,3,6,0
FILEVERSION 1,3,9,0
PRODUCTVERSION 1,3,9,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "1.3.6"
VALUE "FileVersion", "1.3.9"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "1.3.6"
VALUE "ProductVersion", "1.3.9"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -9,9 +9,11 @@
#include "atom/common/api/remote_callback_freer.h"
#include "atom/common/api/remote_object_freer.h"
#include "atom/common/native_mate_converters/content_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h"
#include "base/hash.h"
#include "native_mate/dictionary.h"
#include "url/origin.h"
#include "v8/include/v8-profiler.h"
namespace std {
@@ -92,6 +94,10 @@ void TakeHeapSnapshot(v8::Isolate* isolate) {
isolate->GetHeapProfiler()->TakeHeapSnapshot();
}
bool IsSameOrigin(const GURL& l, const GURL& r) {
return url::Origin(l).IsSameOriginWith(url::Origin(r));
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
@@ -105,6 +111,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap<int32_t>::Create);
dict.SetMethod("createDoubleIDWeakMap",
&atom::api::KeyWeakMap<std::pair<int32_t, int32_t>>::Create);
dict.SetMethod("isSameOrigin", &IsSameOrigin);
}
} // namespace

View File

@@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 1
#define ATOM_MINOR_VERSION 3
#define ATOM_PATCH_VERSION 6
#define ATOM_PATCH_VERSION 9
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -36,6 +36,7 @@
'node_use_perfctr': 'false',
'node_use_v8_platform': 'false',
'node_use_bundled_v8': 'false',
'node_enable_d8': 'false',
'uv_library': 'static_library',
'uv_parent_path': 'vendor/node/deps/uv',
'uv_use_dtrace': 'false',

View File

@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '1.3.6',
'version%': '1.3.9',
},
'includes': [
'filenames.gypi',
@@ -279,6 +279,7 @@
'-lcomdlg32.lib',
'-lwininet.lib',
'-lwinmm.lib',
'-luiautomationcore.lib',
],
},
'dependencies': [

View File

@@ -1,6 +1,7 @@
'use strict'
const {BrowserWindow, ipcMain, webContents} = require('electron')
const {isSameOrigin} = process.atomBinding('v8_util')
const hasProp = {}.hasOwnProperty
const frameToGuest = {}
@@ -100,6 +101,22 @@ const getGuestWindow = function (guestId) {
return guestWindow
}
// Checks whether |sender| can access the |target|:
// 1. Check whether |sender| is the parent of |target|.
// 2. Check whether |sender| has node integration, if so it is allowed to
// do anything it wants.
// 3. Check whether the origins match.
//
// However it allows a child window without node integration but with same
// origin to do anything it wants, when its opener window has node integration.
// The W3C does not have anything on this, but from my understanding of the
// security model of |window.opener|, this should be fine.
const canAccessWindow = function (sender, target) {
return (target.getWebPreferences().openerId === sender.id) ||
(sender.getWebPreferences().nodeIntegration === true) ||
isSameOrigin(sender.getURL(), target.getURL())
}
// Routed window.open messages.
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName, disposition, options) {
options = mergeBrowserWindowOptions(event.sender, options)
@@ -113,18 +130,37 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, fr
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestId) {
const guestWindow = getGuestWindow(guestId)
if (guestWindow != null) guestWindow.destroy()
if (guestWindow == null) return
if (canAccessWindow(event.sender, guestWindow.webContents)) {
guestWindow.destroy()
} else {
console.error(`Blocked ${event.sender.getURL()} from closing its opener.`)
}
})
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) {
const guestWindow = getGuestWindow(guestId)
event.returnValue = guestWindow != null ? guestWindow[method].apply(guestWindow, args) : null
if (guestWindow == null) {
event.returnValue = null
return
}
if (canAccessWindow(event.sender, guestWindow.webContents)) {
event.returnValue = guestWindow[method].apply(guestWindow, args)
} else {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
event.returnValue = null
}
})
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, guestId, message, targetOrigin, sourceOrigin) {
const guestContents = webContents.fromId(guestId)
if (guestContents == null) return
// The W3C does not seem to have word on how postMessage should work when the
// origins do not match, so we do not do |canAccessWindow| check here since
// postMessage across origins is useful and not harmful.
if (guestContents.getURL().indexOf(targetOrigin) === 0 || targetOrigin === '*') {
const sourceId = event.sender.id
guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin)
@@ -133,5 +169,11 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event,
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) {
const guestContents = webContents.fromId(guestId)
if (guestContents != null) guestContents[method].apply(guestContents, args)
if (guestContents == null) return
if (canAccessWindow(event.sender, guestContents)) {
guestContents[method].apply(guestContents, args)
} else {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
}
})

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "1.3.6",
"version": "1.3.9",
"devDependencies": {
"asar": "^0.11.0",
"electabul": "~0.0.4",

View File

@@ -5,7 +5,7 @@ const ws = require('ws')
const url = require('url')
const remote = require('electron').remote
const {BrowserWindow, session, webContents} = remote
const {BrowserWindow, protocol, session, webContents} = remote
const isCI = remote.getGlobal('isCi')
@@ -283,11 +283,11 @@ describe('chromium feature', function () {
describe('window.opener', function () {
this.timeout(10000)
var url = 'file://' + fixtures + '/pages/window-opener.html'
var w = null
let url = 'file://' + fixtures + '/pages/window-opener.html'
let w = null
afterEach(function () {
w != null ? w.destroy() : void 0
if (w) w.destroy()
})
it('is null for main window', function (done) {
@@ -302,7 +302,7 @@ describe('chromium feature', function () {
})
it('is not null for window opened by window.open', function (done) {
var b
let b
listener = function (event) {
assert.equal(event.data, 'object')
b.close()
@@ -313,6 +313,48 @@ describe('chromium feature', function () {
})
})
describe('window.opener security', function () {
this.timeout(10000)
const scheme = 'other'
let url = `${scheme}://${fixtures}/pages/window-opener-location.html`
let w = null
before(function (done) {
protocol.registerFileProtocol(scheme, function (request, callback) {
callback(`${fixtures}/pages/window-opener-location.html`)
}, function (error) {
done(error)
})
})
after(function () {
protocol.unregisterProtocol(scheme)
})
afterEach(function () {
w.close()
})
it('does nothing when origin of current window does not match opener', function (done) {
listener = function (event) {
assert.equal(event.data, undefined)
done()
}
window.addEventListener('message', listener)
w = window.open(url, '', 'show=no')
})
it('works when origin does not match opener but has node integration', function (done) {
listener = function (event) {
assert.equal(event.data, location.href)
done()
}
window.addEventListener('message', listener)
w = window.open(url, '', 'show=no,nodeIntegration=yes')
})
})
describe('window.postMessage', function () {
it('sets the source and origin correctly', function (done) {
var b, sourceId

View File

@@ -0,0 +1,7 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
window.opener.postMessage(window.opener.location, '*')
</script>
</body>
</html>

View File

@@ -94,7 +94,8 @@ describe('Module._nodeModulePaths', function () {
it('includes paths outside of the resources path', function () {
let modulePath = path.resolve('/foo')
assert.deepEqual(Module._nodeModulePaths(modulePath), [
path.join(modulePath, 'node_modules')
path.join(modulePath, 'node_modules'),
path.resolve('/node_modules')
])
})
})

2
vendor/node vendored