mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-11-25 02:10:32 -06:00
ELECTRON-661 (Security fix for pop-outs RCE) (#450)
- Security fix for pop-outs RCE - Bump Electron version to 2.0.6
This commit is contained in:
parent
e441deeb1d
commit
76b995d064
381
js/windowMgr.js
381
js/windowMgr.js
@ -371,194 +371,209 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// open external links in default browser - a tag with href='_blank' or window.open
|
// open external links in default browser - a tag with href='_blank' or window.open
|
||||||
mainWindow.webContents.on('new-window', handleNewWindow);
|
const enforceInheritance = (topWebContents) => {
|
||||||
|
const handleNewWindow = (webContents) => {
|
||||||
|
webContents.on('new-window', (event, newWinUrl, frameName, disposition, newWinOptions) => {
|
||||||
|
if (!newWinOptions.webPreferences) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
newWinOptions.webPreferences = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(newWinOptions.webPreferences, topWebContents);
|
||||||
|
|
||||||
|
let newWinParsedUrl = getParsedUrl(newWinUrl);
|
||||||
|
let mainWinParsedUrl = getParsedUrl(url);
|
||||||
|
|
||||||
|
let newWinHost = newWinParsedUrl && newWinParsedUrl.host;
|
||||||
|
let mainWinHost = mainWinParsedUrl && mainWinParsedUrl.host;
|
||||||
|
|
||||||
|
let emptyUrlString = 'about:blank';
|
||||||
|
let dispositionWhitelist = ['new-window', 'foreground-tab'];
|
||||||
|
|
||||||
|
// only allow window.open to succeed is if coming from same hsot,
|
||||||
|
// otherwise open in default browser.
|
||||||
|
if ((newWinHost === mainWinHost || newWinUrl === emptyUrlString) && dispositionWhitelist.includes(disposition)) {
|
||||||
|
// handle: window.open
|
||||||
|
|
||||||
|
if (!frameName) {
|
||||||
|
// abort - no frame name provided.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.send(logLevels.INFO, 'creating pop-out window url: ' + newWinParsedUrl);
|
||||||
|
|
||||||
|
let x = 0;
|
||||||
|
let y = 0;
|
||||||
|
|
||||||
|
let width = newWinOptions.width || DEFAULT_WIDTH;
|
||||||
|
let height = newWinOptions.height || DEFAULT_HEIGHT;
|
||||||
|
|
||||||
|
// try getting x and y position from query parameters
|
||||||
|
let query = newWinParsedUrl && querystring.parse(newWinParsedUrl.query);
|
||||||
|
if (query && query.x && query.y) {
|
||||||
|
let newX = Number.parseInt(query.x, 10);
|
||||||
|
let newY = Number.parseInt(query.y, 10);
|
||||||
|
|
||||||
|
let newWinRect = { x: newX, y: newY, width, height };
|
||||||
|
|
||||||
|
// only accept if both are successfully parsed.
|
||||||
|
if (Number.isInteger(newX) && Number.isInteger(newY) &&
|
||||||
|
isInDisplayBounds(newWinRect)) {
|
||||||
|
x = newX;
|
||||||
|
y = newY;
|
||||||
|
} else {
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// create new window at slight offset from main window.
|
||||||
|
({ x, y } = getWindowSizeAndPosition(mainWindow));
|
||||||
|
x += 50;
|
||||||
|
y += 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
newWinOptions.x = x;
|
||||||
|
newWinOptions.y = y;
|
||||||
|
newWinOptions.width = Math.max(width, DEFAULT_WIDTH);
|
||||||
|
newWinOptions.height = Math.max(height, DEFAULT_HEIGHT);
|
||||||
|
newWinOptions.minWidth = MIN_WIDTH;
|
||||||
|
newWinOptions.minHeight = MIN_HEIGHT;
|
||||||
|
newWinOptions.alwaysOnTop = alwaysOnTop;
|
||||||
|
newWinOptions.frame = true;
|
||||||
|
|
||||||
|
let newWinKey = getGuid();
|
||||||
|
|
||||||
|
newWinOptions.winKey = newWinKey;
|
||||||
|
/* eslint-enable no-param-reassign */
|
||||||
|
|
||||||
|
let childWebContents = newWinOptions.webContents;
|
||||||
|
|
||||||
|
// Event needed to hide native menu bar
|
||||||
|
childWebContents.once('did-start-loading', () => {
|
||||||
|
let browserWin = BrowserWindow.fromWebContents(childWebContents);
|
||||||
|
if (isWindowsOS && browserWin && !browserWin.isDestroyed()) {
|
||||||
|
browserWin.setMenuBarVisibility(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
childWebContents.once('did-finish-load', function () {
|
||||||
|
let browserWin = BrowserWindow.fromWebContents(childWebContents);
|
||||||
|
|
||||||
|
if (browserWin) {
|
||||||
|
log.send(logLevels.INFO, 'loaded pop-out window url: ' + newWinParsedUrl);
|
||||||
|
|
||||||
|
if (!isMac) {
|
||||||
|
// Removes the menu bar from the pop-out window
|
||||||
|
// setMenu is currently only supported on Windows and Linux
|
||||||
|
browserWin.setMenu(null);
|
||||||
|
}
|
||||||
|
browserWin.webContents.send('on-page-load');
|
||||||
|
// applies styles required for snack bar
|
||||||
|
browserWin.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/snackBar/style.css'), 'utf8').toString());
|
||||||
|
|
||||||
|
initCrashReporterMain({ process: 'pop-out window' });
|
||||||
|
initCrashReporterRenderer(browserWin, { process: 'render | pop-out window' });
|
||||||
|
|
||||||
|
browserWin.winName = frameName;
|
||||||
|
browserWin.setAlwaysOnTop(alwaysOnTop);
|
||||||
|
|
||||||
|
let handleChildWindowCrashEvent = (e) => {
|
||||||
|
const options = {
|
||||||
|
type: 'error',
|
||||||
|
title: i18n.getMessageFor('Renderer Process Crashed'),
|
||||||
|
message: i18n.getMessageFor('Oops! Looks like we have had a crash. Please reload or close this window.'),
|
||||||
|
buttons: ['Reload', 'Close']
|
||||||
|
};
|
||||||
|
|
||||||
|
let childBrowserWindow = BrowserWindow.fromWebContents(e.sender);
|
||||||
|
if (childBrowserWindow && !childBrowserWindow.isDestroyed()) {
|
||||||
|
electron.dialog.showMessageBox(childBrowserWindow, options, function (index) {
|
||||||
|
if (index === 0) {
|
||||||
|
childBrowserWindow.reload();
|
||||||
|
} else {
|
||||||
|
childBrowserWindow.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
browserWin.webContents.on('crashed', handleChildWindowCrashEvent);
|
||||||
|
|
||||||
|
// In case we navigate to an external link from inside a pop-out,
|
||||||
|
// we open that link in an external browser rather than creating
|
||||||
|
// a new window
|
||||||
|
if (browserWin.webContents) {
|
||||||
|
handleNewWindow(browserWin.webContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
addWindowKey(newWinKey, browserWin);
|
||||||
|
|
||||||
|
// Method that sends bound changes as soon
|
||||||
|
// as a new window is created
|
||||||
|
// issue https://perzoinc.atlassian.net/browse/ELECTRON-172
|
||||||
|
sendChildWinBoundsChange(browserWin);
|
||||||
|
|
||||||
|
// throttle full screen
|
||||||
|
let throttledFullScreen = throttle(1000,
|
||||||
|
handleChildWindowFullScreen.bind(null, browserWin));
|
||||||
|
|
||||||
|
// throttle leave full screen
|
||||||
|
let throttledLeaveFullScreen = throttle(1000,
|
||||||
|
handleChildWindowLeaveFullScreen.bind(null, browserWin));
|
||||||
|
|
||||||
|
// throttle changes so we don't flood client.
|
||||||
|
let throttledBoundsChange = throttle(1000,
|
||||||
|
sendChildWinBoundsChange.bind(null, browserWin));
|
||||||
|
|
||||||
|
browserWin.on('move', throttledBoundsChange);
|
||||||
|
browserWin.on('resize', throttledBoundsChange);
|
||||||
|
browserWin.on('enter-full-screen', throttledFullScreen);
|
||||||
|
browserWin.on('leave-full-screen', throttledLeaveFullScreen);
|
||||||
|
|
||||||
|
let handleChildWindowClosed = () => {
|
||||||
|
removeWindowKey(newWinKey);
|
||||||
|
browserWin.removeListener('move', throttledBoundsChange);
|
||||||
|
browserWin.removeListener('resize', throttledBoundsChange);
|
||||||
|
browserWin.removeListener('enter-full-screen', throttledFullScreen);
|
||||||
|
browserWin.removeListener('leave-full-screen', throttledLeaveFullScreen);
|
||||||
|
};
|
||||||
|
|
||||||
|
browserWin.on('close', () => {
|
||||||
|
browserWin.webContents.removeListener('crashed', handleChildWindowCrashEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
browserWin.once('closed', () => {
|
||||||
|
handleChildWindowClosed();
|
||||||
|
});
|
||||||
|
|
||||||
|
handlePermissionRequests(browserWin.webContents);
|
||||||
|
|
||||||
|
if (!isDevEnv) {
|
||||||
|
browserWin.webContents.session.setCertificateVerifyProc(handleCertificateTransparencyChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
browserWin.webContents.on('devtools-opened', () => {
|
||||||
|
handleDevTools(browserWin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
openUrlInDefaultBrowser(newWinUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
handleNewWindow(topWebContents);
|
||||||
|
};
|
||||||
|
|
||||||
if (!isDevEnv) {
|
if (!isDevEnv) {
|
||||||
mainWindow.webContents.session.setCertificateVerifyProc(handleCertificateTransparencyChecks);
|
mainWindow.webContents.session.setCertificateVerifyProc(handleCertificateTransparencyChecks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNewWindow(event, newWinUrl, frameName, disposition, newWinOptions) {
|
// enforce main window's webPreferences to child windows
|
||||||
|
if (mainWindow.webContents) {
|
||||||
let newWinParsedUrl = getParsedUrl(newWinUrl);
|
enforceInheritance(mainWindow.webContents);
|
||||||
let mainWinParsedUrl = getParsedUrl(url);
|
|
||||||
|
|
||||||
let newWinHost = newWinParsedUrl && newWinParsedUrl.host;
|
|
||||||
let mainWinHost = mainWinParsedUrl && mainWinParsedUrl.host;
|
|
||||||
|
|
||||||
let emptyUrlString = 'about:blank';
|
|
||||||
let dispositionWhitelist = ['new-window', 'foreground-tab'];
|
|
||||||
|
|
||||||
// only allow window.open to succeed is if coming from same hsot,
|
|
||||||
// otherwise open in default browser.
|
|
||||||
if ((newWinHost === mainWinHost || newWinUrl === emptyUrlString) && dispositionWhitelist.includes(disposition)) {
|
|
||||||
// handle: window.open
|
|
||||||
|
|
||||||
if (!frameName) {
|
|
||||||
// abort - no frame name provided.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.send(logLevels.INFO, 'creating pop-out window url: ' + newWinParsedUrl);
|
|
||||||
|
|
||||||
let x = 0;
|
|
||||||
let y = 0;
|
|
||||||
|
|
||||||
let width = newWinOptions.width || DEFAULT_WIDTH;
|
|
||||||
let height = newWinOptions.height || DEFAULT_HEIGHT;
|
|
||||||
|
|
||||||
// try getting x and y position from query parameters
|
|
||||||
let query = newWinParsedUrl && querystring.parse(newWinParsedUrl.query);
|
|
||||||
if (query && query.x && query.y) {
|
|
||||||
let newX = Number.parseInt(query.x, 10);
|
|
||||||
let newY = Number.parseInt(query.y, 10);
|
|
||||||
|
|
||||||
let newWinRect = { x: newX, y: newY, width, height };
|
|
||||||
|
|
||||||
// only accept if both are successfully parsed.
|
|
||||||
if (Number.isInteger(newX) && Number.isInteger(newY) &&
|
|
||||||
isInDisplayBounds(newWinRect)) {
|
|
||||||
x = newX;
|
|
||||||
y = newY;
|
|
||||||
} else {
|
|
||||||
x = 0;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// create new window at slight offset from main window.
|
|
||||||
({ x, y } = getWindowSizeAndPosition(mainWindow));
|
|
||||||
x += 50;
|
|
||||||
y += 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
newWinOptions.x = x;
|
|
||||||
newWinOptions.y = y;
|
|
||||||
newWinOptions.width = Math.max(width, DEFAULT_WIDTH);
|
|
||||||
newWinOptions.height = Math.max(height, DEFAULT_HEIGHT);
|
|
||||||
newWinOptions.minWidth = MIN_WIDTH;
|
|
||||||
newWinOptions.minHeight = MIN_HEIGHT;
|
|
||||||
newWinOptions.alwaysOnTop = alwaysOnTop;
|
|
||||||
newWinOptions.frame = true;
|
|
||||||
|
|
||||||
let newWinKey = getGuid();
|
|
||||||
|
|
||||||
newWinOptions.winKey = newWinKey;
|
|
||||||
/* eslint-enable no-param-reassign */
|
|
||||||
|
|
||||||
let webContents = newWinOptions.webContents;
|
|
||||||
|
|
||||||
// Event needed to hide native menu bar
|
|
||||||
webContents.once('did-start-loading', () => {
|
|
||||||
let browserWin = BrowserWindow.fromWebContents(webContents);
|
|
||||||
if (isWindowsOS && browserWin && !browserWin.isDestroyed()) {
|
|
||||||
browserWin.setMenuBarVisibility(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
webContents.once('did-finish-load', function () {
|
|
||||||
let browserWin = BrowserWindow.fromWebContents(webContents);
|
|
||||||
|
|
||||||
if (browserWin) {
|
|
||||||
log.send(logLevels.INFO, 'loaded pop-out window url: ' + newWinParsedUrl);
|
|
||||||
|
|
||||||
if (!isMac) {
|
|
||||||
// Removes the menu bar from the pop-out window
|
|
||||||
// setMenu is currently only supported on Windows and Linux
|
|
||||||
browserWin.setMenu(null);
|
|
||||||
}
|
|
||||||
browserWin.webContents.send('on-page-load');
|
|
||||||
// applies styles required for snack bar
|
|
||||||
browserWin.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/snackBar/style.css'), 'utf8').toString());
|
|
||||||
|
|
||||||
initCrashReporterMain({ process: 'pop-out window' });
|
|
||||||
initCrashReporterRenderer(browserWin, { process: 'render | pop-out window' });
|
|
||||||
|
|
||||||
browserWin.winName = frameName;
|
|
||||||
browserWin.setAlwaysOnTop(alwaysOnTop);
|
|
||||||
|
|
||||||
let handleChildWindowCrashEvent = (e) => {
|
|
||||||
const options = {
|
|
||||||
type: 'error',
|
|
||||||
title: i18n.getMessageFor('Renderer Process Crashed'),
|
|
||||||
message: i18n.getMessageFor('Oops! Looks like we have had a crash. Please reload or close this window.'),
|
|
||||||
buttons: ['Reload', 'Close']
|
|
||||||
};
|
|
||||||
|
|
||||||
let childBrowserWindow = BrowserWindow.fromWebContents(e.sender);
|
|
||||||
if (childBrowserWindow && !childBrowserWindow.isDestroyed()) {
|
|
||||||
electron.dialog.showMessageBox(childBrowserWindow, options, function (index) {
|
|
||||||
if (index === 0) {
|
|
||||||
childBrowserWindow.reload();
|
|
||||||
} else {
|
|
||||||
childBrowserWindow.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
browserWin.webContents.on('crashed', handleChildWindowCrashEvent);
|
|
||||||
|
|
||||||
// In case we navigate to an external link from inside a pop-out,
|
|
||||||
// we open that link in an external browser rather than creating
|
|
||||||
// a new window
|
|
||||||
browserWin.webContents.on('new-window', handleNewWindow.bind(this));
|
|
||||||
|
|
||||||
addWindowKey(newWinKey, browserWin);
|
|
||||||
|
|
||||||
// Method that sends bound changes as soon
|
|
||||||
// as a new window is created
|
|
||||||
// issue https://perzoinc.atlassian.net/browse/ELECTRON-172
|
|
||||||
sendChildWinBoundsChange(browserWin);
|
|
||||||
|
|
||||||
// throttle full screen
|
|
||||||
let throttledFullScreen = throttle(1000,
|
|
||||||
handleChildWindowFullScreen.bind(null, browserWin));
|
|
||||||
|
|
||||||
// throttle leave full screen
|
|
||||||
let throttledLeaveFullScreen = throttle(1000,
|
|
||||||
handleChildWindowLeaveFullScreen.bind(null, browserWin));
|
|
||||||
|
|
||||||
// throttle changes so we don't flood client.
|
|
||||||
let throttledBoundsChange = throttle(1000,
|
|
||||||
sendChildWinBoundsChange.bind(null, browserWin));
|
|
||||||
|
|
||||||
browserWin.on('move', throttledBoundsChange);
|
|
||||||
browserWin.on('resize', throttledBoundsChange);
|
|
||||||
browserWin.on('enter-full-screen', throttledFullScreen);
|
|
||||||
browserWin.on('leave-full-screen', throttledLeaveFullScreen);
|
|
||||||
|
|
||||||
let handleChildWindowClosed = () => {
|
|
||||||
removeWindowKey(newWinKey);
|
|
||||||
browserWin.removeListener('move', throttledBoundsChange);
|
|
||||||
browserWin.removeListener('resize', throttledBoundsChange);
|
|
||||||
browserWin.removeListener('enter-full-screen', throttledFullScreen);
|
|
||||||
browserWin.removeListener('leave-full-screen', throttledLeaveFullScreen);
|
|
||||||
};
|
|
||||||
|
|
||||||
browserWin.on('close', () => {
|
|
||||||
browserWin.webContents.removeListener('new-window', handleNewWindow);
|
|
||||||
browserWin.webContents.removeListener('crashed', handleChildWindowCrashEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
browserWin.once('closed', () => {
|
|
||||||
handleChildWindowClosed();
|
|
||||||
});
|
|
||||||
|
|
||||||
handlePermissionRequests(browserWin.webContents);
|
|
||||||
|
|
||||||
if (!isDevEnv) {
|
|
||||||
browserWin.webContents.session.setCertificateVerifyProc(handleCertificateTransparencyChecks);
|
|
||||||
}
|
|
||||||
|
|
||||||
browserWin.webContents.on('devtools-opened', () => {
|
|
||||||
handleDevTools(browserWin);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
event.preventDefault();
|
|
||||||
openUrlInDefaultBrowser(newWinUrl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// whenever the main window is navigated for ex: window.location.href or url redirect
|
// whenever the main window is navigated for ex: window.location.href or url redirect
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
"bluebird": "3.5.1",
|
"bluebird": "3.5.1",
|
||||||
"browserify": "16.2.2",
|
"browserify": "16.2.2",
|
||||||
"cross-env": "5.2.0",
|
"cross-env": "5.2.0",
|
||||||
"electron": "2.0.4",
|
"electron": "2.0.6",
|
||||||
"electron-builder": "20.16.4",
|
"electron-builder": "20.16.4",
|
||||||
"electron-builder-squirrel-windows": "12.3.0",
|
"electron-builder-squirrel-windows": "12.3.0",
|
||||||
"electron-chromedriver": "2.0.0",
|
"electron-chromedriver": "2.0.0",
|
||||||
|
Loading…
Reference in New Issue
Block a user