From dbc07962d92d5bf73d5b835e0f5fe01830ff1d67 Mon Sep 17 00:00:00 2001 From: bridiver Date: Tue, 8 Nov 2016 11:36:20 -0700 Subject: [PATCH 01/80] temporary and wip changes for chromium54 --- .npmrc | 8 +- app/browser/lib/patchUserDataDir.js | 15 ---- app/browser/tabs.js | 6 ++ app/common/commonMenu.js | 8 +- app/extensions.js | 4 +- .../brave/content/scripts/adInsertion.js | 4 +- .../scripts/blockCanvasFingerprinting.js | 2 +- .../brave/content/scripts/flashListener.js | 2 +- .../brave/content/scripts/idleHandler.js | 14 +-- .../brave/content/scripts/inputHandler.js | 6 +- .../brave/content/scripts/pageInformation.js | 8 +- .../brave/content/scripts/passwordManager.js | 12 +-- .../brave/content/scripts/spellCheck.js | 2 +- .../brave/content/scripts/themeColor.js | 4 +- app/extensions/brave/index-dev.html | 2 +- app/extensions/brave/index-load-script.js | 2 +- app/filtering.js | 13 +-- app/index.js | 22 +++-- .../components/browserActionButton.js | 2 +- js/about/aboutActions.js | 2 +- js/about/adblock.js | 2 +- js/about/autofill.js | 2 +- js/about/bookmarks.js | 2 +- js/about/certerror.js | 2 +- js/about/downloads.js | 2 +- js/about/entry.js | 2 +- js/about/extensions.js | 2 +- js/about/flashPlaceholder.js | 2 +- js/about/history.js | 2 +- js/about/passwords.js | 2 +- js/about/preferences.js | 2 +- js/actions/downloadActions.js | 39 ++++---- js/actions/windowActions.js | 2 +- js/components/clearBrowsingDataPanel.js | 2 +- js/components/frame.js | 89 +++++++++---------- js/components/main.js | 26 +++--- js/components/navigationBar.js | 2 +- js/components/updateBar.js | 2 +- js/components/urlBar.js | 2 +- js/contextMenus.js | 4 +- js/dispatcher/appDispatcher.js | 2 +- js/entry.js | 62 ++++++------- js/flash.js | 7 +- js/lib/appUrlUtil.js | 4 +- js/stores/appStore.js | 3 +- js/stores/windowStore.js | 2 +- package.json | 3 +- webpack.config.js | 9 +- 48 files changed, 199 insertions(+), 221 deletions(-) delete mode 100644 app/browser/lib/patchUserDataDir.js diff --git a/.npmrc b/.npmrc index 01a91a3a532..4982f59a0e9 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,5 @@ -runtime = electron -target = 1.4.0 +#runtime = electron +#target = 1.4.0 target_arch = x64 -brave_electron_version = 1.4.31 -disturl = https://atom.io/download/atom-shell +#brave_electron_version = 1.4.23 +#disturl = https://atom.io/download/atom-shell diff --git a/app/browser/lib/patchUserDataDir.js b/app/browser/lib/patchUserDataDir.js deleted file mode 100644 index 310ff3cb572..00000000000 --- a/app/browser/lib/patchUserDataDir.js +++ /dev/null @@ -1,15 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const path = require('path') -const {app} = require('electron') - -if (!process.env.BRAVE_USER_DATA_DIR && ['development', 'test'].includes(process.env.NODE_ENV)) { - process.env.BRAVE_USER_DATA_DIR = path.join(app.getPath('appData'), app.getName() + '-' + process.env.NODE_ENV) -} - -if (process.env.BRAVE_USER_DATA_DIR) { - app.setPath('userData', process.env.BRAVE_USER_DATA_DIR) -} - diff --git a/app/browser/tabs.js b/app/browser/tabs.js index 065cf1abcc6..da4a99effb7 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -25,6 +25,12 @@ const tabs = { activeTab = tab } }) + tab.on('new-window', (e, url, frameName, disposition, options = {}) => { + let userGesture = options.userGesture + if (userGesture === false) { + e.preventDefault() + } + }) currentWebContents[tabId] = tab }) }, diff --git a/app/common/commonMenu.js b/app/common/commonMenu.js index f1886e2dcce..25ffdac99ef 100644 --- a/app/common/commonMenu.js +++ b/app/common/commonMenu.js @@ -12,13 +12,7 @@ const settings = require('../../js/constants/settings') const getSetting = require('../../js/settings').getSetting const communityURL = 'https://community.brave.com/' const isDarwin = process.platform === 'darwin' - -let electron -try { - electron = require('electron') -} catch (e) { - electron = global.require('electron') -} +const electron = require('electron') let app let BrowserWindow diff --git a/app/extensions.js b/app/extensions.js index 5b5dd8f4fbf..140fe4d7853 100644 --- a/app/extensions.js +++ b/app/extensions.js @@ -128,7 +128,9 @@ let generateBraveManifest = () => { web_accessible_resources: [ 'img/favicon.ico', 'about-flash.html', - 'about-blank.html' + 'about-blank.html', + 'about-newtab.html', + 'about-preferences.html' ], incognito: 'spanning', key: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAupOLMy5Fd4dCSOtjcApsAQOnuBdTs+OvBVt/3P93noIrf068x0xXkvxbn+fpigcqfNamiJ5CjGyfx9zAIs7zcHwbxjOw0Uih4SllfgtK+svNTeE0r5atMWE0xR489BvsqNuPSxYJUmW28JqhaSZ4SabYrRx114KcU6ko7hkjyPkjQa3P+chStJjIKYgu5tWBiMJp5QVLelKoM+xkY6S7efvJ8AfajxCViLGyDQPDviGr2D0VvIBob0D1ZmAoTvYOWafcNCaqaejPDybFtuLFX3pZBqfyOCyyzGhucyCmfBXJALKbhjRAqN5glNsUmGhhPK87TuGATQfVuZtenMvXMQIDAQAB' diff --git a/app/extensions/brave/content/scripts/adInsertion.js b/app/extensions/brave/content/scripts/adInsertion.js index 57e2c3760a3..5430444eed8 100644 --- a/app/extensions/brave/content/scripts/adInsertion.js +++ b/app/extensions/brave/content/scripts/adInsertion.js @@ -158,12 +158,12 @@ if (chrome.contentSettings.adInsertion == 'allow') { var host = document.location.hostname if (host) { host = host.replace('www.', '') - chrome.ipc.on('set-ad-div-candidates', (e, divHost, adDivCandidates, placeholderUrl) => { + chrome.ipcRenderer.on('set-ad-div-candidates', (e, divHost, adDivCandidates, placeholderUrl) => { // don't accidentally intercept messages not intended for this host if (host === divHost) { setAdDivCandidates(adDivCandidates, placeholderUrl) } }) - chrome.ipc.send('get-ad-div-candidates', host) + chrome.ipcRenderer.send('get-ad-div-candidates', host) } } diff --git a/app/extensions/brave/content/scripts/blockCanvasFingerprinting.js b/app/extensions/brave/content/scripts/blockCanvasFingerprinting.js index 94340263e2b..f59c4efb477 100644 --- a/app/extensions/brave/content/scripts/blockCanvasFingerprinting.js +++ b/app/extensions/brave/content/scripts/blockCanvasFingerprinting.js @@ -77,7 +77,7 @@ if (chrome.contentSettings.canvasFingerprinting == 'block') { } // Block the read from occuring; send info to background page instead - chrome.ipc.sendToHost('got-canvas-fingerprinting', msg) + chrome.ipcRenderer.sendToHost('got-canvas-fingerprinting', msg) } /** diff --git a/app/extensions/brave/content/scripts/flashListener.js b/app/extensions/brave/content/scripts/flashListener.js index e0acdfc7ce2..bd6c4f0a4b9 100644 --- a/app/extensions/brave/content/scripts/flashListener.js +++ b/app/extensions/brave/content/scripts/flashListener.js @@ -13,7 +13,7 @@ function isAdobeLink (href) { } function showFlashNotification (origin, e) { - chrome.ipc.sendToHost('show-flash-notification', origin) + chrome.ipcRenderer.sendToHost('show-flash-notification', origin) e.preventDefault() e.stopPropagation() } diff --git a/app/extensions/brave/content/scripts/idleHandler.js b/app/extensions/brave/content/scripts/idleHandler.js index 20e08949cbe..4871fa2997f 100644 --- a/app/extensions/brave/content/scripts/idleHandler.js +++ b/app/extensions/brave/content/scripts/idleHandler.js @@ -1,7 +1,7 @@ -chrome.idle.setDetectionInterval(15*60) -chrome.idle.onStateChanged.addListener((idleState) => { - chrome.ipc.send('dispatch-action', JSON.stringify({ - actionType: 'app-idle-state-changed', - idleState - })) -}) +// chrome.idle.setDetectionInterval(15*60) +// chrome.idle.onStateChanged.addListener((idleState) => { +// chrome.ipcRenderer.send('dispatch-action', JSON.stringify({ +// actionType: 'app-idle-state-changed', +// idleState +// })) +// }) diff --git a/app/extensions/brave/content/scripts/inputHandler.js b/app/extensions/brave/content/scripts/inputHandler.js index 461a6def264..86a9ed03497 100644 --- a/app/extensions/brave/content/scripts/inputHandler.js +++ b/app/extensions/brave/content/scripts/inputHandler.js @@ -136,17 +136,17 @@ document.addEventListener('keydown', (e /*: Event*/) => { case KeyEvent.DOM_VK_ESCAPE: if (document.readyState !== 'complete') { e.preventDefault() - chrome.ipc.sendToHost('stop-load') + chrome.ipcRenderer.sendToHost('stop-load') } break case KeyEvent.DOM_VK_LEFT: if (e.metaKey && !isEditable(document.activeElement) && isPlatformOSX()) { - chrome.ipc.sendToHost('go-back') + chrome.ipcRenderer.sendToHost('go-back') } break case KeyEvent.DOM_VK_RIGHT: if (e.metaKey && !isEditable(document.activeElement) && isPlatformOSX()) { - chrome.ipc.sendToHost('go-forward') + chrome.ipcRenderer.sendToHost('go-forward') } break } diff --git a/app/extensions/brave/content/scripts/pageInformation.js b/app/extensions/brave/content/scripts/pageInformation.js index a9bb1f49671..e04e307c1b1 100644 --- a/app/extensions/brave/content/scripts/pageInformation.js +++ b/app/extensions/brave/content/scripts/pageInformation.js @@ -5,7 +5,7 @@ /* jshint asi: true */ /* jshint esversion: 6 */ -(function () { try { +(function () { try { var resolve = (tree, context) => { var node = tree.body ? tree.body[0] : tree @@ -135,7 +135,7 @@ if (!node) node = document.head.querySelector("link[rel='shortcut icon']") if (node) results.faviconURL = node.getAttribute('href') - var pubinfo = chrome.ipc.sendSync('ledger-publisher', document.location.href) + var pubinfo = chrome.ipcRenderer.sendSync('ledger-publisher', document.location.href) if ((!pubinfo) || (!pubinfo.context) || (!pubinfo.rules)) return console.log('no pubinfo available') var context = pubinfo.context @@ -171,7 +171,7 @@ results.faviconURL = resolve(rule.faviconURL.consequent, context) } break - } + } if (results.faviconURL) { var prefix = (results.faviconURL.indexOf('//') === 0) ? document.location.protocol @@ -182,7 +182,7 @@ } results.url = window.location.href - chrome.ipc.send('dispatch-action', JSON.stringify({ + chrome.ipcRenderer.send('dispatch-action', JSON.stringify({ location: window.location.href, actionType: 'event-set-page-info', pageInfo: results diff --git a/app/extensions/brave/content/scripts/passwordManager.js b/app/extensions/brave/content/scripts/passwordManager.js index b4c79d76028..399b5511dcc 100644 --- a/app/extensions/brave/content/scripts/passwordManager.js +++ b/app/extensions/brave/content/scripts/passwordManager.js @@ -5,7 +5,7 @@ if (chrome.contentSettings.passwordManager == 'allow') { let credentials = {} function savePassword (username/*: ?string*/, pw/*: string*/, origin/*: string*/, action/*: string*/) { - chrome.ipc.send('save-password', username, pw, origin, action) + chrome.ipcRenderer.send('save-password', username, pw, origin, action) } let submittedForms = [] @@ -62,7 +62,7 @@ if (chrome.contentSettings.passwordManager == 'allow') { // Fill the password immediately if there's only one or if the username // is already autofilled - chrome.ipc.send('get-passwords', formOrigin, action) + chrome.ipcRenderer.send('get-passwords', formOrigin, action) if (usernameElem) { usernameElem.addEventListener('keyup', (e) => { @@ -73,11 +73,11 @@ if (chrome.contentSettings.passwordManager == 'allow') { case KeyEvent.DOM_VK_ESCAPE: e.preventDefault() e.stopPropagation() - chrome.ipc.send('hide-context-menu') + chrome.ipcRenderer.send('hide-context-menu') break default: let rect = usernameElem.getBoundingClientRect() - chrome.ipc.send('show-username-list', formOrigin, action, { + chrome.ipcRenderer.send('show-username-list', formOrigin, action, { bottom: rect.bottom, left: rect.left, width: rect.width @@ -91,7 +91,7 @@ if (chrome.contentSettings.passwordManager == 'allow') { form.addEventListener('submit', (e) => { if (usernameElem) { usernameElem.blur() - chrome.ipc.send('hide-context-menu') + chrome.ipcRenderer.send('hide-context-menu') } onFormSubmit(form, formOrigin) }) @@ -137,7 +137,7 @@ if (chrome.contentSettings.passwordManager == 'allow') { tryAutofillForm(formOrigin, form) }) - chrome.ipc.on('got-password', (e, username, password, origin, action, isUnique) => { + chrome.ipcRenderer.on('got-password', (e, username, password, origin, action, isUnique) => { var elems = credentials[action] if (formOrigin === origin && elems) { elems.forEach((elem) => { diff --git a/app/extensions/brave/content/scripts/spellCheck.js b/app/extensions/brave/content/scripts/spellCheck.js index 1da52280382..1f9af2edb76 100644 --- a/app/extensions/brave/content/scripts/spellCheck.js +++ b/app/extensions/brave/content/scripts/spellCheck.js @@ -4,5 +4,5 @@ let lang = navigator.language.split('-')[0].split('_')[0] chrome.webFrame.setSpellCheckProvider(lang || '', true, { - spellCheck: (word) => !chrome.ipc.sendSync('is-misspelled', word) + spellCheck: (word) => !chrome.ipcRenderer.sendSync('is-misspelled', word) }) diff --git a/app/extensions/brave/content/scripts/themeColor.js b/app/extensions/brave/content/scripts/themeColor.js index 2d8c5868b20..345b77b1bbe 100644 --- a/app/extensions/brave/content/scripts/themeColor.js +++ b/app/extensions/brave/content/scripts/themeColor.js @@ -3,7 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ (function () { - var ipcRenderer = chrome.ipc; + var ipcRenderer = chrome.ipcRenderer; const rgbaFromStr = function (rgba) { if (!rgba) { @@ -57,6 +57,6 @@ } if(window.top == window.self) { - chrome.ipc.sendToHost('theme-color-computed', computeThemeColor()) + chrome.ipcRenderer.sendToHost('theme-color-computed', computeThemeColor()) } })() diff --git a/app/extensions/brave/index-dev.html b/app/extensions/brave/index-dev.html index 830a89315bc..1cd14395c81 100644 --- a/app/extensions/brave/index-dev.html +++ b/app/extensions/brave/index-dev.html @@ -7,7 +7,7 @@ - + Brave diff --git a/app/extensions/brave/index-load-script.js b/app/extensions/brave/index-load-script.js index 4b0f1639f1d..3ea41c5b38c 100644 --- a/app/extensions/brave/index-load-script.js +++ b/app/extensions/brave/index-load-script.js @@ -1,4 +1,4 @@ -var baseHref = 'http://localhost:' + process.env.npm_package_config_port +var baseHref = 'http://localhost:8080' // + process.env.npm_package_config_port var appEntry = baseHref + '/gen/app.entry.js' var baseNode = document.createElement('base') diff --git a/app/filtering.js b/app/filtering.js index 3665709e0c5..b1b5df43557 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -549,17 +549,20 @@ function initForPartition (partition) { fns.forEach((fn) => { fn(ses, partition) }) } +const filterableProtocols = ['http:', 'https:'] + function shouldIgnoreUrl (url) { // Ensure host is well-formed (RFC 1035) and has a non-empty hostname try { - let host = urlParse(url).hostname - if (host.includes('..') || host.length > 255 || host.length === 0) { - return true + // TODO(bridiver) - handle RFS check and cancel http/https requests with 0 or > 255 length hostames + const parsedUrl = urlParse(url) + if (filterableProtocols.includes(parsedUrl.protocol)) { + return false } } catch (e) { - return true + console.warn('Error parsing ' + url) } - return false + return true } module.exports.init = () => { diff --git a/app/index.js b/app/index.js index 38c7e6adaad..784a62f4794 100644 --- a/app/index.js +++ b/app/index.js @@ -8,7 +8,7 @@ let ready = false // Setup the crash handling -const CrashHerald = require('./crash-herald') +// const CrashHerald = require('./crash-herald') const handleUncaughtError = (error) => { var message, ref, stack @@ -42,14 +42,12 @@ if (process.platform === 'win32') { const electron = require('electron') const app = electron.app -// set userData before loading anything else -require('./browser/lib/patchUserDataDir') const BrowserWindow = electron.BrowserWindow const dialog = electron.dialog const ipcMain = electron.ipcMain const Immutable = require('immutable') const Menu = require('./browser/menu') -const Updater = require('./updater') +// const Updater = require('./updater') const Importer = require('./importer') const messages = require('../js/constants/messages') const appConfig = require('../js/constants/appConfig') @@ -212,7 +210,7 @@ const saveAppState = (appState, cb) => { // Otherwise just quit. if (appState.updates && (appState.updates.status === UpdateStatus.UPDATE_APPLYING_NO_RESTART || appState.updates.status === UpdateStatus.UPDATE_APPLYING_RESTART)) { - Updater.quitAndInstall() + // Updater.quitAndInstall() } else { app.quit() } @@ -254,7 +252,7 @@ loadAppStatePromise.then((initialState) => { } if (initialState.settings[SEND_CRASH_REPORTS] !== false) { console.log('Crash reporting enabled') - CrashHerald.init() + // CrashHerald.init() } else { console.log('Crash reporting disabled') } @@ -435,7 +433,7 @@ app.on('ready', () => { webtorrent.init() if (!loadedPerWindowState || loadedPerWindowState.length === 0) { - if (!CmdLine.newWindowURL()) { + if (!CmdLine.newWindowURL) { appActions.newWindow() } } else { @@ -458,9 +456,9 @@ app.on('ready', () => { appActions.changeSetting(settings.IS_DEFAULT_BROWSER, isDefaultBrowser) } - if (CmdLine.newWindowURL()) { + if (CmdLine.newWindowURL) { appActions.newWindow(Immutable.fromJS({ - location: CmdLine.newWindowURL() + location: CmdLine.newWindowURL })) } @@ -750,11 +748,11 @@ app.on('ready', () => { // Setup the auto updater, check the env variable first because it's // used to check the update channel before releases. - Updater.init(process.platform, process.arch, process.env.BRAVE_UPDATE_VERSION || pack.version) + // Updater.init(process.platform, process.arch, process.env.BRAVE_UPDATE_VERSION || pack.version) // This is fired by a menu entry (for now - will be scheduled) - process.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) - ipcMain.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) + // process.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) + // ipcMain.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) // This is fired from a auto-update metadata call process.on(messages.UPDATE_META_DATA_RETRIEVED, (metadata) => { diff --git a/app/renderer/components/browserActionButton.js b/app/renderer/components/browserActionButton.js index 2472773f2cc..911285b3568 100644 --- a/app/renderer/components/browserActionButton.js +++ b/app/renderer/components/browserActionButton.js @@ -4,7 +4,7 @@ const React = require('react') const ImmutableComponent = require('../../../js/components/immutableComponent') -const electron = global.require('electron') +const electron = require('electron') const ipc = electron.ipcRenderer const Button = require('../../../js/components/button') const cx = require('../../../js/lib/classSet') diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js index 3dda621c60c..4a5e6bab9cf 100644 --- a/js/about/aboutActions.js +++ b/js/about/aboutActions.js @@ -6,7 +6,7 @@ const messages = require('../constants/messages') const serializer = require('../dispatcher/serializer') const windowConstants = require('../constants/windowConstants') const appConstants = require('../constants/appConstants') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer const aboutActions = { /** diff --git a/js/about/adblock.js b/js/about/adblock.js index 5e9e9ba9498..5217138528d 100644 --- a/js/about/adblock.js +++ b/js/about/adblock.js @@ -12,7 +12,7 @@ const aboutActions = require('./aboutActions') const ImmutableComponent = require('../components/immutableComponent') const SwitchControl = require('../components/switchControl') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer // Stylesheets require('../../less/switchControls.less') diff --git a/js/about/autofill.js b/js/about/autofill.js index d76192f67b1..78dc2287fd9 100644 --- a/js/about/autofill.js +++ b/js/about/autofill.js @@ -9,7 +9,7 @@ const ImmutableComponent = require('../components/immutableComponent') const aboutActions = require('./aboutActions') const Button = require('../components/button') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer require('../../less/about/autofill.less') require('../../node_modules/font-awesome/css/font-awesome.css') diff --git a/js/about/bookmarks.js b/js/about/bookmarks.js index 1eb0e943a7c..39eb0df97da 100644 --- a/js/about/bookmarks.js +++ b/js/about/bookmarks.js @@ -17,7 +17,7 @@ const siteUtil = require('../state/siteUtil') const formatUtil = require('../../app/common/lib/formatUtil') const iconSize = require('../../app/common/lib/faviconUtil').iconSize -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer // Stylesheets require('../../less/about/bookmarks.less') diff --git a/js/about/certerror.js b/js/about/certerror.js index 638ea24e876..ba7573a5f79 100644 --- a/js/about/certerror.js +++ b/js/about/certerror.js @@ -7,7 +7,7 @@ const Button = require('../components/button') const aboutActions = require('./aboutActions') const WindowConstants = require('../constants/windowConstants') const messages = require('../constants/messages') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer require('../../less/button.less') require('../../less/window.less') diff --git a/js/about/downloads.js b/js/about/downloads.js index 4b1cbf5fef4..5d4b1a3577f 100644 --- a/js/about/downloads.js +++ b/js/about/downloads.js @@ -10,7 +10,7 @@ const messages = require('../constants/messages') const aboutActions = require('./aboutActions') const downloadUtil = require('../state/downloadUtil') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer // Stylesheets require('../../less/about/itemList.less') diff --git a/js/about/entry.js b/js/about/entry.js index 9c2b4afdfee..6ba511c1073 100644 --- a/js/about/entry.js +++ b/js/about/entry.js @@ -32,7 +32,7 @@ if (getFavicon()) { const ReactDOM = require('react-dom') const {getSourceAboutUrl, getBaseUrl} = require('../lib/appUrlUtil') const {ABOUT_COMPONENT_INITIALIZED} = require('../constants/messages') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer let element diff --git a/js/about/extensions.js b/js/about/extensions.js index 97cd964a7a4..f07ad20927a 100644 --- a/js/about/extensions.js +++ b/js/about/extensions.js @@ -9,7 +9,7 @@ const ImmutableComponent = require('../components/immutableComponent') const messages = require('../constants/messages') const aboutActions = require('./aboutActions') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer // Stylesheets require('../../less/about/itemList.less') diff --git a/js/about/flashPlaceholder.js b/js/about/flashPlaceholder.js index 0fd207c5a91..b262862ce32 100644 --- a/js/about/flashPlaceholder.js +++ b/js/about/flashPlaceholder.js @@ -7,7 +7,7 @@ const ImmutableComponent = require('../components/immutableComponent') const messages = require('../constants/messages') const aboutActions = require('./aboutActions') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer require('../../less/about/flash.less') diff --git a/js/about/history.js b/js/about/history.js index d6af81d9586..538b4c049f5 100644 --- a/js/about/history.js +++ b/js/about/history.js @@ -16,7 +16,7 @@ const Button = require('../components/button') const {makeImmutable} = require('../../app/common/state/immutableUtil') const historyUtil = require('../../app/common/lib/historyUtil') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer // Stylesheets require('../../less/about/history.less') diff --git a/js/about/passwords.js b/js/about/passwords.js index 99349905463..8d740ec2145 100644 --- a/js/about/passwords.js +++ b/js/about/passwords.js @@ -7,7 +7,7 @@ const messages = require('../constants/messages') const Immutable = require('immutable') const aboutActions = require('./aboutActions') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer require('../../less/about/passwords.less') require('../../node_modules/font-awesome/css/font-awesome.css') diff --git a/js/about/preferences.js b/js/about/preferences.js index 7db8c173044..19be7a12cda 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -50,7 +50,7 @@ const widevine = appConfig.resourceNames.WIDEVINE const isDarwin = navigator.platform === 'MacIntel' const isWindows = navigator.platform && navigator.platform.includes('Win') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer // TODO: Determine this from the l20n file automatically const hintCount = 3 diff --git a/js/actions/downloadActions.js b/js/actions/downloadActions.js index 308c3165e15..d22a8bb4bef 100644 --- a/js/actions/downloadActions.js +++ b/js/actions/downloadActions.js @@ -4,12 +4,7 @@ 'use strict' -let electron -try { - electron = require('electron') -} catch (e) { - electron = global.require('electron') -} +const electron = require('electron') let shell, ipc, clipboard, getCurrentWebContents if (process.type === 'browser') { @@ -27,8 +22,8 @@ if (process.type === 'browser') { const appDownloadActions = require('../constants/downloadActions') const appActions = require('../actions/appActions') const messages = require('../constants/messages') -const fs = require('fs') -const path = require('path') +// const fs = require('fs') +// const path = require('path') /** * Creates an action function for the specified app download action @@ -48,22 +43,22 @@ const downloadActions = { // void new window.Notification(locale.translation('urlCopied')) }, openDownloadPath: function (download) { - fs.exists(download.get('savePath'), (exists) => { - if (exists) { - shell.openItem(download.get('savePath')) - } else { - shell.beep() - } - }) + // fs.exists(download.get('savePath'), (exists) => { + // if (exists) { + // shell.openItem(download.get('savePath')) + // } else { + // shell.beep() + // } + // }) }, locateShellPath: function (download) { - fs.exists(download.get('savePath'), (exists) => { - if (exists) { - shell.showItemInFolder(download.get('savePath')) - } else { - shell.openItem(path.dirname(download.get('savePath'))) - } - }) + // fs.exists(download.get('savePath'), (exists) => { + // if (exists) { + // shell.showItemInFolder(download.get('savePath')) + // } else { + // shell.openItem(path.dirname(download.get('savePath'))) + // } + // }) }, hideDownloadsToolbar: function () { if (process.type === 'renderer') { diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js index 06a810574ec..bef2f8b0ea8 100644 --- a/js/actions/windowActions.js +++ b/js/actions/windowActions.js @@ -314,7 +314,7 @@ const windowActions = { * @param {Object} frameProps - The properties of the frame to close */ closeFrame: function (frames, frameProps, forceClosePinned) { - const ipc = global.require('electron').ipcRenderer + const ipc = require('electron').ipcRenderer const origin = siteUtil.getOrigin(frameProps.get('location')) if (origin) { appActions.clearMessageBoxes(origin) diff --git a/js/components/clearBrowsingDataPanel.js b/js/components/clearBrowsingDataPanel.js index fc9f68b0808..1d91d113025 100644 --- a/js/components/clearBrowsingDataPanel.js +++ b/js/components/clearBrowsingDataPanel.js @@ -9,7 +9,7 @@ const Button = require('./button') const SwitchControl = require('./switchControl') const windowActions = require('../actions/windowActions') const appActions = require('../actions/appActions') -const ipc = global.require('electron').ipcRenderer +const ipc = require('electron').ipcRenderer const messages = require('../constants/messages') class ClearBrowsingDataPanel extends ImmutableComponent { diff --git a/js/components/frame.js b/js/components/frame.js index c3fb05fcddf..81d83f564b0 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -16,8 +16,8 @@ const UrlUtil = require('../lib/urlutil') const messages = require('../constants/messages') const contextMenus = require('../contextMenus') const {siteHacks} = require('../data/siteHacks') -const ipc = global.require('electron').ipcRenderer -const clipboard = global.require('electron').clipboard +const ipc = require('electron').ipcRenderer +const clipboard = require('electron').clipboard const FullScreenWarning = require('./fullScreenWarning') const debounce = require('../lib/debounce') const getSetting = require('../settings').getSetting @@ -28,7 +28,7 @@ const {isFrameError} = require('../../app/common/lib/httpUtil') const locale = require('../l10n') const appConfig = require('../constants/appConfig') const {getSiteSettingsForHostPattern} = require('../state/siteSettings') -const flash = require('../flash') +// const flash = require('../flash') const currentWindow = require('../../app/renderer/currentWindow') const windowStore = require('../stores/windowStore') const appStoreRenderer = require('../stores/appStoreRenderer') @@ -143,7 +143,7 @@ class Frame extends ImmutableComponent { newTabDetail: this.props.newTabDetail ? this.props.newTabDetail.toJS() : null }) } else if (location === 'about:autofill') { - const defaultSession = global.require('electron').remote.session.defaultSession + const defaultSession = require('electron').remote.session.defaultSession if (this.props.autofillAddresses) { const guids = this.props.autofillAddresses.get('guid') let list = [] @@ -300,17 +300,30 @@ class Frame extends ImmutableComponent { // the webview tag is where the user's page is rendered (runs in its own process) // @see http://electron.atom.io/docs/api/web-view-tag/ this.webview = document.createElement('webview') - + this.addEventListeners() + if (cb) { + this.runOnDomReady = cb + let eventCallback = (e) => { + this.webview.removeEventListener(e.type, eventCallback) + // handle deprectaed zoom level site settings + if (this.zoomLevel) { + this.webview.setZoomLevel(this.zoomLevel) + } + this.runOnDomReady() + delete this.runOnDomReady + } + this.webview.addEventListener('did-attach', eventCallback) + } let partition = FrameStateUtil.getPartition(this.frame) ipc.sendSync(messages.INITIALIZE_PARTITION, partition) this.webview.setAttribute('partition', partition) - if (guestInstanceId) { - this.webview.setAttribute('data-guest-instance-id', guestInstanceId) + if (!this.webview.setGuestInstanceId(guestInstanceId)) { + guestInstanceId = null + } } webviewAdded = true } - this.webview.setAttribute('allowDisplayingInsecureContent', true) this.webview.setAttribute('data-frame-key', this.props.frameKey) const parsedUrl = urlParse(location) @@ -335,20 +348,6 @@ class Frame extends ImmutableComponent { } if (webviewAdded) { - if (cb) { - this.runOnDomReady = cb - let eventCallback = (e) => { - this.webview.removeEventListener(e.type, eventCallback) - // handle deprectaed zoom level site settings - if (this.zoomLevel) { - this.webview.setZoomLevel(this.zoomLevel) - } - this.runOnDomReady() - delete this.runOnDomReady - } - this.webview.addEventListener('did-attach', eventCallback) - } - this.addEventListeners() this.webviewContainer.appendChild(this.webview) } else { cb && cb() @@ -640,26 +639,26 @@ class Frame extends ImmutableComponent { appActions.hideMessageBox(message) } } else { - flash.checkFlashInstalled((installed) => { - if (installed) { - let message = locale.translation('flashInstalled') - appActions.showMessageBox({ - buttons: [ - {text: locale.translation('goToPrefs')}, - {text: locale.translation('goToAdobe')} - ], - message: message, - options: {nonce} - }) - this.notificationCallbacks[message] = (buttonIndex) => { - appActions.hideMessageBox(message) - const location = buttonIndex === 0 ? 'about:preferences#security' : appConfig.flash.installUrl - windowActions.newFrame({ location }, true) - } - } else if (noFlashCallback) { - noFlashCallback() - } - }) + // flash.checkFlashInstalled((installed) => { + // if (installed) { + // let message = locale.translation('flashInstalled') + // appActions.showMessageBox({ + // buttons: [ + // {text: locale.translation('goToPrefs')}, + // {text: locale.translation('goToAdobe')} + // ], + // message: message, + // options: {nonce} + // }) + // this.notificationCallbacks[message] = (buttonIndex) => { + // appActions.hideMessageBox(message) + // const location = buttonIndex === 0 ? 'about:preferences#security' : appConfig.flash.installUrl + // windowActions.newFrame({ location }, true) + // } + // } else if (noFlashCallback) { + // noFlashCallback() + // } + // }) } ipc.once(messages.NOTIFICATION_RESPONSE + nonce, (e, msg, buttonIndex, persist) => { @@ -780,9 +779,7 @@ class Frame extends ImmutableComponent { }) // @see new-window event this.webview.addEventListener('new-window', (e) => { - e.preventDefault() - - let guestInstanceId = e.options && e.options.webPreferences && e.options.webPreferences.guestInstanceId + let guestInstanceId = e.options && e.options.guestInstanceId let windowOpts = e.options && e.options.windowOptions || {} windowOpts.parentWindowKey = currentWindow.id windowOpts.disposition = e.disposition @@ -1163,7 +1160,7 @@ class Frame extends ImmutableComponent { } }) // Handle zoom using Ctrl/Cmd and the mouse wheel. - this.webview.addEventListener('mousewheel', this.onMouseWheel.bind(this)) + // this.webview.addEventListener('mousewheel', this.onMouseWheel.bind(this)) } goBack () { diff --git a/js/components/main.js b/js/components/main.js index 65b97c5e637..bc3c81da036 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -5,9 +5,9 @@ const React = require('react') const ImmutableComponent = require('./immutableComponent') const Immutable = require('immutable') -const electron = global.require('electron') +const electron = require('electron') const ipc = electron.ipcRenderer -const systemPreferences = electron.remote.systemPreferences +// const systemPreferences = electron.remote.systemPreferences // Actions const appActions = require('../actions/appActions') @@ -206,7 +206,7 @@ class Main extends ImmutableComponent { registerSwipeListener () { // Navigates back/forward on macOS two-finger swipe var trackingFingers = false - var swipeGesture = false + // var swipeGesture = false var isSwipeOnEdge = false var deltaX = 0 var deltaY = 0 @@ -219,7 +219,7 @@ class Main extends ImmutableComponent { deltaY = deltaY + e.deltaY time = (new Date()).getTime() - startTime } - }) + }, { passive: true }) ipc.on(messages.DEBUG_REACT_PROFILE, (e, args) => { window.perf = require('react-addons-perf') if (!window.perf.isRunning()) { @@ -247,18 +247,18 @@ class Main extends ImmutableComponent { } }) ipc.on(messages.ENABLE_SWIPE_GESTURE, (e) => { - swipeGesture = true + // swipeGesture = true }) ipc.on(messages.DISABLE_SWIPE_GESTURE, (e) => { - swipeGesture = false + // swipeGesture = false }) ipc.on('scroll-touch-begin', function () { - if (swipeGesture && - systemPreferences.isSwipeTrackingFromScrollEventsEnabled()) { - trackingFingers = true - isSwipeOnEdge = false - startTime = (new Date()).getTime() - } + // if (swipeGesture && + // systemPreferences.isSwipeTrackingFromScrollEventsEnabled()) { + // trackingFingers = true + // isSwipeOnEdge = false + // startTime = (new Date()).getTime() + // } }) ipc.on('scroll-touch-end', function () { if (time > 50 && trackingFingers && Math.abs(deltaY) < 50 && isSwipeOnEdge) { @@ -499,7 +499,7 @@ class Main extends ImmutableComponent { }, true) const activeFrame = FrameStateUtil.getActiveFrame(self.props.windowState) - if (activeFrame) { + if (activeFrame && activeFrame.get('title')) { currentWindow.setTitle(activeFrame.get('title')) } diff --git a/js/components/navigationBar.js b/js/components/navigationBar.js index 67546336ae1..c0ee31b1cbb 100644 --- a/js/components/navigationBar.js +++ b/js/components/navigationBar.js @@ -13,7 +13,7 @@ const windowActions = require('../actions/windowActions') const siteTags = require('../constants/siteTags') const messages = require('../constants/messages') const settings = require('../constants/settings') -const ipc = global.require('electron').ipcRenderer +const ipc = require('electron').ipcRenderer const {isSourceAboutUrl} = require('../lib/appUrlUtil') const AddEditBookmarkHanger = require('../../app/renderer/components/addEditBookmarkHanger') const siteUtil = require('../state/siteUtil') diff --git a/js/components/updateBar.js b/js/components/updateBar.js index 7896b1388d5..fa24170daa7 100644 --- a/js/components/updateBar.js +++ b/js/components/updateBar.js @@ -9,7 +9,7 @@ const Button = require('./button') const appActions = require('../actions/appActions') const windowActions = require('../actions/windowActions') const UpdateStatus = require('../constants/updateStatus') -const remote = global.require('electron').remote +const remote = require('electron').remote const path = require('path') const cx = require('../lib/classSet') diff --git a/js/components/urlBar.js b/js/components/urlBar.js index c102dbbecb2..f309be1e656 100644 --- a/js/components/urlBar.js +++ b/js/components/urlBar.js @@ -11,7 +11,7 @@ const appActions = require('../actions/appActions') const KeyCodes = require('../../app/common/constants/keyCodes') const cx = require('../lib/classSet') const debounce = require('../lib/debounce') -const ipc = global.require('electron').ipcRenderer +const ipc = require('electron').ipcRenderer const UrlBarSuggestions = require('./urlBarSuggestions') const UrlBarIcon = require('../../app/renderer/components/urlBarIcon') diff --git a/js/contextMenus.js b/js/contextMenus.js index 4251cbbfbee..50f517c21a7 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -const electron = global.require('electron') +const electron = require('electron') const remote = electron.remote const Menu = remote.Menu const Immutable = require('immutable') @@ -24,7 +24,7 @@ const CommonMenu = require('../app/common/commonMenu') const dnd = require('./dnd') const dndData = require('./dndData') const appStoreRenderer = require('./stores/appStoreRenderer') -const ipc = global.require('electron').ipcRenderer +const ipc = require('electron').ipcRenderer const locale = require('../js/l10n') const {getSetting} = require('./settings') const settings = require('./constants/settings') diff --git a/js/dispatcher/appDispatcher.js b/js/dispatcher/appDispatcher.js index c11dfc63692..bc6c5238b2c 100644 --- a/js/dispatcher/appDispatcher.js +++ b/js/dispatcher/appDispatcher.js @@ -4,7 +4,7 @@ const Serializer = require('./serializer') const messages = require('../constants/messages') -const electron = process.type === 'renderer' ? global.require('electron') : require('electron') +const electron = require('electron') 'use strict' class AppDispatcher { diff --git a/js/entry.js b/js/entry.js index ff741d545c1..91472ae3f29 100644 --- a/js/entry.js +++ b/js/entry.js @@ -22,27 +22,27 @@ require('../less/addEditBookmark.less') require('../node_modules/font-awesome/css/font-awesome.css') // Enable or disable crash reporting based on platform -const setupCrashReporting = () => { - if (process.platform === 'darwin') { - // Setup the crash handling for mac renderer processes - // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md#crashreporterstartoptions - console.log('macOS renderer crash reporting initialized') - require('../app/crash-herald').init() - } -} +// const setupCrashReporting = () => { +// // if (process.platform === 'darwin') { +// // // Setup the crash handling for mac renderer processes +// // // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md#crashreporterstartoptions +// // console.log('macOS renderer crash reporting initialized') +// // require('../app/crash-herald').init() +// // } +// } -// Notify that renderer crash reporting is disabled -const disableCrashReporting = () => { - console.log('Disabling renderer crash reporting') -} +// // Notify that renderer crash reporting is disabled +// const disableCrashReporting = () => { +// console.log('Disabling renderer crash reporting') +// } const React = require('react') const ReactDOM = require('react-dom') const Window = require('./components/window') -const electron = global.require('electron') -const currentWindow = require('../app/renderer/currentWindow') +const electron = require('electron') +// const currentWindow = require('../app/renderer/currentWindow') const ipc = electron.ipcRenderer -const webFrame = electron.webFrame +// // const webFrame = electron.webFrame const windowStore = require('./stores/windowStore') const appStoreRenderer = require('./stores/appStoreRenderer') const windowActions = require('./actions/windowActions') @@ -51,11 +51,11 @@ const Immutable = require('immutable') const patch = require('immutablepatch') const l10n = require('./l10n') -// don't allow scaling or zooming of the ui -webFrame.setPageScaleLimits(1, 1) -webFrame.setZoomLevelLimits(0, 0) -// override any default zoom level changes -currentWindow.webContents.setZoomLevel(0.0) +// // // don't allow scaling or zooming of the ui +// // webFrame.setPageScaleLimits(1, 1) +// // webFrame.setZoomLevelLimits(0, 0) +// // // override any default zoom level changes +// // currentWindow.webContents.setZoomLevel(0.0) l10n.init() @@ -63,11 +63,11 @@ ipc.on(messages.REQUEST_WINDOW_STATE, () => { ipc.send(messages.RESPONSE_WINDOW_STATE, windowStore.getState().toJS()) }) -if (process.env.NODE_ENV === 'test') { - window.appStoreRenderer = appStoreRenderer - window.windowActions = windowActions - window.windowStore = windowStore -} +// // if (process.env.NODE_ENV === 'test') { +// // window.appStoreRenderer = appStoreRenderer +// // window.windowActions = windowActions +// // window.windowStore = windowStore +// // } ipc.on(messages.APP_STATE_CHANGE, (e, action) => { appStoreRenderer.state = action.stateDiff @@ -83,15 +83,15 @@ window.addEventListener('beforeunload', function () { ipc.send(messages.LAST_WINDOW_STATE, windowStore.getState().toJS()) }) -// get appStore from url ipc.on(messages.INITIALIZE_WINDOW, (e, disposition, appState, frames, initWindowState) => { // Configure renderer crash reporting - if (appState.settings[require('./constants/settings').SEND_CRASH_REPORTS] !== false) { - setupCrashReporting() - } else { - disableCrashReporting() - } + // if (appState.settings[require('./constants/settings').SEND_CRASH_REPORTS] !== false) { + // setupCrashReporting() + // } else { + // disableCrashReporting() + // } appStoreRenderer.state = Immutable.fromJS(appState) + // ReactDOM.render(
test
, document.getElementById('windowContainer')) ReactDOM.render( , document.getElementById('windowContainer')) diff --git a/js/flash.js b/js/flash.js index eb0d1352bb4..04c5d13b912 100644 --- a/js/flash.js +++ b/js/flash.js @@ -5,13 +5,8 @@ const fs = require('fs') const path = require('path') -let electron +const electron = require('electron') let app -try { - electron = require('electron') -} catch (e) { - electron = global.require('electron') -} if (process.type === 'browser') { app = electron.app } else { diff --git a/js/lib/appUrlUtil.js b/js/lib/appUrlUtil.js index 05a14d6b9ec..eb5a2a32d20 100644 --- a/js/lib/appUrlUtil.js +++ b/js/lib/appUrlUtil.js @@ -71,8 +71,8 @@ module.exports.getBraveIndexPath = function (relateivePath = '') { module.exports.getBraveExtIndexHTML = function () { return process.env.NODE_ENV === 'development' - ? module.exports.getBraveIndexPath('index-dev.html') - : module.exports.getBraveIndexPath('index.html') + ? module.exports.getBraveIndexPath('index-dev.html').replace('file://', 'chrome://brave') + : module.exports.getBraveIndexPath('index.html').replace('file://', 'chrome://brave') } /** diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 0fd2cf0f98a..05726fc1dc0 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -233,8 +233,6 @@ const createWindow = (browserOpts, defaults, frameOpts, windowState) => { }) LocalShortcuts.register(mainWindow) - - mainWindow.loadURL(appUrlUtil.getBraveExtIndexHTML()) return mainWindow } @@ -287,6 +285,7 @@ function windowDefaults () { windowOffset: 20, webPreferences: { sharedWorker: true, + nodeIntegration: false, partition: 'default', allowFileAccessFromFileUrls: true, allowUniversalAccessFromFileUrls: true diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index 2064bf08236..4e214b50449 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -9,7 +9,7 @@ const config = require('../constants/config') const settings = require('../constants/settings') const Immutable = require('immutable') const FrameStateUtil = require('../state/frameStateUtil') -const ipc = global.require('electron').ipcRenderer +const ipc = require('electron').ipcRenderer const messages = require('../constants/messages') const debounce = require('../lib/debounce') const getSetting = require('../settings').getSetting diff --git a/package.json b/package.json index 22cf0862343..38b7fb3c3f2 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "lint": "standard", "postinstall": "webpack", "preload-httpse": "node ./preload-httpse.js", - "start": "node ./tools/start.js --debug=5858 --enable-logging --v=0 --enable-extension-activity-logging --enable-sandbox-logging --enable-dcheck", + "start": "node ./tools/start.js --user-data-dir=brave-development --debug=5858 --enable-logging --v=0 --enable-extension-activity-logging --enable-sandbox-logging --enable-dcheck", "start-brk": "node ./tools/start.js --debug-brk=5858 -enable-logging --v=0 --enable-dcheck", "test": "NODE_ENV=test mocha --require babel-register --require babel-polyfill 'test/**/*Test.js'", "unittest": "NODE_ENV=test mocha --require babel-register --require babel-polyfill 'test/unit/**/*Test.js'", @@ -137,7 +137,6 @@ "css-loader": "^0.23.0", "electron-builder": "^2.3.1", "electron-packager": "brave/electron-packager", - "electron-rebuild": "^1.1.1", "electron-winstaller": "2.5.1", "empty-port": "0.0.2", "flow-bin": "^0.22.1", diff --git a/webpack.config.js b/webpack.config.js index b3f9099a2f8..f7ec3da168e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -50,6 +50,9 @@ function config () { resolve: { extensions: ['', '.js', '.jsx'] }, + externals: { + 'electron': 'chrome' + }, plugins: [ new WebpackNotifierPlugin({title: 'Brave-' + env}), new webpack.IgnorePlugin(/^\.\/stores\/appStore$/), @@ -64,6 +67,7 @@ function config () { }) ], node: { + process: false, __filename: true, __dirname: true, fs: 'empty' @@ -74,7 +78,8 @@ function config () { function development () { var dev = config() dev.devServer = { - publicPath: 'http://localhost:' + port + '/gen/' + publicPath: 'http://localhost:' + port + '/gen/', + headers: { 'Access-Control-Allow-Origin': '*' } } return dev } @@ -102,7 +107,7 @@ function merge (config, env) { var app = { name: 'app', - target: 'electron', + target: 'web', entry: ['./js/entry.js'], output: { path: path.resolve(__dirname, 'app', 'extensions', 'brave', 'gen'), From 949763eef0dab0daa6a14b5aea64d3ec0f38e4e5 Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 16 Nov 2016 16:48:37 -0700 Subject: [PATCH 02/80] use remote clipboard --- js/contextMenus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/contextMenus.js b/js/contextMenus.js index 50f517c21a7..91263fa0f97 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -6,7 +6,7 @@ const electron = require('electron') const remote = electron.remote const Menu = remote.Menu const Immutable = require('immutable') -const clipboard = electron.clipboard +const clipboard = remote.clipboard const nativeImage = electron.nativeImage const messages = require('./constants/messages') const windowStore = require('./stores/windowStore') From bbd12273f6a97e604938aef1bc55b15f5ae006cb Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 16 Nov 2016 17:56:19 -0700 Subject: [PATCH 03/80] allow access to file image urls for the main window --- app/extensions/brave/index-dev.html | 2 +- app/extensions/brave/index.html | 2 +- js/stores/appStore.js | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/extensions/brave/index-dev.html b/app/extensions/brave/index-dev.html index 1cd14395c81..89e4637cfe7 100644 --- a/app/extensions/brave/index-dev.html +++ b/app/extensions/brave/index-dev.html @@ -7,7 +7,7 @@ - + Brave diff --git a/app/extensions/brave/index.html b/app/extensions/brave/index.html index 6a03c3b44a6..e1f4b7aa5ae 100644 --- a/app/extensions/brave/index.html +++ b/app/extensions/brave/index.html @@ -7,7 +7,7 @@ - + Brave diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 05726fc1dc0..558c1f63424 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -287,6 +287,7 @@ function windowDefaults () { sharedWorker: true, nodeIntegration: false, partition: 'default', + webSecurity: false, allowFileAccessFromFileUrls: true, allowUniversalAccessFromFileUrls: true } From 919b42abf1b7b42d88242f349cff3a998d7140fb Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 16 Nov 2016 21:40:34 -0700 Subject: [PATCH 04/80] newWindowURL is a method --- app/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/index.js b/app/index.js index 784a62f4794..43dcdae184b 100644 --- a/app/index.js +++ b/app/index.js @@ -433,7 +433,7 @@ app.on('ready', () => { webtorrent.init() if (!loadedPerWindowState || loadedPerWindowState.length === 0) { - if (!CmdLine.newWindowURL) { + if (!CmdLine.newWindowURL()) { appActions.newWindow() } } else { @@ -456,9 +456,9 @@ app.on('ready', () => { appActions.changeSetting(settings.IS_DEFAULT_BROWSER, isDefaultBrowser) } - if (CmdLine.newWindowURL) { + if (CmdLine.newWindowURL()) { appActions.newWindow(Immutable.fromJS({ - location: CmdLine.newWindowURL + location: CmdLine.newWindowURL() })) } From 4744da104c5ca40956cab7b2da615a306d3edec9 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 17 Nov 2016 00:14:40 -0700 Subject: [PATCH 05/80] re-enable updater --- app/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/index.js b/app/index.js index 43dcdae184b..621ecf77ce3 100644 --- a/app/index.js +++ b/app/index.js @@ -47,7 +47,7 @@ const dialog = electron.dialog const ipcMain = electron.ipcMain const Immutable = require('immutable') const Menu = require('./browser/menu') -// const Updater = require('./updater') +const Updater = require('./updater') const Importer = require('./importer') const messages = require('../js/constants/messages') const appConfig = require('../js/constants/appConfig') @@ -210,7 +210,7 @@ const saveAppState = (appState, cb) => { // Otherwise just quit. if (appState.updates && (appState.updates.status === UpdateStatus.UPDATE_APPLYING_NO_RESTART || appState.updates.status === UpdateStatus.UPDATE_APPLYING_RESTART)) { - // Updater.quitAndInstall() + Updater.quitAndInstall() } else { app.quit() } @@ -748,11 +748,11 @@ app.on('ready', () => { // Setup the auto updater, check the env variable first because it's // used to check the update channel before releases. - // Updater.init(process.platform, process.arch, process.env.BRAVE_UPDATE_VERSION || pack.version) + Updater.init(process.platform, process.arch, process.env.BRAVE_UPDATE_VERSION || pack.version) // This is fired by a menu entry (for now - will be scheduled) - // process.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) - // ipcMain.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) + process.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) + ipcMain.on(messages.CHECK_FOR_UPDATE, () => Updater.checkForUpdate(true)) // This is fired from a auto-update metadata call process.on(messages.UPDATE_META_DATA_RETRIEVED, (metadata) => { From c6b9d143d3b46d45fdb82233cb54e9cc1b3e9be5 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Thu, 17 Nov 2016 21:50:17 +0800 Subject: [PATCH 06/80] Fix mac - OS buttons overlap with back/forward buttons requies https://github.com/brave/electron/commit/92c9e25 --- app/common/lib/platformUtil.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/common/lib/platformUtil.js b/app/common/lib/platformUtil.js index dc67d7d74b3..ced53923f82 100644 --- a/app/common/lib/platformUtil.js +++ b/app/common/lib/platformUtil.js @@ -4,19 +4,17 @@ 'use strict' -const os = require('os') - /** * Get list of styles which should be applied to root window div * return array of strings (each being a class name) */ module.exports.getPlatformStyles = () => { - const platform = os.platform() + const platform = process.platform() const styleList = ['platform--' + platform] switch (platform) { case 'win32': - if (/6.1./.test(os.release())) { + if (process.platformVersion() === 'win7') { styleList.push('win7') } else { styleList.push('win10') @@ -27,11 +25,11 @@ module.exports.getPlatformStyles = () => { } module.exports.isDarwin = () => { - return os.platform() === 'darwin' || + return process.platform() === 'darwin' || navigator.platform === 'MacIntel' } module.exports.isWindows = () => { - return os.platform() === 'win32' || + return process.platform() === 'win32' || navigator.platform === 'Win32' } From acad822f19cb4a76c6fa1c7b924fd5b43254a3dd Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 17 Nov 2016 19:06:08 -0700 Subject: [PATCH 07/80] platform is a property --- .npmrc | 2 +- app/common/lib/platformUtil.js | 8 ++++---- tools/cibuild.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.npmrc b/.npmrc index 4982f59a0e9..8d06ade0567 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,5 @@ #runtime = electron #target = 1.4.0 target_arch = x64 -#brave_electron_version = 1.4.23 +brave_electron_version = 2.0.0 #disturl = https://atom.io/download/atom-shell diff --git a/app/common/lib/platformUtil.js b/app/common/lib/platformUtil.js index ced53923f82..ab29dc386ae 100644 --- a/app/common/lib/platformUtil.js +++ b/app/common/lib/platformUtil.js @@ -9,12 +9,12 @@ * return array of strings (each being a class name) */ module.exports.getPlatformStyles = () => { - const platform = process.platform() + const platform = process.platform const styleList = ['platform--' + platform] switch (platform) { case 'win32': - if (process.platformVersion() === 'win7') { + if (process.platformVersion === 'win7') { styleList.push('win7') } else { styleList.push('win10') @@ -25,11 +25,11 @@ module.exports.getPlatformStyles = () => { } module.exports.isDarwin = () => { - return process.platform() === 'darwin' || + return process.platform === 'darwin' || navigator.platform === 'MacIntel' } module.exports.isWindows = () => { - return process.platform() === 'win32' || + return process.platform === 'win32' || navigator.platform === 'Win32' } diff --git a/tools/cibuild.py b/tools/cibuild.py index bbee7bf15b5..38c166667cd 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -5,7 +5,7 @@ import sys import os.path -BRAVE_ELECTRON = '1.4.31' +BRAVE_ELECTRON = '2.0.0' UPSTREAM_ELECTRON = '1.4.0' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) TARGET_ARCH= os.environ['TARGET_ARCH'] if os.environ.has_key('TARGET_ARCH') else 'x64' From 4dfe1d00b62a274899340db8f9b40eb1231527e8 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Mon, 21 Nov 2016 11:10:26 +0800 Subject: [PATCH 08/80] Calling nativeImage.createFromDataURL in browser process --- app/nativeImage.js | 15 +++++++++++++++ js/actions/appActions.js | 12 ++++++++++++ js/constants/appConstants.js | 4 +++- js/contextMenus.js | 11 ++--------- js/stores/appStore.js | 4 ++++ 5 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 app/nativeImage.js diff --git a/app/nativeImage.js b/app/nativeImage.js new file mode 100644 index 00000000000..6850ac83a5d --- /dev/null +++ b/app/nativeImage.js @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const electron = require('electron') +const nativeImage = electron.nativeImage +const clipboard = electron.clipboard + +module.exports.copyDataURL = (dataURL, html, text) => { + clipboard.write({ + image: nativeImage.createFromDataURL(dataURL), + html: html, + text: text + }) +} diff --git a/js/actions/appActions.js b/js/actions/appActions.js index 103ddb468cc..f8f57982168 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -579,6 +579,18 @@ const appActions = { AppDispatcher.dispatch({ actionType: AppConstants.APP_POPULATE_HISTORY }) + }, + + /** + * Dispatch a message to copy data URL to clipboard + **/ + dataURLCopied: function (dataURL, html, text) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_DATA_URL_COPIED, + dataURL, + html, + text + }) } } diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index d72dd17cc58..d4d1298a945 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -64,7 +64,9 @@ const AppConstants = { APP_DEFAULT_BROWSER_UPDATED: _, APP_DEFAULT_BROWSER_CHECK_COMPLETE: _, APP_POPULATE_HISTORY: _, - APP_RENDER_URL_TO_PDF: _ + APP_RENDER_URL_TO_PDF: _, + APP_POPULATE_HISTORY: _, + APP_DATA_URL_COPIED: _ } module.exports = mapValuesByKeys(AppConstants) diff --git a/js/contextMenus.js b/js/contextMenus.js index 91263fa0f97..2a71638eb0a 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -7,7 +7,6 @@ const remote = electron.remote const Menu = remote.Menu const Immutable = require('immutable') const clipboard = remote.clipboard -const nativeImage = electron.nativeImage const messages = require('./constants/messages') const windowStore = require('./stores/windowStore') const windowActions = require('./actions/windowActions') @@ -939,18 +938,12 @@ function mainTemplateInit (nodeProps, frame) { { label: locale.translation('copyImage'), click: (item) => { - const copyFromDataURL = (dataURL) => - clipboard.write({ - image: nativeImage.createFromDataURL(dataURL), - html: ``, - text: nodeProps.srcURL - }) if (nodeProps.srcURL) { if (urlParse(nodeProps.srcURL).protocol === 'data:') { - copyFromDataURL(nodeProps.srcURL) + appActions.dataURLCopied(nodeProps.srcURL, ``, nodeProps.srcURL)) } } } diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 558c1f63424..106ca5bc8a5 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -31,6 +31,7 @@ const debounce = require('../lib/debounce.js') const locale = require('../../app/locale') const path = require('path') const autofill = require('../../app/autofill') +const nativeImage = require('../../app/nativeImage') // state helpers const basicAuthState = require('../../app/common/state/basicAuthState') @@ -437,6 +438,9 @@ const handleAppAction = (action) => { case AppConstants.APP_POPULATE_HISTORY: appState = aboutHistoryState.setHistory(appState, action) break + case AppConstants.APP_DATA_URL_COPIED: + nativeImage.copyDataURL(action.dataURL, action.html, action.text) + break case AppConstants.APP_ADD_SITE: const oldSiteSize = appState.get('sites').size if (action.siteDetail.constructor === Immutable.List) { From 0bac16cd7157d4671367d6e5424451b1bfd59984 Mon Sep 17 00:00:00 2001 From: bridiver Date: Mon, 21 Nov 2016 15:34:00 -0700 Subject: [PATCH 09/80] replace setAttributes that no longer exist --- js/components/frame.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 81d83f564b0..8d44c2d5fe5 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -328,14 +328,14 @@ class Frame extends ImmutableComponent { const parsedUrl = urlParse(location) if (!appConfig.uaExceptionHosts.includes(parsedUrl.hostname)) { - this.webview.setAttribute('useragent', getSetting(settings.USERAGENT) || '') + this.webview.setUserAgentOverride(getSetting(settings.USERAGENT) || '') } const hack = siteHacks[parsedUrl.hostname] if (hack && hack.userAgent) { - this.webview.setAttribute('useragent', hack.userAgent) + this.webview.setUserAgentOverride(hack.userAgent) } if (this.allowRunningFlashPlugin() || this.allowRunningWidevinePlugin()) { - this.webview.setAttribute('plugins', true) + this.webview.setAllowPlugins(true) this.webview.allowRunningPlugins = true } From 69892335f922860eaf79e47b103bdd86664e424a Mon Sep 17 00:00:00 2001 From: bridiver Date: Mon, 21 Nov 2016 17:20:09 -0700 Subject: [PATCH 10/80] use contentSettings for plugins --- js/components/frame.js | 4 +--- js/state/contentSettings.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 8d44c2d5fe5..8a84fbe1a83 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -195,8 +195,7 @@ class Frame extends ImmutableComponent { } shouldCreateWebview () { - return !this.webview || - !!this.webview.allowRunningPlugins !== (this.allowRunningFlashPlugin() || this.allowRunningWidevinePlugin()) + return !this.webview } runInsecureContent () { @@ -335,7 +334,6 @@ class Frame extends ImmutableComponent { this.webview.setUserAgentOverride(hack.userAgent) } if (this.allowRunningFlashPlugin() || this.allowRunningWidevinePlugin()) { - this.webview.setAllowPlugins(true) this.webview.allowRunningPlugins = true } diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index edb22cbb904..53e54e4ef16 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -14,6 +14,7 @@ const urlParse = require('url').parse const siteSettings = require('./siteSettings') const {setUserPref} = require('./userPrefs') const {getSetting} = require('../settings') +const {getIndexHTML} = require('../lib/appUrlUtil') // backward compatibility with appState siteSettings const parseSiteSettingsPattern = (pattern) => { @@ -110,8 +111,12 @@ const hostSettingsToContentSettings = (hostSettings, contentSettingsSource) => { if (hostSetting.adControl) { addContentSettings(contentSettings.adInsertion, hostPattern, '*', hostSetting.adControl === 'showBraveAds' ? 'allow' : 'block') } - if (typeof hostSetting.flash === 'number') { + if (typeof hostSetting.flash === 'number' && AppStore.getState().get('flashInitialized')) { addContentSettings(contentSettings.flashActive, hostPattern, '*', 'allow') + addContentSettings(contentSettings.plugins, hostPattern, '*', 'allow') + } + if (typeof hostSetting.widevine === 'number' && AppStore.getState().getIn(['widevine', 'enabled'])) { + addContentSettings(contentSettings.plugins, hostPattern, '*', 'allow') } } // On the second pass we consider only shieldsUp === false settings since we want those to take precedence. @@ -168,6 +173,13 @@ const getContentSettingsFromSiteSettings = (appState, isPrivate = false) => { runInsecureContent: [{ setting: 'block', primaryPattern: '*' + }], + plugins: [{ + setting: 'block', + primaryPattern: '*' + }, { + setting: 'allow', + primaryPattern: getIndexHTML() }] } From fbbad7a9832d043d28c1759192c0b33c84033075 Mon Sep 17 00:00:00 2001 From: bridiver Date: Mon, 3 Oct 2016 21:03:16 -0700 Subject: [PATCH 11/80] Track tabs and windows in appState --- app/browser/basicAuth.js | 62 +- app/browser/tabs.js | 228 ++++-- app/browser/windows.js | 139 ++++ app/common/state/basicAuthState.js | 51 +- app/common/state/extensionState.js | 11 +- app/common/state/immutableUtil.js | 21 +- app/common/state/tabState.js | 189 ++++- app/common/state/windowState.js | 148 ++++ app/index.js | 6 +- app/sessionStore.js | 31 +- docs/appActions.md | 45 +- docs/state.md | 25 + js/actions/appActions.js | 82 +- js/components/frame.js | 2 - js/constants/appConstants.js | 12 +- js/stores/appStore.js | 62 +- js/stores/eventStore.js | 4 +- .../app/common/state/basicAuthStateTest.js | 63 +- test/unit/app/common/state/tabStateTest.js | 765 +++++++++++++----- test/unit/common/state/windowStateTest.js | 480 +++++++++++ 20 files changed, 1980 insertions(+), 446 deletions(-) create mode 100644 app/browser/windows.js create mode 100644 app/common/state/windowState.js create mode 100644 test/unit/common/state/windowStateTest.js diff --git a/app/browser/basicAuth.js b/app/browser/basicAuth.js index ad68ed73283..b6a25e5ac98 100644 --- a/app/browser/basicAuth.js +++ b/app/browser/basicAuth.js @@ -1,9 +1,7 @@ -const electron = require('electron') -const app = electron.app +const {app} = require('electron') const appActions = require('../../js/actions/appActions') -const appConstants = require('../../js/constants/appConstants') -const appDispatcher = require('../../js/dispatcher/appDispatcher') -const appStore = require('../../js/stores/appStore') +const basicAuthState = require('../common/state/basicAuthState') +const { makeImmutable } = require('../common/state/immutableUtil') // URLs to callback for auth. let authCallbacks = {} @@ -12,34 +10,8 @@ const cleanupAuthCallback = (tabId) => { delete authCallbacks[tabId] } -const runAuthCallback = (tabId, detail) => { - let cb = authCallbacks[tabId] - if (cb) { - delete authCallbacks[tabId] - if (detail) { - let username = detail.get('username') - let password = detail.get('password') - cb(username, password) - } else { - cb() - } - } -} - -const doAction = (action) => { - switch (action.actionType) { - case appConstants.APP_SET_LOGIN_RESPONSE_DETAIL: - appDispatcher.waitFor([appStore.dispatchToken], () => { - runAuthCallback(action.tabId, action.detail) - }) - break - default: - } -} - const basicAuth = { init: () => { - appDispatcher.register(doAction) app.on('login', (e, webContents, request, authInfo, cb) => { e.preventDefault() let tabId = webContents.getId() @@ -50,11 +22,33 @@ const basicAuth = { webContents.on('crashed', () => { cleanupAuthCallback(tabId) }) - appActions.setLoginRequiredDetail(tabId, { - request, - authInfo + setImmediate(() => { + appActions.setLoginRequiredDetail(tabId, { + request, + authInfo + }) }) }) + }, + + setLoginResponseDetail: (state, action) => { + state = makeImmutable(state) + action = makeImmutable(action) + let tabId = action.get('tabId') + let detail = action.get('detail') + state = basicAuthState.setLoginResponseDetail(state, action) + let cb = authCallbacks[tabId] + if (cb) { + cleanupAuthCallback(tabId) + if (detail) { + let username = detail.get('username') + let password = detail.get('password') + cb(username, password) + } else { + cb() + } + } + return state } } diff --git a/app/browser/tabs.js b/app/browser/tabs.js index da4a99effb7..846cd54f86f 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -1,112 +1,180 @@ -const {app, BrowserWindow, session, webContents} = require('electron') -const extensions = process.atomBinding('extension') -const { getBraveExtIndexHTML } = require('../../js/lib/appUrlUtil') +const {app, extensions} = require('electron') +const appActions = require('../../js/actions/appActions') +const { makeImmutable } = require('../common/state/immutableUtil') +const tabState = require('../common/state/tabState') let currentWebContents = {} -let activeTab = null const cleanupWebContents = (tabId) => { delete currentWebContents[tabId] + setImmediate(() => { + appActions.tabClosed({ tabId }) + }) } -const tabs = { - init: () => { +const getTabValue = function (tabId) { + let tab = api.getWebContents(tabId) + if (tab) { + return makeImmutable(extensions.tabValue(tab)) + } +} + +const createInternal = (createProperties, tab, cb = null) => { + return new Promise((resolve, reject) => { + tab.once('did-attach', () => { + cb && cb(tab) + }) + tab.once('did-fail-provisional-load', (e) => { + resolve(tab, e) + }) + tab.once('did-fail-load', (e) => { + resolve(tab, e) + }) + tab.once('did-finish-load', (e) => { + resolve(tab, e) + }) + let openerTab = extensions.getOpener(createProperties) + extensions.openTab(tab, createProperties, openerTab) + }) +} + +const updateTab = (tabId) => { + let tabValue = getTabValue(tabId) + if (tabValue) { + setImmediate(() => { + appActions.tabUpdated(tabValue) + }) + } +} + +const api = { + init: (state, action) => { app.on('web-contents-created', function (event, tab) { // TODO(bridiver) - also exclude extension action windows?? - if (extensions.isBackgroundPage(tab) || tab.getURL() === getBraveExtIndexHTML()) { + if (extensions.isBackgroundPage(tab) || !tab.hostWebContents) { return } let tabId = tab.getId() - tab.on('destroyed', cleanupWebContents.bind(null, tabId)) - tab.on('crashed', cleanupWebContents.bind(null, tabId)) - tab.on('close', cleanupWebContents.bind(null, tabId)) + tab.once('destroyed', cleanupWebContents.bind(null, tabId)) + tab.once('crashed', cleanupWebContents.bind(null, tabId)) + tab.once('close', cleanupWebContents.bind(null, tabId)) tab.on('set-active', function (evt, active) { - if (active) { - activeTab = tab + updateTab(tabId) + }) + tab.on('page-favicon-updated', function (e, favicons) { + if (favicons && favicons.length > 0) { + tab.setTabValues({ + faviconUrl: favicons[0] + }) + updateTab(tabId) } }) - tab.on('new-window', (e, url, frameName, disposition, options = {}) => { - let userGesture = options.userGesture - if (userGesture === false) { - e.preventDefault() + tab.on('unresponsive', () => { + console.log('unresponsive') + }) + tab.on('responsive', () => { + console.log('responsive') + }) + tab.on('did-attach', () => { + updateTab(tabId) + }) + tab.on('did-detach', () => { + updateTab(tabId) + }) + tab.on('page-title-updated', function () { + updateTab(tabId) + }) + tab.on('did-fail-load', function () { + updateTab(tabId) + }) + tab.on('did-fail-provisional-load', function () { + updateTab(tabId) + }) + tab.on('did-stop-loading', function () { + updateTab(tabId) + }) + tab.on('navigation-entry-commited', function (evt, url) { + updateTab(tabId) + }) + tab.on('did-navigate', function (evt, url) { + updateTab(tabId) + }) + tab.on('load-start', function (evt, url, isMainFrame, isErrorPage) { + if (isMainFrame) { + updateTab(tabId) } }) + tab.on('did-finish-load', function () { + updateTab(tabId) + }) + currentWebContents[tabId] = tab + let tabValue = getTabValue(tabId) + if (tabValue) { + setImmediate(() => { + appActions.tabCreated(tabValue) + }) + } }) + + return state }, getWebContents: (tabId) => { return currentWebContents[tabId] }, - create: (createProperties) => { - return new Promise((resolve, reject) => { - // TODO(bridiver) - make this available from electron - var payload = {} - process.emit('ELECTRON_GUEST_VIEW_MANAGER_NEXT_INSTANCE_ID', payload) - var guestInstanceId = payload.returnValue - - let win = BrowserWindow.getFocusedWindow() - let windowId = createProperties.windowId - if (windowId && windowId !== -2) { - win = BrowserWindow.fromId(windowId) || win - } - if (!win) { - reject('Could not find a window for new tab') - return - } - let opener = null - let newSession = session.defaultSession - let openerTabId = createProperties.openerTabId - if (openerTabId) { - opener = tabs.getWebContents(openerTabId) - if (!opener) { - reject('Opener does not exist') - return - } - // only use the opener if it is in the same window - if (opener.webContents.hostWebContents !== win.webContents) { - reject('Opener must be in the same window as new tab') - return - } - } - - opener = opener || activeTab - if (opener) { - newSession = opener.session - } else { - reject('Could not find an opener for new tab') - return - } + setAudioMuted: (state, action) => { + action = makeImmutable(action) + let frameProps = action.get('frameProps') + let muted = action.get('muted') + let tabId = frameProps.get('tabId') + let webContents = api.getWebContents(tabId) + if (webContents) { + webContents.setAudioMuted(muted) + let tabValue = getTabValue(tabId) + return tabState.updateTab(state, { tabValue }) + } + }, - let webPreferences = { - isGuest: true, - embedder: win.webContents, - session: newSession, - guestInstanceId, - delayedLoadUrl: createProperties.url || 'about:newtab' - } - webPreferences = Object.assign({}, opener.getWebPreferences(), webPreferences) - let guest = webContents.create(webPreferences) - process.emit('ELECTRON_GUEST_VIEW_MANAGER_REGISTER_GUEST', { sender: opener }, guest, guestInstanceId) + newTab: (state, action) => { + action = makeImmutable(action) + let createProperties = action.get('createProperties') + createProperties = makeImmutable(createProperties).toJS() + let guest = extensions.registerGuest(createProperties) + createInternal(createProperties, guest).catch((err) => { + console.error(err) + // TODO(bridiver) - report the error + }) + let tab = guest.webContents + let tabValue = getTabValue(tab) + return tabState.maybeCreateTab(state, { tabValue }) + }, - guest.once('did-finish-load', () => { - resolve(guest) - }) - let active = createProperties.active !== false - if (!active) { - active = createProperties.selected !== false + closeTab: (state, action) => { + action = makeImmutable(action) + let tabId = action.get('tabId') + let tab = api.getWebContents(tabId) + try { + if (!tab.isDestroyed()) { + tab.close() } - let disposition = active ? 'foreground-tab' : 'background-tab' + } catch (e) { + // ignore + } + return tabState.removeTabByTabId(state, tabId) + }, - process.emit('ELECTRON_GUEST_VIEW_MANAGER_TAB_OPEN', - { sender: opener }, // event - 'about:blank', - '', - disposition, - { webPreferences: guest.getWebPreferences() }) - }) + create: (createProperties, cb = null) => { + try { + createProperties = makeImmutable(createProperties).toJS() + let guest = extensions.registerGuest(createProperties) + return createInternal(createProperties, guest, cb) + } catch (e) { + cb && cb() + return new Promise((resolve, reject) => { reject(e.message) }) + } } } -module.exports = tabs +module.exports = api diff --git a/app/browser/windows.js b/app/browser/windows.js new file mode 100644 index 00000000000..5fecfeb7e11 --- /dev/null +++ b/app/browser/windows.js @@ -0,0 +1,139 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const {app, BrowserWindow} = require('electron') +const appActions = require('../../js/actions/appActions') +const debounce = require('../../js/lib/debounce.js') +const { makeImmutable } = require('../common/state/immutableUtil') +const windowState = require('../common/state/windowState') + +// TODO(bridiver) - set window uuid +let currentWindows = {} + +const cleanupWindow = (windowId) => { + delete currentWindows[windowId] + setImmediate(() => { + appActions.windowClosed({ windowValue: windowId }) + }) +} + +const getWindowState = (win) => { + if (win.isFullScreen()) { + return 'fullscreen' + } else if (win.isMinimized()) { + return 'minimized' + } else if (win.isMaximized()) { + return 'maximized' + } else { + return 'normal' + } +} + +const getWindowValue = (windowId) => { + let win = BrowserWindow.fromId(windowId) + if (win) { + return makeImmutable({ + windowId: win.id, + focused: win.isFocused(), + top: win.getBounds().y, + left: win.getBounds().x, + width: win.getSize()[0], + height: win.getSize()[1], + type: 'normal', + state: getWindowState(win) + }) + } +} + +const updateWindow = (windowId) => { + let windowValue = getWindowValue(windowId) + if (windowValue) { + setImmediate(() => { + appActions.windowUpdated(windowValue) + }) + } +} + +const updateWindowMove = debounce(updateWindow, 1000) + +const api = { + init: (state, action) => { + app.on('browser-window-created', function (event, win) { + let windowId = -1 + win.once('initialized', () => { + windowId = win.id + currentWindows[windowId] = win + let windowValue = getWindowValue(windowId) + setImmediate(() => { + appActions.windowCreated(windowValue) + }) + }) + win.once('closed', () => { + cleanupWindow(windowId) + }) + win.on('blur', () => { + updateWindow(windowId) + }) + win.on('focus', () => { + updateWindow(windowId) + }) + win.on('show', () => { + updateWindow(windowId) + }) + win.on('hide', () => { + updateWindow(windowId) + }) + win.on('maximize', () => { + updateWindow(windowId) + }) + win.on('unmaximize', () => { + updateWindow(windowId) + }) + win.on('minimize', () => { + updateWindow(windowId) + }) + win.on('restore', () => { + updateWindow(windowId) + }) + win.on('resize', () => { + updateWindow(windowId) + }) + win.on('move', () => { + updateWindowMove(windowId) + }) + win.on('enter-full-screen', () => { + updateWindow(windowId) + }) + win.on('leave-full-screen', () => { + updateWindow(windowId) + }) + }) + // TODO(bridiver) - handle restoring windows + // windowState.getWindows(state).forEach((win) => { + // console.log('restore', win.toJS()) + // // restore window + // }) + return state + }, + + closeWindow: (state, action) => { + action = makeImmutable(action) + let windowId = action.get('windowId') + let win = api.getWindow(windowId) + try { + if (!win.isDestroyed()) { + win.close() + } + } catch (e) { + // ignore + } + return windowState.removeWindowByWindowId(state, windowId) + }, + + getWindow: (windowId) => { + return currentWindows[windowId] + } +} + +module.exports = api diff --git a/app/common/state/basicAuthState.js b/app/common/state/basicAuthState.js index 48d99b827bb..3b7494763b4 100644 --- a/app/common/state/basicAuthState.js +++ b/app/common/state/basicAuthState.js @@ -6,35 +6,48 @@ const tabState = require('./tabState') const {makeImmutable} = require('./immutableUtil') const loginRequiredDetail = 'loginRequiredDetail' -tabState.addTransientFields([loginRequiredDetail]) const basicAuthState = { - setLoginRequiredDetail: (appState, tabId, detail) => { - appState = makeImmutable(appState) - detail = makeImmutable(detail) - let tab = tabState.getOrCreateByTabId(appState, tabId) + setLoginRequiredDetail: (state, action) => { + state = makeImmutable(state) + action = makeImmutable(action) + let tabId = action.get('tabId') + let detail = action.get('detail') + let tabValue = tabState.getByTabId(state, tabId) + + if (!tabValue) { + return state + } + if (!detail || detail.size === 0) { - tab = tab.delete(loginRequiredDetail) + tabValue = tabValue.delete(loginRequiredDetail) } else { - tab = tab.set(loginRequiredDetail, detail) + tabValue = tabValue.set(loginRequiredDetail, detail) } - return tabState.updateTab(appState, tabId, tab) + return tabState.updateTab(state, {tabValue, replace: true}) }, - getLoginRequiredDetail: (appState, tabId) => { - appState = makeImmutable(appState) - let tab = tabState.getByTabId(appState, tabId) - return tab && tab.get(loginRequiredDetail) + getLoginRequiredDetail: (state, tabId) => { + if (!tabId) { + return + } + state = makeImmutable(state) + let tabValue = tabState.getByTabId(state, tabId) + return tabValue && tabValue.get(loginRequiredDetail) }, - setLoginResponseDetail: (appState, tabId, detail) => { - appState = makeImmutable(appState) - let tab = tabState.getByTabId(appState, tabId) - if (!tab) { - return appState + setLoginResponseDetail: (state, action) => { + state = makeImmutable(state) + action = makeImmutable(action) + let tabId = action.get('tabId') + let tabValue = tabState.getByTabId(state, tabId) + + if (!tabValue) { + return state } - tab = tab.delete(loginRequiredDetail) - return tabState.updateTab(appState, tabId, tab) + + tabValue = tabValue.delete(loginRequiredDetail) + return tabState.updateTab(state, {tabValue, replace: true}) } } diff --git a/app/common/state/extensionState.js b/app/common/state/extensionState.js index 254a0859d04..be8404a0c3d 100644 --- a/app/common/state/extensionState.js +++ b/app/common/state/extensionState.js @@ -2,15 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -const tabState = require('./tabState') -const {makeImmutable} = require('./immutableUtil') +const { makeImmutable } = require('./immutableUtil') const Immutable = require('immutable') const WindowConstants = require('../../../js/constants/windowConstants') -let transientFields = [] - -tabState.addTransientFields(['browserAction']) - const browserActionDefaults = Immutable.fromJS({ tabs: {} }) @@ -135,10 +130,6 @@ const extensionState = { } }, - getTransientFields: () => { - return transientFields - }, - getPersistentTabState: (extension) => { extension = makeImmutable(extension) extensionState.getTransientFields().forEach((field) => { diff --git a/app/common/state/immutableUtil.js b/app/common/state/immutableUtil.js index f4edd4c8f75..ae1c90b7651 100644 --- a/app/common/state/immutableUtil.js +++ b/app/common/state/immutableUtil.js @@ -4,13 +4,22 @@ const Immutable = require('immutable') -const immutableUtils = { +const api = { + isImmutable: (obj) => { + return obj && obj.toJS + }, + + isMap: (obj) => { + return Immutable.Map.isMap(obj) + }, + + isList: (obj) => { + return Immutable.List.isList(obj) + }, + makeImmutable: (obj) => { - if (!obj) { - return null - } - return obj.toJS ? obj : Immutable.fromJS(obj) + return api.isImmutable(obj) ? obj : Immutable.fromJS(obj) } } -module.exports = immutableUtils +module.exports = api diff --git a/app/common/state/tabState.js b/app/common/state/tabState.js index 1b38d2b0212..ce456625bcd 100644 --- a/app/common/state/tabState.js +++ b/app/common/state/tabState.js @@ -2,68 +2,185 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -const {makeImmutable} = require('./immutableUtil') +const { makeImmutable, isMap, isList } = require('./immutableUtil') +const assert = require('assert') -let transientFields = ['tabId', 'windowId'] +const validateId = function (propName, id) { + assert(id, `${propName} cannot be null`) + id = parseInt(id) + assert(id === -1 || id > 0, `${propName} must be positive`) + return id +} + +const validateTabs = function (tabs) { + tabs = makeImmutable(tabs) + assert(isList(tabs), 'tabs must be an Immutable.List') + tabs.forEach((tab) => validateTabValue(tab)) + return tabs +} -const tabState = { - defaultTabState: makeImmutable({ - windowId: -1, - frameKey: -1, - tabId: -1 - }), +const validateState = function (state) { + state = makeImmutable(state) + assert(isMap(state), 'state must be an Immutable.Map') + assert(isList(state.get('tabs')), 'state must contain an Immutable.List of tabs') + return state +} + +const validateWindowValue = function (windowValue) { + windowValue = makeImmutable(windowValue) + assert(isMap(windowValue), 'windowValue must be an Immutable.Map') + assert(windowValue.get('windowId'), 'window must have a windowId') + return windowValue +} + +const validateTabValue = function (tabValue) { + tabValue = makeImmutable(tabValue) + assert(isMap(tabValue), 'tabValue must be an Immutable.Map') + assert(tabValue.get('tabId'), 'tab must have a tabId') + return tabValue +} + +const validateAction = function (action) { + action = makeImmutable(action) + assert(isMap(action), 'action must be an Immutable.Map') + return action +} + +const api = { + getTabIndex: (state, tabValue) => { + state = validateState(state) + tabValue = validateTabValue(tabValue) + let tabId = validateId('tabId', tabValue.get('tabId')) + return api.getTabIndexByTabId(state, tabId) + }, getTabIndexByTabId: (state, tabId) => { + tabId = validateId('tabId', tabId) + state = validateState(state) + return state.get('tabs').findIndex((tab) => tab.get('tabId') === tabId) }, - createTab: (props) => { - props = makeImmutable(props) - return tabState.defaultTabState.merge(props) + removeTabByTabId: (state, tabId) => { + tabId = validateId('tabId', tabId) + state = validateState(state) + + let index = api.getTabIndexByTabId(state, tabId) + if (index === -1) { + return state + } + return api.removeTabByIndex(state, index) + }, + + removeTabByIndex: (state, index) => { + index = parseInt(index) + assert(index >= 0, 'index must be positive') + state = validateState(state) + return state.set('tabs', state.get('tabs').delete(index)) + }, + + closeFrame: (state, action) => { + let tabId = makeImmutable(action).getIn(['frameProps', 'tabId']) + return api.removeTabByTabId(state, tabId) }, - getOrCreateByTabId: (state, tabId) => { - let tab = tabState.getByTabId(state, tabId) - return tab || tabState.createTab({tabId}) + removeTab: (state, action) => { + action = validateAction(action) + state = validateState(state) + let tabValue = validateTabValue(action.get('tabValue')) + let tabId = validateId('tabId', tabValue.get('tabId')) + return api.removeTabByTabId(state, tabId) + }, + + insertTab: (state, action) => { + action = validateAction(action) + state = validateState(state) + let tabValue = validateTabValue(action.get('tabValue')) + assert(!api.getTab(state, tabValue), 'Tab already exists') + return state.set('tabs', state.get('tabs').push(tabValue)) + }, + + maybeCreateTab: (state, action) => { + action = validateAction(action) + state = validateState(state) + let tabValue = validateTabValue(action.get('tabValue')) + + if (api.getTab(state, tabValue)) { + return api.updateTab(state, action) + } else { + return api.insertTab(state, action) + } + }, + + getTabsByWindowId: (state, windowId) => { + state = validateState(state) + windowId = validateId('windowId', windowId) + return state.get('tabs').filter((tab) => tab.get('windowId') === windowId) + }, + + getTabsByWindow: (state, windowValue) => { + state = validateState(state) + windowValue = validateWindowValue(windowValue) + let windowId = validateId('windowId', windowValue.get('windowId')) + return state.get('tabs').filter((tab) => tab.get('windowId') === windowId) }, getByTabId: (state, tabId) => { + tabId = validateId('tabId', tabId) + state = validateState(state) + return state.get('tabs').find((tab) => tab.get('tabId') === tabId) }, - closeTab: (state, tabId) => { - let index = tabState.getTabIndexByTabId(state, tabId) + getTab: (state, tabValue) => { + state = validateState(state) + tabValue = validateTabValue(tabValue) + let tabId = validateId('tabId', tabValue.get('tabId')) + return api.getByTabId(state, tabId) + }, + + updateTab: (state, action) => { + state = validateAction(state) + action = validateAction(action) + let tabValue = validateTabValue(action.get('tabValue')) + let tabs = state.get('tabs') + let index = api.getTabIndex(state, tabValue) if (index === -1) { return state } - let tabs = state.get('tabs').delete(index) - state = state.set('tabs', tabs) - return state - }, + let currentTabValue = tabs.get(index) - updateTab: (state, tabId, tab) => { - let tabs = state.get('tabs') - let index = tabState.getTabIndexByTabId(state, tabId) - tabs = tabs.delete(index).insert(index, tab) - return state.set('tabs', tabs) + let tabId = tabValue.get('tabId') + if (tabId) { + tabId = validateId('tabId', tabId) + let currentTabId = currentTabValue.get('tabId') + if (currentTabId) { + assert(tabId === currentTabId, 'Changing a tabId is not allowed') + } + } + if (!action.get('replace')) { + tabValue = currentTabValue.mergeDeep(tabValue) + } + return state.set('tabs', tabs.delete(index).insert(index, tabValue)) }, - addTransientFields: (fields) => { - transientFields = transientFields.concat(fields) + getTabs: (state) => { + state = validateState(state) + return state.get('tabs') }, - getTransientFields: () => { - return transientFields + setTabs: (state, tabs) => { + state = validateState(state) + tabs = validateTabs(tabs) + return state.set('tabs', tabs) }, - getPersistentTabState: (tab) => { - tab = makeImmutable(tab) - tabState.getTransientFields().forEach((field) => { - tab = tab.delete(field) - }) - return tab + getPersistentState: (state) => { + // TODO(bridiver) - handle restoring tabs + state = makeImmutable(state) + return state.delete('tabs') } } -module.exports = tabState +module.exports = api diff --git a/app/common/state/windowState.js b/app/common/state/windowState.js new file mode 100644 index 00000000000..942995a88d2 --- /dev/null +++ b/app/common/state/windowState.js @@ -0,0 +1,148 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { makeImmutable, isMap, isList } = require('./immutableUtil') +const assert = require('assert') + +// TODO(bridiver) - make these generic validation functions +const validateId = function (propName, id) { + assert(id, `${propName} cannot be null`) + id = parseInt(id) + assert(id > 0, `${propName} must be positive`) + return id +} + +const validateState = function (state) { + state = makeImmutable(state) + assert(isMap(state), 'state must be an Immutable.Map') + assert(isList(state.get('windows')), 'state must contain an Immutable.List of windows') + return state +} + +const validateWindowValue = function (windowValue) { + windowValue = makeImmutable(windowValue) + assert(isMap(windowValue), 'windowValue must be an Immutable.Map') + assert(windowValue.get('windowId'), 'window must have a windowId') + return windowValue +} + +const validateAction = function (action) { + action = makeImmutable(action) + assert(isMap(action), 'action must be an Immutable.Map') + return action +} + +const api = { + getWindowIndex: (state, windowValue) => { + state = validateState(state) + + let windowId = validateId('windowId', windowValue.get('windowId')) + return api.getWindowIndexByWindowId(state, windowId) + }, + + insertWindow: (state, action) => { + action = validateAction(action) + state = validateState(state) + let windowValue = validateWindowValue(action.get('windowValue')) + assert(!api.getWindow(state, windowValue), 'Window already exists') + return state.set('windows', state.get('windows').push(windowValue)) + }, + + getWindow: (state, windowValue) => { + state = validateState(state) + windowValue = validateWindowValue(windowValue) + let windowId = windowValue.get('windowId') + return api.getByWindowId(state, windowId) + }, + + maybeCreateWindow: (state, action) => { + action = validateAction(action) + state = validateState(state) + let windowValue = validateWindowValue(action.get('windowValue')) + + if (api.getWindow(state, windowValue)) { + return api.updateWindow(state, action) + } else { + return api.insertWindow(state, action) + } + }, + + getByWindowId: (state, windowId) => { + state = validateState(state) + windowId = validateId('windowId', windowId) + return state.get('windows').find((win) => win.get('windowId') === windowId) + }, + + getWindowIndexByWindowId: (state, windowId) => { + state = validateState(state) + windowId = validateId('windowId', windowId) + return state.get('windows').findIndex((win) => win.get('windowId') === windowId) + }, + + removeWindowByWindowId: (state, windowId) => { + windowId = validateId('windowId', windowId) + state = validateState(state) + + let index = api.getWindowIndexByWindowId(state, windowId) + if (index === -1) { + return state + } + return api.removeWindowByIndex(state, index) + }, + + removeWindowByIndex: (state, index) => { + index = parseInt(index) + assert(index >= 0, 'index must be positive') + state = validateState(state) + return state.set('windows', state.get('windows').delete(index)) + }, + + removeWindow: (state, action) => { + action = validateAction(action) + state = validateState(state) + let windowValue = validateWindowValue(action.get('windowValue')) + let windowId = validateId('windowId', windowValue.get('windowId')) + return api.removeWindowByWindowId(state, windowId) + }, + + updateWindow: (state, action) => { + action = validateAction(action) + state = validateState(state) + let windowValue = validateWindowValue(action.get('windowValue')) + + let windows = state.get('windows') + let index = api.getWindowIndex(state, windowValue) + if (index === -1) { + return state + } + + let currentWindowValue = windows.get(index) + + let windowId = windowValue.get('windowId') + if (windowId) { + windowId = validateId('windowId', windowId) + let currentWindowId = currentWindowValue.get('windowId') + if (currentWindowId) { + assert(windowId === currentWindowId, 'Changing a windowId is not allowed') + } + } + if (!action.get('replace')) { + windowValue = currentWindowValue.mergeDeep(windowValue) + } + return state.set('windows', windows.delete(index).insert(index, windowValue)) + }, + + getWindows: (state) => { + state = validateState(state) + return state.get('windows') + }, + + getPersistentState: (state) => { + // TODO(bridiver) handle restoring state + state = makeImmutable(state) + return state.delete('windows') + } +} + +module.exports = api diff --git a/app/index.js b/app/index.js index 621ecf77ce3..c9123e41cdc 100644 --- a/app/index.js +++ b/app/index.js @@ -76,9 +76,7 @@ const ledger = require('./ledger') const flash = require('../js/flash') const contentSettings = require('../js/state/contentSettings') const privacy = require('../js/state/privacy') -const basicAuth = require('./browser/basicAuth') const async = require('async') -const tabs = require('./browser/tabs') const settings = require('../js/constants/settings') const webtorrent = require('./browser/webtorrent') @@ -295,7 +293,6 @@ app.on('ready', () => { let host = urlParse(url).host if (host && acceptCertDomains[host] === true) { // Ignore the cert error - e.preventDefault() cb(true) return } @@ -318,6 +315,7 @@ app.on('ready', () => { }) app.on('before-quit', (e) => { + appActions.shuttingDown() shuttingDown = true if (sessionStateStoreCompleteOnQuit) { return @@ -417,8 +415,6 @@ app.on('ready', () => { Menu.init(initialState, null) return loadedPerWindowState }).then((loadedPerWindowState) => { - tabs.init() - basicAuth.init() contentSettings.init() privacy.init() Autofill.init() diff --git a/app/sessionStore.js b/app/sessionStore.js index 65c0f3bffca..72dad5fa2cd 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -29,6 +29,9 @@ const autofill = require('./autofill') const {navigatableTypes} = require('../js/lib/appUrlUtil') // const tabState = require('./common/state/tabState') const Channel = require('./channel') +const { makeImmutable } = require('./common/state/immutableUtil') +const tabState = require('./common/state/tabState') +const windowState = require('./common/state/windowState') const getSetting = require('../js/settings').getSetting const promisify = require('../js/lib/promisify') @@ -68,7 +71,7 @@ module.exports.saveAppState = (payload, isShutdown) => { } try { - module.exports.cleanAppData(payload, isShutdown) + payload = module.exports.cleanAppData(payload, isShutdown) payload.cleanedOnShutdown = isShutdown } catch (e) { payload.cleanedOnShutdown = false @@ -231,6 +234,10 @@ module.exports.cleanPerWindowData = (perWindowData, isShutdown) => { * WARNING: getPrefs is only available in this function when isShutdown is true */ module.exports.cleanAppData = (data, isShutdown) => { + // make a copy + // TODO(bridiver) use immutable + data = makeImmutable(data).toJS() + if (data.settings) { // useragent value gets recalculated on restart data.settings[settings.USERAGENT] = undefined @@ -249,9 +256,7 @@ module.exports.cleanAppData = (data, isShutdown) => { try { delete data.ui.about.preferences.recoverySucceeded } catch (e) {} - // We used to store a huge list of IDs but we didn't use them. - // Get rid of them here. - delete data.windows + if (data.perWindowState) { data.perWindowState.forEach((perWindowState) => module.exports.cleanPerWindowData(perWindowState, isShutdown)) @@ -317,21 +322,14 @@ module.exports.cleanAppData = (data, isShutdown) => { }) } } - // all data in tabs is transient while we make the transition from window to app state - delete data.tabs - // if (data.tabs) { - // data.tabs = data.tabs.map((tab) => tabState.getPersistentTabState(tab).toJS()) - // } + data = tabState.getPersistentState(data).toJS() + data = windowState.getPersistentState(data).toJS() if (data.extensions) { Object.keys(data.extensions).forEach((extensionId) => { delete data.extensions[extensionId].tabs }) } - - if (data.about) { - delete data.about.brave - delete data.about.history - } + return data } /** @@ -444,7 +442,7 @@ module.exports.loadAppState = () => { } // Clean app data here if it wasn't cleared on shutdown if (data.cleanedOnShutdown !== true || data.lastAppVersion !== app.getVersion()) { - module.exports.cleanAppData(data, false) + data = module.exports.cleanAppData(data, false) } data = Object.assign(module.exports.defaultAppState(), data) data.cleanedOnShutdown = false @@ -467,7 +465,7 @@ module.exports.loadAppState = () => { } catch (e) { // TODO: Session state is corrupted, maybe we should backup this // corrupted value for people to report into support. - console.log('could not parse data: ', data) + console.log('could not parse data: ', data, e) data = exports.defaultAppState() data = setVersionInformation(data) } @@ -486,6 +484,7 @@ module.exports.defaultAppState = () => { firstRunTimestamp: new Date().getTime(), sites: topSites, tabs: [], + windows: [], extensions: {}, visits: [], settings: {}, diff --git a/docs/appActions.md b/docs/appActions.md index 9d519335333..dd27f86070f 100644 --- a/docs/appActions.md +++ b/docs/appActions.md @@ -33,6 +33,46 @@ Dispatches an event to the main process to create a new window. +### newTab(createProperties) + +A new tab has been requested + +**Parameters** + +**createProperties**: `Object`, windowId, url, active, openerTabId + + + +### tabCreated(tabValue) + +A new tab has been created + +**Parameters** + +**tabValue**: `Object`, A new tab has been created + + + +### tabUpdated(tabValue) + +A tab has been updated + +**Parameters** + +**tabValue**: `Object`, A tab has been updated + + + +### tabClosed(tabId) + +Closes an open tab + +**Parameters** + +**tabId**: `number`, Closes an open tab + + + ### addSite(siteDetail, tag, originalSiteDetail, destinationIsParent) Adds a site to the site list @@ -439,13 +479,14 @@ Autofill data changed -### windowBlurred(appWindowId) +### windowBlurred(windowId) Dispatches a message when appWindowId loses focus +Dispatches a message when windowId loses focus **Parameters** -**appWindowId**: `Number`, the unique id of the window +**windowId**: `Number`, the unique id of the window diff --git a/docs/state.md b/docs/state.md index ac78b58a578..485bb8b7523 100644 --- a/docs/state.md +++ b/docs/state.md @@ -10,6 +10,31 @@ AppStore ```javascript { firstRunTimestamp: integer, + tabs: [{ + // persistent properties + url: string, + index: number, // the position of the tab in the window + windowUUID: string, // the permanent identifier for the window + active: boolean, // whether the tab is selected + title: string, + favIconUrl: string, + // session properties + windowId: number, // the windowId that contains the tab + audible: boolean, // is audio playing (muted or not) + muted: boolean, // is the tab muted + }], + windows: [{ + // persistent properties + focused: boolean, + top: number, + left: number, + width: number, + height: number, + type: string, // "normal", "popup", or "devtools" + state: string // "normal", "minimized", "maximized", or "fullscreen" + // session properties + id: number, // the electron id for the window + }], extensions: { [id]: { // the unique id of the extension id: string, diff --git a/js/actions/appActions.js b/js/actions/appActions.js index f8f57982168..01158ac18c7 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -37,10 +37,75 @@ const appActions = { }) }, - closeWindow: function (appWindowId) { + closeWindow: function (windowId) { AppDispatcher.dispatch({ actionType: AppConstants.APP_CLOSE_WINDOW, - appWindowId + windowId + }) + }, + + windowClosed: function (windowValue) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_WINDOW_CLOSED, + windowValue + }) + }, + + windowCreated: function (windowValue) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_WINDOW_CREATED, + windowValue + }) + }, + + windowUpdated: function (windowValue) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_WINDOW_UPDATED, + windowValue + }) + }, + + /** + * A new tab has been requested + * @param {Object} createProperties - windowId, url, active, openerTabId + */ + newTab: function (createProperties) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_NEW_TAB, + createProperties + }) + }, + + /** + * A new tab has been created + * @param {Object} tabValue + */ + tabCreated: function (tabValue) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_TAB_CREATED, + tabValue + }) + }, + + /** + * A tab has been updated + * @param {Object} tabValue + */ + tabUpdated: function (tabValue) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_TAB_UPDATED, + tabValue + }) + }, + + /** + * Closes an open tab + * @param {number} tabId + */ + tabClosed: function (tabValue) { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_TAB_CLOSED, + tabValue }) }, @@ -511,13 +576,14 @@ const appActions = { /** * Dispatches a message when appWindowId loses focus + * Dispatches a message when windowId loses focus * - * @param {Number} appWindowId - the unique id of the window + * @param {Number} windowId - the unique id of the window */ - windowBlurred: function (appWindowId) { + windowBlurred: function (windowId) { AppDispatcher.dispatch({ actionType: AppConstants.APP_WINDOW_BLURRED, - appWindowId: appWindowId + windowId: windowId }) }, @@ -591,6 +657,12 @@ const appActions = { html, text }) + }, + + shuttingDown: function () { + AppDispatcher.dispatch({ + actionType: AppConstants.APP_SHUTTING_DOWN + }) } } diff --git a/js/components/frame.js b/js/components/frame.js index 8a84fbe1a83..e4731f1d3b0 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -355,7 +355,6 @@ class Frame extends ImmutableComponent { componentDidMount () { const cb = () => { this.webview.setActive(this.props.isActive) - this.webview.setAudioMuted(this.props.audioMuted || false) this.updateAboutDetails() } this.updateWebview(cb) @@ -431,7 +430,6 @@ class Frame extends ImmutableComponent { this.exitHtmlFullScreen() } } - this.webview.setAudioMuted(this.props.audioMuted || false) this.updateAboutDetails() } diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index d4d1298a945..fba7531fe23 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -8,6 +8,13 @@ const _ = null const AppConstants = { APP_NEW_WINDOW: _, APP_CLOSE_WINDOW: _, + APP_WINDOW_CLOSED: _, + APP_WINDOW_CREATED: _, + APP_WINDOW_UPDATED: _, + APP_NEW_TAB: _, + APP_CLOSE_TAB: _, + APP_TAB_CLOSED: _, + APP_TAB_UPDATED: _, APP_ADD_SITE: _, APP_CLEAR_HISTORY: _, APP_SET_STATE: _, @@ -65,8 +72,9 @@ const AppConstants = { APP_DEFAULT_BROWSER_CHECK_COMPLETE: _, APP_POPULATE_HISTORY: _, APP_RENDER_URL_TO_PDF: _, - APP_POPULATE_HISTORY: _, - APP_DATA_URL_COPIED: _ + APP_DATA_URL_COPIED: _, + APP_DEFAULT_BROWSER_CHECK_COMPLETE: _, + APP_SHUTTING_DOWN: _ } module.exports = mapValuesByKeys(AppConstants) diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 106ca5bc8a5..7cc209550ca 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -27,18 +27,24 @@ const getSetting = require('../settings').getSetting const EventEmitter = require('events').EventEmitter const Immutable = require('immutable') const diff = require('immutablediff') -const debounce = require('../lib/debounce.js') +const debounce = require('../lib/debounce') const locale = require('../../app/locale') const path = require('path') const autofill = require('../../app/autofill') const nativeImage = require('../../app/nativeImage') +const basicAuth = require('../../app/browser/basicAuth') +const tabs = require('../../app/browser/tabs') +const windows = require('../../app/browser/windows') + // state helpers const basicAuthState = require('../../app/common/state/basicAuthState') const extensionState = require('../../app/common/state/extensionState') const tabState = require('../../app/common/state/tabState') const aboutNewTabState = require('../../app/common/state/aboutNewTabState') const aboutHistoryState = require('../../app/common/state/aboutHistoryState') +const windowState = require('../../app/common/state/windowState') + const isDarwin = process.platform === 'darwin' const isWindows = process.platform === 'win32' @@ -49,6 +55,7 @@ const defaultProtocols = ['https', 'http'] let appState let lastEmittedState +let shuttingDown = false // TODO cleanup all this createWindow crap function isModal (browserOpts) { @@ -346,18 +353,28 @@ function handleChangeSettingAction (settingKey, settingValue) { } const handleAppAction = (action) => { + if (shuttingDown) { + return + } + const ledger = require('../../app/ledger') switch (action.actionType) { case AppConstants.APP_SET_STATE: appState = action.appState + windows.init(appState, action) + tabs.init(appState, action) + basicAuth.init(appState, action) + break + case AppConstants.APP_SHUTTING_DOWN: + shuttingDown = true break case AppConstants.APP_NEW_WINDOW: const frameOpts = action.frameOpts && action.frameOpts.toJS() const browserOpts = (action.browserOpts && action.browserOpts.toJS()) || {} - const windowState = action.restoredState || {} + const newWindowState = action.restoredState || {} - const mainWindow = createWindow(browserOpts, windowDefaults(), frameOpts, windowState) + const mainWindow = createWindow(browserOpts, windowDefaults(), frameOpts, newWindowState) const homepageSetting = getSetting(settings.HOMEPAGE) // initialize frames state @@ -408,8 +425,16 @@ const handleAppAction = (action) => { mainWindow.show() break case AppConstants.APP_CLOSE_WINDOW: - const appWindow = BrowserWindow.fromId(action.appWindowId) - appWindow.close() + appState = windows.closeWindow(appState, action) + break + case AppConstants.APP_WINDOW_CLOSED: + appState = windowState.removeWindow(appState, action) + break + case AppConstants.APP_WINDOW_CREATED: + appState = windowState.maybeCreateWindow(appState, action) + break + case AppConstants.APP_WINDOW_UPDATED: + appState = windowState.maybeCreateWindow(appState, action) break case AppConstants.APP_ADD_PASSWORD: // If there is already an entry for this exact origin, action, and @@ -709,13 +734,13 @@ const handleAppAction = (action) => { appState = appState.setIn(['autofill', 'creditCards', 'timestamp'], date) break case AppConstants.APP_SET_LOGIN_REQUIRED_DETAIL: - appState = basicAuthState.setLoginRequiredDetail(appState, action.tabId, action.detail) + appState = basicAuthState.setLoginRequiredDetail(appState, action) break case AppConstants.APP_SET_LOGIN_RESPONSE_DETAIL: - appState = basicAuthState.setLoginResponseDetail(appState, action.tabId, action.detail) + appState = basicAuth.setLoginResponseDetail(appState, action) break case WindowConstants.WINDOW_CLOSE_FRAME: - appState = tabState.closeTab(appState, action.frameProps.get('tabId')) + appState = tabState.closeFrame(appState, action) break case ExtensionConstants.BROWSER_ACTION_REGISTERED: appState = extensionState.browserActionRegistered(appState, action) @@ -780,10 +805,23 @@ const handleAppAction = (action) => { appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) appState = aboutNewTabState.setSites(appState, action) break - case WindowConstants.WINDOW_SET_NAVIGATED: - if (!action.isNavigatedInPage) { - appState = extensionState.browserActionUpdated(appState, action) - } + case AppConstants.APP_NEW_TAB: + appState = tabs.newTab(appState, action) + break + case AppConstants.APP_TAB_CREATED: + appState = tabState.maybeCreateTab(appState, action) + break + case AppConstants.APP_TAB_UPDATED: + appState = tabState.maybeCreateTab(appState, action) + break + case AppConstants.APP_CLOSE_TAB: + appState = tabs.removeTab(appState, action) + break + case AppConstants.APP_TAB_CLOSED: + appState = tabState.removeTab(appState, action) + break + case WindowConstants.WINDOW_SET_AUDIO_MUTED: + appState = tabs.setAudioMuted(appState, action) break case AppConstants.APP_RENDER_URL_TO_PDF: const pdf = require('../../app/pdf') diff --git a/js/stores/eventStore.js b/js/stores/eventStore.js index 68dad951872..98c5adfaed4 100644 --- a/js/stores/eventStore.js +++ b/js/stores/eventStore.js @@ -95,7 +95,7 @@ const doAction = (action) => { addPageView(action.frameProps.get('location'), lastActiveTabId) break case AppConstants.APP_WINDOW_BLURRED: - windowBlurred(action.appWindowId) + windowBlurred(action.windowId) break case AppConstants.APP_IDLE_STATE_CHANGED: if (action.idleState !== 'active') { @@ -106,7 +106,7 @@ const doAction = (action) => { break case AppConstants.APP_CLOSE_WINDOW: AppDispatcher.waitFor([AppStore.dispatchToken], () => { - windowClosed(action.appWindowId) + windowClosed(action.windowId) }) break case 'event-set-page-info': diff --git a/test/unit/app/common/state/basicAuthStateTest.js b/test/unit/app/common/state/basicAuthStateTest.js index df354f2cf71..f8bfc258dab 100644 --- a/test/unit/app/common/state/basicAuthStateTest.js +++ b/test/unit/app/common/state/basicAuthStateTest.js @@ -5,11 +5,17 @@ const Immutable = require('immutable') const assert = require('assert') const defaultAppState = Immutable.fromJS({ + windows: [{ + windowId: 1, + windowUUID: 'uuid' + }], tabs: [] }) const defaultTab = Immutable.fromJS({ tabId: 1, + windowId: 1, + windowUUID: 'uuid', loginRequiredDetail: { request: { url: 'someurl' }, authInfo: { authInfoProp: 'value' } @@ -21,10 +27,11 @@ describe('basicAuthState', function () { describe('`tabId` exists in appState with loginRequiredDetail', function () { before(function () { this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab])) - this.appState = basicAuthState.setLoginResponseDetail(this.appState, 1, { - username: 'username', - password: 'password' - }) + this.appState = basicAuthState.setLoginResponseDetail(this.appState, {tabId: 1, + detail: { + username: 'username', + password: 'password' + }}) }) it('removes the login detail', function () { @@ -37,10 +44,11 @@ describe('basicAuthState', function () { describe('`tabId` exists in appState with no loginRequiredDetail', function () { before(function () { this.appState = defaultAppState.set('tabs', Immutable.fromJS([{ tabId: 1 }])) - this.appState = basicAuthState.setLoginResponseDetail(this.appState, 1, { - username: 'username', - password: 'password' - }) + this.appState = basicAuthState.setLoginResponseDetail(this.appState, {tabId: 1, + detail: { + username: 'username', + password: 'password' + }}) }) it('returns the unmodified appState', function () { @@ -52,10 +60,11 @@ describe('basicAuthState', function () { describe('`tabId` does not exist in appState', function () { before(function () { - this.appState = basicAuthState.setLoginResponseDetail(defaultAppState, 1, { - username: 'username', - password: 'password' - }) + this.appState = basicAuthState.setLoginResponseDetail(defaultAppState, {tabId: 1, + detail: { + username: 'username', + password: 'password' + }}) }) it('returns the unmodified appState', function () { @@ -71,7 +80,7 @@ describe('basicAuthState', function () { describe('with null detail', function () { before(function () { this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab])) - this.appState = basicAuthState.setLoginRequiredDetail(this.appState, 1, null) + this.appState = basicAuthState.setLoginRequiredDetail(this.appState, {tabId: 1}) }) it('removes the login detail', function () { @@ -84,7 +93,7 @@ describe('basicAuthState', function () { describe('with empty detail', function () { before(function () { this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab])) - this.appState = basicAuthState.setLoginRequiredDetail(this.appState, 1, {}) + this.appState = basicAuthState.setLoginRequiredDetail(this.appState, {tabId: 1, detail: {}}) }) it('removes the login detail', function () { @@ -101,10 +110,11 @@ describe('basicAuthState', function () { tabId: 1 } ])) - this.appState = basicAuthState.setLoginRequiredDetail(this.appState, 1, { - request: { url: 'someurl' }, - authInfo: { authInfoProp: 'value' } - }) + this.appState = basicAuthState.setLoginRequiredDetail(this.appState, {tabId: 1, + detail: { + request: { url: 'someurl' }, + authInfo: { authInfoProp: 'value' } + }}) }) it('sets the login detail for `tabId` in the appState', function () { @@ -118,18 +128,15 @@ describe('basicAuthState', function () { describe('`tabId` does not exist in appState', function () { before(function () { - this.appState = basicAuthState.setLoginRequiredDetail(defaultAppState, 1, { - request: { url: 'someurl' }, - authInfo: { authInfoProp: 'value' } - }) + this.appState = basicAuthState.setLoginRequiredDetail(defaultAppState, {tabId: 1, + detail: { + request: { url: 'someurl' }, + authInfo: { authInfoProp: 'value' } + }}) }) - it('creates a new tab in the appState and sets the login detail', function () { - let tab = tabState.getByTabId(this.appState, 1) - assert(tab) - let loginRequiredDetail = tab.get('loginRequiredDetail') - assert.equal('someurl', loginRequiredDetail.getIn(['request', 'url'])) - assert.equal('value', loginRequiredDetail.getIn(['authInfo', 'authInfoProp'])) + it('returns the state', function () { + assert.equal(defaultAppState, this.appState) }) }) }) diff --git a/test/unit/app/common/state/tabStateTest.js b/test/unit/app/common/state/tabStateTest.js index 2daf1b33182..8e8baced634 100644 --- a/test/unit/app/common/state/tabStateTest.js +++ b/test/unit/app/common/state/tabStateTest.js @@ -1,155 +1,383 @@ /* global describe, it, before */ const tabState = require('../../../../../app/common/state/tabState') const Immutable = require('immutable') -const assert = require('assert') +const assert = require('chai').assert +const AssertionError = require('assert').AssertionError const defaultAppState = Immutable.fromJS({ tabs: [], + windows: [], otherProp: true }) +const shouldValidateId = function (cb) { + it('throws an AssertionError if tabId is not a number', function () { + assert.throws( + () => { + cb(null) + }, + AssertionError + ) + assert.throws( + () => { + cb('b') + }, + AssertionError + ) + assert.doesNotThrow( + () => { + cb('1') + }, + AssertionError + ) + }) + + it('throws an AssertionError if tabId < 1 and !== -1', function () { + assert.throws( + () => { + cb(0) + }, + AssertionError + ) + assert.throws( + () => { + cb(-2) + }, + AssertionError + ) + assert.doesNotThrow( + () => { + cb(-1) + }, + AssertionError + ) + }) +} + +const shouldValidateTabState = function (cb) { + it('throws an AssertionError if state does not contain a `tabs` array', function () { + assert.doesNotThrow( + () => { + cb(Immutable.fromJS({ tabs: [] })) + }, + AssertionError + ) + assert.throws( + () => { + cb(Immutable.Map({})) + }, + AssertionError + ) + }) + + it('throws an AssertionError if state is not convertable to an Immutable.Map', function () { + assert.doesNotThrow( + () => { + cb({ tabs: [] }) + }, + AssertionError + ) + assert.throws( + () => { + cb([]) + }, + AssertionError + ) + assert.throws( + () => { + cb('test') + }, + AssertionError + ) + assert.throws( + () => { + cb(null) + }, + AssertionError + ) + }) +} + +const shouldValidateTabValue = function (cb) { + it('throws an AssertionError if `tabValue` does not contain a valid `tabId`', function () { + assert.doesNotThrow( + () => { + cb({ tabId: 1 }) + }, + AssertionError + ) + assert.throws( + () => { + cb({}) + }, + AssertionError + ) + assert.throws( + () => { + cb({ tabId: 'a' }) + }, + AssertionError + ) + }) +} + +const shouldValidateAction = function (cb) { + it('throws an AssertionError if action does not contain a `tabValue` that is convertable to an Immutable.Map', function () { + assert.doesNotThrow( + () => { + cb(Immutable.fromJS({ tabValue: { tabId: 1 } })) + cb({ tabValue: { tabId: 1 } }) + }, + AssertionError + ) + assert.throws( + () => { + cb(Immutable.Map({ blah: {} })) + }, + AssertionError + ) + assert.throws( + () => { + cb(Immutable.Map({})) + }, + AssertionError + ) + }) + + it('throws an AssertionError if `action` is not convertable to an Immutable.Map', function () { + assert.doesNotThrow( + () => { + cb({ tabValue: { tabId: 1 } }) + }, + AssertionError + ) + assert.throws( + () => { + cb([]) + }, + AssertionError + ) + assert.throws( + () => { + cb('test') + }, + AssertionError + ) + assert.throws( + () => { + cb(null) + }, + AssertionError + ) + }) +} + describe('tabState', function () { - describe('createTab', function () { - it('creates a new tab from the defaultTabState', function () { - let tab = tabState.createTab({}) - tabState.defaultTabState.keys((key) => { - assert.equal(tabState.defaultTabState.get(key), tab.get(key)) - }) - }) - - it('merges supplied and default values', function () { - let tab = tabState.createTab({tabId: 20, myProp: 'test'}) - tabState.defaultTabState.keys((key) => { - if (key !== 'tabId') { - assert.equal(tabState.defaultTabState.get(key), tab.get(key)) - } - }) - assert.equal(20, tab.get('tabId')) - assert.equal('test', tab.get('myProp')) + describe('getTabIndexByTabId', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 2 }, + { tabId: 3 }, + { tabId: 1 } + ])) + }) + + it('returns the index of the tab for the tabId', function () { + assert.equal(tabState.getTabIndexByTabId(this.appState, 1), 2) + assert.equal(tabState.getTabIndexByTabId(this.appState, 2), 0) + assert.equal(tabState.getTabIndexByTabId(this.appState, 3), 1) + }) + + it('returns -1 if the tabId does not exist', function () { + assert.equal(tabState.getTabIndexByTabId(this.appState, 4), -1) + }) + + shouldValidateId((tabId) => { + tabState.getTabIndexByTabId(defaultAppState, tabId) + }) + + shouldValidateTabState((state) => { + tabState.getTabIndexByTabId(state, 1) }) }) describe('getByTabId', function () { - describe('`tabId` exists in appState', function () { - before(function () { - this.appState = defaultAppState.set('tabs', Immutable.fromJS([ - { - windowId: 1, - frameKey: 1, - tabId: 2 - } - ])) - }) + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { + windowId: 1, + frameKey: 1, + tabId: 2 + }, + { + windowId: 1, + frameKey: 2, + tabId: 1 + } + ])) + }) - it('returns the tab for `tabId` from the appState', function () { - let tab = tabState.getByTabId(this.appState, 2) - assert(tab) - assert.equal(1, tab.get('windowId')) - assert.equal(1, tab.get('frameKey')) - assert.equal(2, tab.get('tabId')) - }) + it('returns the tab for `tabId` if it exists', function () { + let tab = tabState.getByTabId(this.appState, 2) + assert(tab) + assert.equal(1, tab.get('windowId')) + assert.equal(1, tab.get('frameKey')) + assert.equal(2, tab.get('tabId')) + }) + + it('returns null if the tab for `tabId` does not exist', function () { + let tab = tabState.getByTabId(defaultAppState, 3) + assert.equal(null, tab) }) - describe('`tabId` does not exist in appState', function () { - it('returns null', function () { - let tab = tabState.getByTabId(defaultAppState, 2) - assert.equal(null, tab) - }) + shouldValidateId((tabId) => { + tabState.getByTabId(defaultAppState, tabId) + }) + + shouldValidateTabState((state) => { + tabState.getByTabId(state, 1) }) }) - describe('closeTab', function () { - describe('`tabId` exists in appState', function () { - before(function () { - this.appState = defaultAppState.set('tabs', Immutable.fromJS([ - { - windowId: 1, - frameKey: 1, - tabId: 1, - myProp: 'test1', - myProp2: 'blah' - }, - { - windowId: 1, - frameKey: 1, - tabId: 2, - myProp: 'test2', - myProp2: 'blah' - } - ])) - - this.newAppState = tabState.closeTab(this.appState, 2) - }) - - it('removes the tab from the appState', function () { - let tab2 = this.newAppState.get('tabs').find((tab) => tab.get('tabId') === 2) - assert.equal(undefined, tab2) - let tab1 = this.newAppState.get('tabs').find((tab) => tab.get('tabId') === 1) - assert(tab1) - }) - - it('does not change other values in the appState', function () { - let tab = this.newAppState.get('tabs').find((tab) => tab.get('tabId') === 1) - assert(tab) - assert.equal('test1', tab.get('myProp')) - assert.equal('blah', tab.get('myProp2')) - assert.equal(1, tab.get('windowId')) - assert.equal(1, tab.get('frameKey')) - assert.equal(1, tab.get('tabId')) - assert.equal(true, this.newAppState.get('otherProp')) - }) - }) - - describe('`tabId` does not exist in appState', function () { - before(function () { - this.appState = defaultAppState.set('tabs', Immutable.fromJS([ - { - windowId: 1, - frameKey: 1, - tabId: 1, - myProp: 'test1', - myProp2: 'blah' - } - ])) + describe('removeTabByTabId', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1 }, + { tabId: 2 } + ])) + }) - this.newAppState = tabState.closeTab(this.appState, 2) - }) + it('returns a new immutable state with the tab for `tabId` removed if it exists', function () { + assert.deepEqual(tabState.removeTabByTabId(this.appState, 2).get('tabs').toJS(), [ {tabId: 1} ]) + }) - it('returns the original appState', function () { - assert(this.appState.equals(this.newAppState)) - }) + it('returns the state unmodified if the tab for `tabId` does not exist', function () { + assert.deepEqual(tabState.removeTabByTabId(this.appState, 3).toJS(), this.appState.toJS()) + }) + + shouldValidateId((tabId) => { + tabState.removeTabByTabId(defaultAppState, tabId) + }) + + shouldValidateTabState((state) => { + tabState.removeTabByTabId(state, 1) }) }) - describe('getOrCreateByTabId', function () { - describe('`tabId` exists in appState', function () { - before(function () { - this.appState = defaultAppState.set('tabs', Immutable.fromJS([ - { - windowId: 1, - frameKey: 1, - tabId: 2 - } - ])) - }) - - it('returns the tab for `tabId` from the appState', function () { - let tab = tabState.getOrCreateByTabId(this.appState, 2) - assert(tab) - assert.equal(1, tab.get('windowId')) - assert.equal(1, tab.get('frameKey')) - assert.equal(2, tab.get('tabId')) - }) - }) - - describe('`tabId` does not exist in appState', function () { - it('creates a new tab for `tabId`', function () { - let tab = tabState.getOrCreateByTabId(defaultAppState, 2) - assert(tab) - assert.equal(-1, tab.get('windowId')) - assert.equal(-1, tab.get('frameKey')) - assert.equal(2, tab.get('tabId')) - }) + describe('removeTabByIndex', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1 }, + { tabId: 2 } + ])) + }) + + it('returns a new immutable state with the tab at `index` removed if it exists', function () { + assert.deepEqual(tabState.removeTabByIndex(this.appState, 1).get('tabs').toJS(), [ {tabId: 1} ]) + }) + + it('returns the state unmodified if `index` is out of bounds', function () { + assert.deepEqual(tabState.removeTabByIndex(this.appState, 2).toJS(), this.appState.toJS()) + }) + + it('throws an AssertionError if `index` < 0', function () { + assert.throws( + () => { + tabState.removeTabByIndex(this.appState, -1) + }, + AssertionError + ) + }) + + it('throws an AssertionError if `index` is not a number', function () { + assert.throws( + () => { + tabState.removeTabByIndex(this.appState, null) + }, + AssertionError + ) + assert.throws( + () => { + tabState.removeTabByIndex(this.appState, 'a') + }, + AssertionError + ) + assert.doesNotThrow( + () => { + tabState.removeTabByIndex(this.appState, '1') + }, + AssertionError + ) + }) + + shouldValidateTabState((state) => { + tabState.removeTabByIndex(state, 1) + }) + }) + + describe('removeTab', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1 }, + { tabId: 2 } + ])) + }) + + it('returns a new immutable state with the tab removed by `tabId`', function () { + assert.deepEqual( + tabState.removeTab(this.appState, { tabValue: { tabId: 2 } }).get('tabs').toJS(), + [{ tabId: 1 }]) + }) + + shouldValidateAction((action) => { + tabState.removeTab(defaultAppState, action) + }) + + shouldValidateTabValue((tabValue) => { + tabState.removeTab(defaultAppState, { tabValue }) + }) + + shouldValidateId((tabId) => { + tabState.removeTab(defaultAppState, { tabValue: { tabId } }) + }) + + shouldValidateTabState((state) => { + tabState.removeTab(state, { tabValue: { tabId: 1 } }) + }) + }) + + describe('insertTab', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1 } + ])) + }) + + it('returns a new immutable state with the tabValue appended to the end of the list', function () { + assert.deepEqual( + tabState.insertTab(this.appState, { tabValue: { tabId: 2 } }).get('tabs').toJS(), + [{ tabId: 1 }, { tabId: 2 }]) + }) + + it('throws an AssertionError if there is already a tab with the tabId', function () { + assert.throws( + () => { + tabState.insertTab(this.appState, { tabValue: { tabId: 1 } }) + }, + AssertionError + ) + }) + + shouldValidateAction((action) => { + tabState.insertTab(defaultAppState, action) + }) + + shouldValidateTabValue((tabValue) => { + tabState.insertTab(defaultAppState, { tabValue }) + }) + + shouldValidateTabState((state) => { + tabState.insertTab(state, { tabValue: { tabId: 1 } }) }) }) @@ -171,74 +399,75 @@ describe('tabState', function () { myProp2: 'blah' } ])) - - this.newAppState = tabState.updateTab(this.appState, 2, Immutable.fromJS({ - windowId: 1, - frameKey: 1, - tabId: 2, - myProp: 'test3' - })) }) - it('error for no such tabId') + it('returns a new immutable state with the tabValue updated if it already exists', function () { + assert.deepEqual( + tabState.updateTab(this.appState, { tabValue: { tabId: 1, test: 'blue', myProp: 'test2' } }).get('tabs').toJS(), [ + { + tabId: 1, + test: 'blue', + windowId: 1, + frameKey: 1, + myProp: 'test2', + myProp2: 'blah' + }, + { + windowId: 1, + frameKey: 1, + tabId: 2, + myProp: 'test2', + myProp2: 'blah' + } + ]) + }) - it('updates the tab values for `tabId` in the appState', function () { - let tab = this.newAppState.get('tabs').find((tab) => tab.get('tabId') === 2) - assert(tab) - assert.equal('test3', tab.get('myProp')) - assert.equal(undefined, tab.get('myProp2')) - assert.equal(1, tab.get('windowId')) - assert.equal(1, tab.get('frameKey')) - assert.equal(2, tab.get('tabId')) + it('returns a new immutable state with the tabValue replaced if it already exists and `replace` is true', function () { + assert.deepEqual( + tabState.updateTab(this.appState, { replace: true, tabValue: { tabId: 1, test: 'blue', myProp: 'test2' } }).get('tabs').toJS(), [ + { + tabId: 1, + test: 'blue', + myProp: 'test2' + }, + { + windowId: 1, + frameKey: 1, + tabId: 2, + myProp: 'test2', + myProp2: 'blah' + } + ]) }) it('does not change other values in the appState', function () { - let tab = this.newAppState.get('tabs').find((tab) => tab.get('tabId') === 1) + let state = tabState.updateTab(this.appState, { tabValue: { tabId: 2, test: 'blue' } }) + let tab = state.get('tabs').find((tab) => tab.get('tabId') === 1) assert(tab) assert.equal('test1', tab.get('myProp')) assert.equal('blah', tab.get('myProp2')) assert.equal(1, tab.get('windowId')) assert.equal(1, tab.get('frameKey')) assert.equal(1, tab.get('tabId')) - assert.equal(true, this.newAppState.get('otherProp')) + assert.equal(true, state.get('otherProp')) }) - }) - describe('getOrCreateByTabId', function () { - describe('`tabId` exists in appState', function () { - before(function () { - this.appState = defaultAppState.set('tabs', Immutable.fromJS([ - { - windowId: 1, - frameKey: 1, - tabId: 2 - } - ])) - }) - - it('returns the tab for `tabId` from the appState', function () { - let tab = tabState.getOrCreateByTabId(this.appState, 2) - assert(tab) - assert.equal(1, tab.get('windowId')) - assert.equal(1, tab.get('frameKey')) - assert.equal(2, tab.get('tabId')) - }) - }) - - describe('`tabId` does not exist in appState', function () { - it('creates a new tab for `tabId`', function () { - let tab = tabState.getOrCreateByTabId(defaultAppState, 2) - assert(tab) - assert.equal(-1, tab.get('windowId')) - assert.equal(-1, tab.get('frameKey')) - assert.equal(2, tab.get('tabId')) - }) + shouldValidateAction((action) => { + tabState.updateTab(defaultAppState, action) + }) + + shouldValidateTabValue((tabValue) => { + tabState.updateTab(defaultAppState, { tabValue }) + }) + + shouldValidateTabState((state) => { + tabState.updateTab(state, { tabValue: { tabId: 1 } }) }) }) - describe('getPersistentTabState', function () { + describe('getPersistentState', function () { before(function () { - this.tab = Immutable.fromJS({ + this.tabs = Immutable.fromJS([{ windowId: 1, frameKey: 1, tabId: 2, @@ -246,24 +475,186 @@ describe('tabState', function () { request: { url: 'someurl' }, authInfo: { authInfoProp: 'value' } } - }) - this.tab = tabState.getPersistentTabState(this.tab) + }]) + this.tabs = tabState.getPersistentState(this.tabs) + }) + }) + + describe('maybeCreateTab', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1 } + ])) + }) + + it('returns a new immutable state with the tabValue appended to the end of the list if it does not already exist', function () { + assert.deepEqual( + tabState.maybeCreateTab(this.appState, { tabValue: { tabId: 2 } }).get('tabs').toJS(), + [{ tabId: 1 }, { tabId: 2 }]) }) - it('should keep frameKey', function () { - assert.equal(1, this.tab.get('frameKey')) + it('returns a new immutable state with the tabValue updated if it already exists', function () { + assert.deepEqual( + tabState.maybeCreateTab(this.appState, { tabValue: { tabId: 1, test: 'blue' } }).get('tabs').toJS(), + [{ tabId: 1, test: 'blue' }]) }) - it('should remove windowId', function () { - assert.equal(undefined, this.tab.get('tabId')) + shouldValidateAction((action) => { + tabState.maybeCreateTab(defaultAppState, action) }) - it('should remove tabId', function () { - assert.equal(undefined, this.tab.get('tabId')) + shouldValidateTabValue((tabValue) => { + tabState.maybeCreateTab(defaultAppState, { tabValue }) + }) + + shouldValidateTabState((state) => { + tabState.maybeCreateTab(state, { tabValue: { tabId: 1 } }) + }) + }) + + describe('getTabsByWindowId', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1, windowId: 1 }, + { tabId: 2, windowId: 1 }, + { tabId: 3, windowId: 2 } + ])) + }) + + it('returns the tabs with `windowId`', function () { + assert.deepEqual(tabState.getTabsByWindowId(this.appState, 1).toJS(), [ + { tabId: 1, windowId: 1 }, + { tabId: 2, windowId: 1 } + ]) + assert.deepEqual(tabState.getTabsByWindowId(this.appState, 2).toJS(), [ + { tabId: 3, windowId: 2 } + ]) + assert.deepEqual(tabState.getTabsByWindowId(this.appState, 3).toJS(), []) + }) + + shouldValidateTabState((state) => { + tabState.getTabsByWindowId(state, 1) + }) + + shouldValidateId((windowId) => { + tabState.getTabsByWindowId(defaultAppState, windowId) + }) + }) + + describe('getTabsForWindow', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1, windowId: 1 }, + { tabId: 2, windowId: 1 }, + { tabId: 3, windowId: 2 } + ])) + }) + + it('returns the tabs with matching the `windowId`', function () { + assert.deepEqual(tabState.getTabsByWindow(this.appState, { windowId: 1 }).toJS(), [ + { tabId: 1, windowId: 1 }, + { tabId: 2, windowId: 1 } + ]) + assert.deepEqual(tabState.getTabsByWindow(this.appState, { windowId: 2 }).toJS(), [ + { tabId: 3, windowId: 2 } + ]) + assert.deepEqual(tabState.getTabsByWindow(this.appState, { windowId: 3 }).toJS(), []) + }) + + it('throws an AssertionError if `windowValue` does not contain a valid `windowId`', function () { + assert.doesNotThrow( + () => { + tabState.getTabsByWindow(this.appState, { windowId: 1 }) + }, + AssertionError + ) + assert.throws( + () => { + tabState.getTabsByWindow(this.appState, {}) + }, + AssertionError + ) + assert.throws( + () => { + tabState.getTabsByWindow(this.appState, { windowId: 'a' }) + }, + AssertionError + ) + }) + + shouldValidateTabState((state) => { + tabState.getTabsByWindow(state, { windowId: 1 }) + }) + }) + + describe('getTabs', function () { + shouldValidateTabState((state) => { + tabState.getTabs(state) + }) + }) + + describe('setTabs', function () { + before(function () { + this.appState = defaultAppState.set('tabs', Immutable.fromJS([ + { tabId: 1, windowId: 1 } + ])) + }) + + it('returns a new immutable state with state.tabs set to the tab list', function () { + let tabList = [ + { tabId: 1, windowId: 1 }, + { tabId: 2, windowId: 1 } + ] + assert.deepEqual(tabState.setTabs(this.appState, tabList).get('tabs').toJS(), tabList) + }) + + it('throws an AssertionError if `tabs` does not contain an Immutable.List of valid tabValue', function () { + assert.doesNotThrow( + () => { + tabState.setTabs(defaultAppState, []) + }, + AssertionError + ) + assert.doesNotThrow( + () => { + tabState.setTabs(defaultAppState, Immutable.List()) + }, + AssertionError + ) + assert.throws( + () => { + tabState.setTabs(defaultAppState, [{ frameKey: 1 }]) + }, + AssertionError + ) + assert.throws( + () => { + tabState.setTabs(defaultAppState, {}) + }, + AssertionError + ) + assert.throws( + () => { + tabState.setTabs(defaultAppState, null) + }, + AssertionError + ) + assert.throws( + () => { + tabState.setTabs(defaultAppState, 'blah') + }, + AssertionError + ) + assert.throws( + () => { + tabState.setTabs(defaultAppState, 11) + }, + AssertionError + ) }) - it('should remove loginRequiredDetail', function () { - assert.equal(undefined, this.tab.get('loginRequiredDetail')) + shouldValidateTabState((state) => { + tabState.setTabs(state, []) }) }) }) diff --git a/test/unit/common/state/windowStateTest.js b/test/unit/common/state/windowStateTest.js new file mode 100644 index 00000000000..fea29f807d7 --- /dev/null +++ b/test/unit/common/state/windowStateTest.js @@ -0,0 +1,480 @@ +/* global describe, it, before */ +const windowState = require('../../../../app/common/state/windowState') +const Immutable = require('immutable') +const assert = require('chai').assert +const AssertionError = require('assert').AssertionError + +const defaultAppState = Immutable.fromJS({ + tabs: [], + windows: [], + otherProp: true +}) + +const shouldValidateId = function (cb) { + it('throws an AssertionError if windowId is not a number', function () { + assert.throws( + () => { + cb(null) + }, + AssertionError + ) + assert.throws( + () => { + cb('b') + }, + AssertionError + ) + assert.doesNotThrow( + () => { + cb('1') + }, + AssertionError + ) + }) + + it('throws an AssertionError if windowId < 1', function () { + assert.throws( + () => { + cb(0) + }, + AssertionError + ) + assert.throws( + () => { + cb(-1) + }, + AssertionError + ) + }) +} + +const shouldValidateWindowState = function (cb) { + it('throws an AssertionError if state does not contain a `windows` array', function () { + assert.doesNotThrow( + () => { + cb(Immutable.fromJS({ windows: [] })) + }, + AssertionError + ) + assert.throws( + () => { + cb(Immutable.Map({})) + }, + AssertionError + ) + }) + + it('throws an AssertionError if state is not convertable to an Immutable.Map', function () { + assert.doesNotThrow( + () => { + cb({ windows: [] }) + }, + AssertionError + ) + assert.throws( + () => { + cb([]) + }, + AssertionError + ) + assert.throws( + () => { + cb('test') + }, + AssertionError + ) + assert.throws( + () => { + cb(null) + }, + AssertionError + ) + }) +} + +const shouldValidateWindowValue = function (cb) { + it('throws an AssertionError if `windowValue` does not contain a valid `windowId`', function () { + assert.doesNotThrow( + () => { + cb({ windowId: 1 }) + }, + AssertionError + ) + assert.throws( + () => { + cb({}) + }, + AssertionError + ) + assert.throws( + () => { + cb({ windowId: 'a' }) + }, + AssertionError + ) + }) +} + +const shouldValidateAction = function (cb) { + it('throws an AssertionError if action does not contain a `windowValue` that is convertable to an Immutable.Map', function () { + assert.doesNotThrow( + () => { + cb(Immutable.fromJS({ windowValue: { windowId: 1 } })) + cb({ windowValue: { windowId: 1 } }) + }, + AssertionError + ) + assert.throws( + () => { + cb(Immutable.Map({ blah: {} })) + }, + AssertionError + ) + assert.throws( + () => { + cb(Immutable.Map({})) + }, + AssertionError + ) + }) + + it('throws an AssertionError if `action` is not convertable to an Immutable.Map', function () { + assert.doesNotThrow( + () => { + cb({ windowValue: { windowId: 1 } }) + }, + AssertionError + ) + assert.throws( + () => { + cb([]) + }, + AssertionError + ) + assert.throws( + () => { + cb('test') + }, + AssertionError + ) + assert.throws( + () => { + cb(null) + }, + AssertionError + ) + }) +} + +describe('windowState', function () { + describe('getWindowIndexByWindowId', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 2 }, + { windowId: 3 }, + { windowId: 1 } + ])) + }) + + it('returns the index of the tab for the windowId', function () { + assert.equal(windowState.getWindowIndexByWindowId(this.appState, 1), 2) + assert.equal(windowState.getWindowIndexByWindowId(this.appState, 2), 0) + assert.equal(windowState.getWindowIndexByWindowId(this.appState, 3), 1) + }) + + it('returns -1 if the windowId does not exist', function () { + assert.equal(windowState.getWindowIndexByWindowId(this.appState, 4), -1) + }) + + shouldValidateId((windowId) => { + windowState.getWindowIndexByWindowId(defaultAppState, windowId) + }) + + shouldValidateWindowState((state) => { + windowState.getWindowIndexByWindowId(state, 1) + }) + }) + + describe('getByWindowId', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 1, focused: false }, + { windowId: 2, focused: true } + ])) + }) + + it('returns the window for `windowId` if it exists', function () { + let win = windowState.getByWindowId(this.appState, 2) + assert(win) + assert.equal(win.get('windowId'), 2) + assert.equal(win.get('focused'), true) + }) + + it('returns null if the win for `windowId` does not exist', function () { + let win = windowState.getByWindowId(defaultAppState, 3) + assert.equal(win, null) + }) + + shouldValidateId((windowId) => { + windowState.getByWindowId(defaultAppState, windowId) + }) + + shouldValidateWindowState((state) => { + windowState.getByWindowId(state, 1) + }) + }) + + describe('removeWindowByWindowId', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 1 }, + { windowId: 2 } + ])) + }) + + it('returns a new immutable state with the window for `windowId` removed if it exists', function () { + assert.deepEqual(windowState.removeWindowByWindowId(this.appState, 2).get('windows').toJS(), [ {windowId: 1} ]) + }) + + it('returns the state unmodified if the window for `windowId` does not exist', function () { + assert.deepEqual(windowState.removeWindowByWindowId(this.appState, 3).toJS(), this.appState.toJS()) + }) + + shouldValidateId((windowId) => { + windowState.removeWindowByWindowId(defaultAppState, windowId) + }) + + shouldValidateWindowState((state) => { + windowState.removeWindowByWindowId(state, 1) + }) + }) + + describe('removeWindowByIndex', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 1 }, + { windowId: 2 } + ])) + }) + + it('returns a new immutable state with the window at `index` removed if it exists', function () { + assert.deepEqual(windowState.removeWindowByIndex(this.appState, 1).get('windows').toJS(), [ {windowId: 1} ]) + }) + + it('returns the state unmodified if `index` is out of bounds', function () { + assert.deepEqual(windowState.removeWindowByIndex(this.appState, 2).toJS(), this.appState.toJS()) + }) + + it('throws an AssertionError if `index` < 0', function () { + assert.throws( + () => { + windowState.removeWindowByIndex(this.appState, -1) + }, + AssertionError + ) + }) + + it('throws an AssertionError if `index` is not a number', function () { + assert.throws( + () => { + windowState.removeWindowByIndex(this.appState, null) + }, + AssertionError + ) + assert.throws( + () => { + windowState.removeWindowByIndex(this.appState, 'a') + }, + AssertionError + ) + assert.doesNotThrow( + () => { + windowState.removeWindowByIndex(this.appState, '1') + }, + AssertionError + ) + }) + + shouldValidateWindowState((state) => { + windowState.removeWindowByIndex(state, 1) + }) + }) + + describe('removeWindow', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 1 }, + { windowId: 2 } + ])) + }) + + it('returns a new immutable state with the window removed by `windowId`', function () { + assert.deepEqual( + windowState.removeWindow(this.appState, { windowValue: { windowId: 2 } }).get('windows').toJS(), + [{ windowId: 1 }]) + }) + + shouldValidateAction((action) => { + windowState.removeWindow(defaultAppState, action) + }) + + shouldValidateWindowValue((windowValue) => { + windowState.removeWindow(defaultAppState, { windowValue }) + }) + + shouldValidateId((windowId) => { + windowState.removeWindow(defaultAppState, { windowValue: { windowId } }) + }) + + shouldValidateWindowState((state) => { + windowState.removeWindow(state, { windowValue: { windowId: 1 } }) + }) + }) + + describe('insertWindow', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 1 } + ])) + }) + + it('returns a new immutable state with the windowValue appended to the end of the list', function () { + assert.deepEqual( + windowState.insertWindow(this.appState, { windowValue: { windowId: 2 } }).get('windows').toJS(), + [{ windowId: 1 }, { windowId: 2 }]) + }) + + it('throws an AssertionError if there is already a tab with the windowId', function () { + assert.throws( + () => { + windowState.insertWindow(this.appState, { windowValue: { windowId: 1 } }) + }, + AssertionError + ) + }) + + shouldValidateAction((action) => { + windowState.insertWindow(defaultAppState, action) + }) + + shouldValidateWindowValue((windowValue) => { + windowState.insertWindow(defaultAppState, { windowValue }) + }) + + shouldValidateWindowState((state) => { + windowState.insertWindow(state, { windowValue: { windowId: 1 } }) + }) + }) + + describe('updateWindow', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { + windowId: 1, + focused: true, + myProp: 'test1' + }, + { + windowId: 2, + focused: false + } + ])) + }) + + it('returns a new immutable state with the windowValue updated if it already exists', function () { + assert.deepEqual( + windowState.updateWindow(this.appState, { windowValue: { windowId: 1, test: 'blue', myProp: 'test2' } }).get('windows').toJS(), [ + { + windowId: 1, + myProp: 'test2', + test: 'blue', + focused: true + }, + { + windowId: 2, + focused: false + } + ]) + }) + + it('returns a new immutable state with the windowValue replaced if it already exists and `replace` is true', function () { + assert.deepEqual( + windowState.updateWindow(this.appState, { replace: true, windowValue: { windowId: 1, test: 'blue', focused: false } }).get('windows').toJS(), [ + { + windowId: 1, + focused: false, + test: 'blue' + }, + { + windowId: 2, + focused: false + } + ]) + }) + + it('does not change other values in the appState', function () { + let state = windowState.updateWindow(this.appState, { windowValue: { windowId: 2, test: 'blue' } }) + assert.deepEqual(state.get('windows').find((win) => win.get('windowId') === 1).toJS(), { focused: true, myProp: 'test1', windowId: 1 }) + }) + + shouldValidateAction((action) => { + windowState.updateWindow(defaultAppState, action) + }) + + shouldValidateWindowValue((windowValue) => { + windowState.updateWindow(defaultAppState, { windowValue }) + }) + + shouldValidateWindowState((state) => { + windowState.updateWindow(state, { windowValue: { windowId: 1 } }) + }) + }) + + describe('getPersistentState', function () { + before(function () { + this.windows = Immutable.fromJS([{ + windowId: 1, + focused: true + }]) + this.windows = windowState.getPersistentState(this.windows) + }) + }) + + describe('maybeCreateWindow', function () { + before(function () { + this.appState = defaultAppState.set('windows', Immutable.fromJS([ + { windowId: 1 } + ])) + }) + + it('returns a new immutable state with the windowValue appended to the end of the list if it does not already exist', function () { + assert.deepEqual( + windowState.maybeCreateWindow(this.appState, { windowValue: { windowId: 2 } }).get('windows').toJS(), + [{ windowId: 1 }, { windowId: 2 }]) + }) + + it('returns a new immutable state with the windowValue updated if it already exists', function () { + assert.deepEqual( + windowState.maybeCreateWindow(this.appState, { windowValue: { windowId: 1, test: 'blue' } }).get('windows').toJS(), + [{ windowId: 1, test: 'blue' }]) + }) + + shouldValidateAction((action) => { + windowState.maybeCreateWindow(defaultAppState, action) + }) + + shouldValidateWindowValue((windowValue) => { + windowState.maybeCreateWindow(defaultAppState, { windowValue }) + }) + + shouldValidateWindowState((state) => { + windowState.maybeCreateWindow(state, { windowValue: { windowId: 1 } }) + }) + }) + + describe('getWindows', function () { + shouldValidateWindowState((state) => { + windowState.getWindows(state) + }) + }) +}) From 7373d06fa2f0183e856148b8e40a580876be803a Mon Sep 17 00:00:00 2001 From: bridiver Date: Tue, 22 Nov 2016 15:39:46 -0700 Subject: [PATCH 12/80] rebase fixes --- docs/appActions.md | 6 ++++++ js/constants/appConstants.js | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/appActions.md b/docs/appActions.md index dd27f86070f..8f52d4397e2 100644 --- a/docs/appActions.md +++ b/docs/appActions.md @@ -535,6 +535,12 @@ Notify the AppStore to provide default history values. +### dataURLCopied() + +Dispatch a message to copy data URL to clipboard + + + * * * diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index fba7531fe23..65979266f61 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -73,7 +73,6 @@ const AppConstants = { APP_POPULATE_HISTORY: _, APP_RENDER_URL_TO_PDF: _, APP_DATA_URL_COPIED: _, - APP_DEFAULT_BROWSER_CHECK_COMPLETE: _, APP_SHUTTING_DOWN: _ } From bac2c2288760cccec73d4ba110b9a24509f8c1ba Mon Sep 17 00:00:00 2001 From: bridiver Date: Tue, 22 Nov 2016 19:13:15 -0700 Subject: [PATCH 13/80] fix assert --- app/common/state/tabState.js | 26 +++++++++++++------------- app/common/state/windowState.js | 20 ++++++++++---------- js/state/contentSettings.js | 4 ---- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/app/common/state/tabState.js b/app/common/state/tabState.js index ce456625bcd..4dda1491509 100644 --- a/app/common/state/tabState.js +++ b/app/common/state/tabState.js @@ -6,43 +6,43 @@ const { makeImmutable, isMap, isList } = require('./immutableUtil') const assert = require('assert') const validateId = function (propName, id) { - assert(id, `${propName} cannot be null`) + assert.ok(id, `${propName} cannot be null`) id = parseInt(id) - assert(id === -1 || id > 0, `${propName} must be positive`) + assert.ok(id === -1 || id > 0, `${propName} must be positive`) return id } const validateTabs = function (tabs) { tabs = makeImmutable(tabs) - assert(isList(tabs), 'tabs must be an Immutable.List') + assert.ok(isList(tabs), 'tabs must be an Immutable.List') tabs.forEach((tab) => validateTabValue(tab)) return tabs } const validateState = function (state) { state = makeImmutable(state) - assert(isMap(state), 'state must be an Immutable.Map') - assert(isList(state.get('tabs')), 'state must contain an Immutable.List of tabs') + assert.ok(isMap(state), 'state must be an Immutable.Map') + assert.ok(isList(state.get('tabs')), 'state must contain an Immutable.List of tabs') return state } const validateWindowValue = function (windowValue) { windowValue = makeImmutable(windowValue) - assert(isMap(windowValue), 'windowValue must be an Immutable.Map') - assert(windowValue.get('windowId'), 'window must have a windowId') + assert.ok(isMap(windowValue), 'windowValue must be an Immutable.Map') + assert.ok(windowValue.get('windowId'), 'window must have a windowId') return windowValue } const validateTabValue = function (tabValue) { tabValue = makeImmutable(tabValue) - assert(isMap(tabValue), 'tabValue must be an Immutable.Map') - assert(tabValue.get('tabId'), 'tab must have a tabId') + assert.ok(isMap(tabValue), 'tabValue must be an Immutable.Map') + assert.ok(tabValue.get('tabId'), 'tab must have a tabId') return tabValue } const validateAction = function (action) { action = makeImmutable(action) - assert(isMap(action), 'action must be an Immutable.Map') + assert.ok(isMap(action), 'action must be an Immutable.Map') return action } @@ -74,7 +74,7 @@ const api = { removeTabByIndex: (state, index) => { index = parseInt(index) - assert(index >= 0, 'index must be positive') + assert.ok(index >= 0, 'index must be positive') state = validateState(state) return state.set('tabs', state.get('tabs').delete(index)) }, @@ -96,7 +96,7 @@ const api = { action = validateAction(action) state = validateState(state) let tabValue = validateTabValue(action.get('tabValue')) - assert(!api.getTab(state, tabValue), 'Tab already exists') + assert.ok(!api.getTab(state, tabValue), 'Tab already exists') return state.set('tabs', state.get('tabs').push(tabValue)) }, @@ -156,7 +156,7 @@ const api = { tabId = validateId('tabId', tabId) let currentTabId = currentTabValue.get('tabId') if (currentTabId) { - assert(tabId === currentTabId, 'Changing a tabId is not allowed') + assert.ok(tabId === currentTabId, 'Changing a tabId is not allowed') } } if (!action.get('replace')) { diff --git a/app/common/state/windowState.js b/app/common/state/windowState.js index 942995a88d2..7a3f947cf9d 100644 --- a/app/common/state/windowState.js +++ b/app/common/state/windowState.js @@ -7,29 +7,29 @@ const assert = require('assert') // TODO(bridiver) - make these generic validation functions const validateId = function (propName, id) { - assert(id, `${propName} cannot be null`) + assert.ok(id, `${propName} cannot be null`) id = parseInt(id) - assert(id > 0, `${propName} must be positive`) + assert.ok(id > 0, `${propName} must be positive`) return id } const validateState = function (state) { state = makeImmutable(state) - assert(isMap(state), 'state must be an Immutable.Map') - assert(isList(state.get('windows')), 'state must contain an Immutable.List of windows') + assert.ok(isMap(state), 'state must be an Immutable.Map') + assert.ok(isList(state.get('windows')), 'state must contain an Immutable.List of windows') return state } const validateWindowValue = function (windowValue) { windowValue = makeImmutable(windowValue) - assert(isMap(windowValue), 'windowValue must be an Immutable.Map') - assert(windowValue.get('windowId'), 'window must have a windowId') + assert.ok(isMap(windowValue), 'windowValue must be an Immutable.Map') + assert.ok(windowValue.get('windowId'), 'window must have a windowId') return windowValue } const validateAction = function (action) { action = makeImmutable(action) - assert(isMap(action), 'action must be an Immutable.Map') + assert.ok(isMap(action), 'action must be an Immutable.Map') return action } @@ -45,7 +45,7 @@ const api = { action = validateAction(action) state = validateState(state) let windowValue = validateWindowValue(action.get('windowValue')) - assert(!api.getWindow(state, windowValue), 'Window already exists') + assert.ok(!api.getWindow(state, windowValue), 'Window already exists') return state.set('windows', state.get('windows').push(windowValue)) }, @@ -93,7 +93,7 @@ const api = { removeWindowByIndex: (state, index) => { index = parseInt(index) - assert(index >= 0, 'index must be positive') + assert.ok(index >= 0, 'index must be positive') state = validateState(state) return state.set('windows', state.get('windows').delete(index)) }, @@ -124,7 +124,7 @@ const api = { windowId = validateId('windowId', windowId) let currentWindowId = currentWindowValue.get('windowId') if (currentWindowId) { - assert(windowId === currentWindowId, 'Changing a windowId is not allowed') + assert.ok(windowId === currentWindowId, 'Changing a windowId is not allowed') } } if (!action.get('replace')) { diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index 53e54e4ef16..9e7051b0119 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -14,7 +14,6 @@ const urlParse = require('url').parse const siteSettings = require('./siteSettings') const {setUserPref} = require('./userPrefs') const {getSetting} = require('../settings') -const {getIndexHTML} = require('../lib/appUrlUtil') // backward compatibility with appState siteSettings const parseSiteSettingsPattern = (pattern) => { @@ -177,9 +176,6 @@ const getContentSettingsFromSiteSettings = (appState, isPrivate = false) => { plugins: [{ setting: 'block', primaryPattern: '*' - }, { - setting: 'allow', - primaryPattern: getIndexHTML() }] } From 0f94bbb9c3c127d75e5a843c6a38bc8b0170db21 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 24 Nov 2016 20:35:28 -0700 Subject: [PATCH 14/80] wip fix for create tab --- app/browser/tabs.js | 53 +++++++-------------------------- app/browser/windows.js | 25 +++++++++++++++- js/actions/appActions.js | 4 +-- js/actions/windowActions.js | 18 +++++++++++ js/components/frame.js | 5 +--- js/constants/windowConstants.js | 4 ++- js/contextMenus.js | 6 ++-- js/stores/appStore.js | 3 -- js/stores/windowStore.js | 15 ++++++++++ 9 files changed, 78 insertions(+), 55 deletions(-) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index 846cd54f86f..689b4866e03 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -1,4 +1,4 @@ -const {app, extensions} = require('electron') +const {app, extensions, webContents} = require('electron') const appActions = require('../../js/actions/appActions') const { makeImmutable } = require('../common/state/immutableUtil') const tabState = require('../common/state/tabState') @@ -19,25 +19,6 @@ const getTabValue = function (tabId) { } } -const createInternal = (createProperties, tab, cb = null) => { - return new Promise((resolve, reject) => { - tab.once('did-attach', () => { - cb && cb(tab) - }) - tab.once('did-fail-provisional-load', (e) => { - resolve(tab, e) - }) - tab.once('did-fail-load', (e) => { - resolve(tab, e) - }) - tab.once('did-finish-load', (e) => { - resolve(tab, e) - }) - let openerTab = extensions.getOpener(createProperties) - extensions.openTab(tab, createProperties, openerTab) - }) -} - const updateTab = (tabId) => { let tabValue = getTabValue(tabId) if (tabValue) { @@ -69,6 +50,12 @@ const api = { updateTab(tabId) } }) + tab.on('new-window', (e, url, frameName, disposition, options = {}) => { + let userGesture = options.userGesture + if (userGesture === false) { + e.preventDefault() + } + }) tab.on('unresponsive', () => { console.log('unresponsive') }) @@ -137,20 +124,6 @@ const api = { } }, - newTab: (state, action) => { - action = makeImmutable(action) - let createProperties = action.get('createProperties') - createProperties = makeImmutable(createProperties).toJS() - let guest = extensions.registerGuest(createProperties) - createInternal(createProperties, guest).catch((err) => { - console.error(err) - // TODO(bridiver) - report the error - }) - let tab = guest.webContents - let tabValue = getTabValue(tab) - return tabState.maybeCreateTab(state, { tabValue }) - }, - closeTab: (state, action) => { action = makeImmutable(action) let tabId = action.get('tabId') @@ -166,14 +139,10 @@ const api = { }, create: (createProperties, cb = null) => { - try { - createProperties = makeImmutable(createProperties).toJS() - let guest = extensions.registerGuest(createProperties) - return createInternal(createProperties, guest, cb) - } catch (e) { - cb && cb() - return new Promise((resolve, reject) => { reject(e.message) }) - } + createProperties = makeImmutable(createProperties).toJS() + webContents.createTab(createProperties, (webContents) => { + cb && cb(webContents) + }) } } diff --git a/app/browser/windows.js b/app/browser/windows.js index 5fecfeb7e11..2448043c707 100644 --- a/app/browser/windows.js +++ b/app/browser/windows.js @@ -14,7 +14,7 @@ let currentWindows = {} const cleanupWindow = (windowId) => { delete currentWindows[windowId] setImmediate(() => { - appActions.windowClosed({ windowValue: windowId }) + appActions.windowClosed({ windowId }) }) } @@ -72,6 +72,29 @@ const api = { win.once('closed', () => { cleanupWindow(windowId) }) + win.webContents.on('new-window', (e, url, frameName, disposition, options = {}) => { + console.log(options) + let userGesture = options.userGesture + if (userGesture === false) { + e.preventDefault() + } else { + let frameProps = { + location: url, + delayedLoadUrl: options.delayedLoadUrl, + guestInstanceId: options.guestInstanceId, + windowId, + disposition + } + + let windowOpts = options.windowOptions || {} + windowOpts.disposition = disposition + if (disposition === 'new-window' || disposition === 'new-popup') { + appActions.newWindow(frameProps, windowOpts) + } else { + appActions.newTab(frameProps) + } + } + }) win.on('blur', () => { updateWindow(windowId) }) diff --git a/js/actions/appActions.js b/js/actions/appActions.js index 01158ac18c7..fc7ddee7b45 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -69,10 +69,10 @@ const appActions = { * A new tab has been requested * @param {Object} createProperties - windowId, url, active, openerTabId */ - newTab: function (createProperties) { + newTab: function (frameProps) { AppDispatcher.dispatch({ actionType: AppConstants.APP_NEW_TAB, - createProperties + frameProps }) }, diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js index bef2f8b0ea8..44dbb391afe 100644 --- a/js/actions/windowActions.js +++ b/js/actions/windowActions.js @@ -1192,6 +1192,24 @@ const windowActions = { className, props }) + }, + + autofillSelectionClicked: function (tabId, value, frontEndId, index) { + dispatch({ + actionType: WindowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED, + tabId, + value, + frontEndId, + index + }) + }, + + autofillPopupHidden: function (tabId, notify = false) { + dispatch({ + actionType: WindowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN, + tabId, + notify + }) } } diff --git a/js/components/frame.js b/js/components/frame.js index e4731f1d3b0..0d345511465 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -828,10 +828,7 @@ class Frame extends ImmutableComponent { contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) }) this.webview.addEventListener('hide-autofill-popup', (e) => { - let webContents = this.webview.getWebContents() - if (webContents && webContents.isFocused()) { - windowActions.setContextMenuDetail() - } + windowActions.autofillPopupHidden(this.props.tabId) }) this.webview.addEventListener('ipc-message', (e) => { let method = () => {} diff --git a/js/constants/windowConstants.js b/js/constants/windowConstants.js index dc18a685bbc..7cfe0bff730 100644 --- a/js/constants/windowConstants.js +++ b/js/constants/windowConstants.js @@ -85,7 +85,9 @@ const windowConstants = { WINDOW_ON_FOCUS_CHANGED: _, WINDOW_SET_MODAL_DIALOG_DETAIL: _, WINDOW_WIDEVINE_SITE_ACCESSED_WITHOUT_INSTALL: _, - WINDOW_WIDEVINE_PANEL_DETAIL_CHANGED: _ + WINDOW_WIDEVINE_PANEL_DETAIL_CHANGED: _, + WINDOW_AUTOFILL_SELECTION_CLICKED: _, + WINDOW_AUTOFILL_POPUP_HIDDEN: _ } module.exports = mapValuesByKeys(windowConstants) diff --git a/js/contextMenus.js b/js/contextMenus.js index 2a71638eb0a..e44bc026187 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -455,8 +455,7 @@ function autofillTemplateInit (suggestions, frame) { template.push({ label: value, click: (item, focusedWindow) => { - ipc.send('autofill-selection-clicked', frame.get('tabId'), value, frontendId, i) - windowActions.setContextMenuDetail() + windowActions.autofillSelectionClicked(frame.get('tabId'), value, frontendId, i) } }) } @@ -1370,7 +1369,10 @@ function onShowAutofillMenu (suggestions, boundingRect, frame) { x: (window.innerWidth - boundingRect.clientWidth), y: (window.innerHeight - boundingRect.clientHeight) } + const tabId = frame.get('tabId') windowActions.setContextMenuDetail(Immutable.fromJS({ + type: 'autofill', + tabId, left: offset.x + boundingRect.x, top: offset.y + (boundingRect.y + boundingRect.height) - downloadsBarOffset, template: menuTemplate diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 7cc209550ca..91d6afac752 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -805,9 +805,6 @@ const handleAppAction = (action) => { appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) appState = aboutNewTabState.setSites(appState, action) break - case AppConstants.APP_NEW_TAB: - appState = tabs.newTab(appState, action) - break case AppConstants.APP_TAB_CREATED: appState = tabState.maybeCreateTab(appState, action) break diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index 4e214b50449..a557996dd90 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -4,6 +4,7 @@ const AppDispatcher = require('../dispatcher/appDispatcher') const EventEmitter = require('events').EventEmitter +const AppConstants = require('../constants/appConstants') const WindowConstants = require('../constants/windowConstants') const config = require('../constants/config') const settings = require('../constants/settings') @@ -634,8 +635,19 @@ const doAction = (action) => { // Since the input values of bookmarks are bound, we need to notify the controls sync. windowStore.emitChanges() return + case WindowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED: + ipc.send('autofill-selection-clicked', action.tabId, action.value, action.frontendId, action.index) + windowState = windowState.delete('contextMenuDetail') + break + case WindowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN: case WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL: if (!action.detail) { + if (windowState.getIn('contextMenuDetail', 'type') === 'autofill' && + windowState.getIn('contextMenuDetail', 'tabId') === action.tabId) { + if (action.notify) { + ipc.send('autofill-popup-hidden', action.tabId) + } + } windowState = windowState.delete('contextMenuDetail') } else { windowState = windowState.set('contextMenuDetail', action.detail) @@ -896,6 +908,9 @@ const doAction = (action) => { // Since the input values of address are bound, we need to notify the controls sync. windowStore.emitChanges() break + case AppConstants.APP_NEW_TAB: + newFrame(action.frameProps, action.frameProps.get('disposition') === 'foreground-tab') + break default: } From 92b138a002fc5bc4f91c480995b899841cf68f89 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 24 Nov 2016 23:30:52 -0700 Subject: [PATCH 15/80] fix new tab page --- {img => app/extensions/brave/img}/newtab/bookmarks_btn.svg | 0 {img => app/extensions/brave/img}/newtab/history_btn.svg | 0 {img => app/extensions/brave/img}/newtab/settings_prefs_btn.svg | 0 {img => app/extensions/brave/img}/newtab/topsites_btn_1.svg | 0 {img => app/extensions/brave/img}/newtab/topsites_btn_2.svg | 0 {img => app/extensions/brave/img}/newtab/topsites_btn_3.svg | 0 js/about/newtab.js | 2 +- js/webtorrent/entry.js | 2 +- 8 files changed, 2 insertions(+), 2 deletions(-) rename {img => app/extensions/brave/img}/newtab/bookmarks_btn.svg (100%) rename {img => app/extensions/brave/img}/newtab/history_btn.svg (100%) rename {img => app/extensions/brave/img}/newtab/settings_prefs_btn.svg (100%) rename {img => app/extensions/brave/img}/newtab/topsites_btn_1.svg (100%) rename {img => app/extensions/brave/img}/newtab/topsites_btn_2.svg (100%) rename {img => app/extensions/brave/img}/newtab/topsites_btn_3.svg (100%) diff --git a/img/newtab/bookmarks_btn.svg b/app/extensions/brave/img/newtab/bookmarks_btn.svg similarity index 100% rename from img/newtab/bookmarks_btn.svg rename to app/extensions/brave/img/newtab/bookmarks_btn.svg diff --git a/img/newtab/history_btn.svg b/app/extensions/brave/img/newtab/history_btn.svg similarity index 100% rename from img/newtab/history_btn.svg rename to app/extensions/brave/img/newtab/history_btn.svg diff --git a/img/newtab/settings_prefs_btn.svg b/app/extensions/brave/img/newtab/settings_prefs_btn.svg similarity index 100% rename from img/newtab/settings_prefs_btn.svg rename to app/extensions/brave/img/newtab/settings_prefs_btn.svg diff --git a/img/newtab/topsites_btn_1.svg b/app/extensions/brave/img/newtab/topsites_btn_1.svg similarity index 100% rename from img/newtab/topsites_btn_1.svg rename to app/extensions/brave/img/newtab/topsites_btn_1.svg diff --git a/img/newtab/topsites_btn_2.svg b/app/extensions/brave/img/newtab/topsites_btn_2.svg similarity index 100% rename from img/newtab/topsites_btn_2.svg rename to app/extensions/brave/img/newtab/topsites_btn_2.svg diff --git a/img/newtab/topsites_btn_3.svg b/app/extensions/brave/img/newtab/topsites_btn_3.svg similarity index 100% rename from img/newtab/topsites_btn_3.svg rename to app/extensions/brave/img/newtab/topsites_btn_3.svg diff --git a/js/about/newtab.js b/js/about/newtab.js index af74f85eb3e..ea1f8a9fc89 100644 --- a/js/about/newtab.js +++ b/js/about/newtab.js @@ -20,7 +20,7 @@ const siteTags = require('../constants/siteTags') const config = require('../constants/config') const backgrounds = require('../data/backgrounds') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer require('../../less/about/newtab.less') require('../../node_modules/font-awesome/css/font-awesome.css') diff --git a/js/webtorrent/entry.js b/js/webtorrent/entry.js index cfe7e179362..05690b52632 100644 --- a/js/webtorrent/entry.js +++ b/js/webtorrent/entry.js @@ -1,6 +1,6 @@ /* global Blob, URL */ -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer const messages = require('../constants/messages') const parseTorrent = require('parse-torrent') const React = require('react') From b6d6208c58ad3a09af281f3e7ff329ec3d082ef4 Mon Sep 17 00:00:00 2001 From: bridiver Date: Fri, 25 Nov 2016 01:33:01 -0700 Subject: [PATCH 16/80] fix test urls --- test/lib/brave.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/lib/brave.js b/test/lib/brave.js index 244ba0091e4..1382abccb62 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -5,7 +5,7 @@ require('./coMocha') const path = require('path') const fs = require('fs') const os = require('os') -const {getTargetAboutUrl, isSourceAboutUrl} = require('../../js/lib/appUrlUtil') +const {getTargetAboutUrl, isSourceAboutUrl, getBraveExtIndexHTML} = require('../../js/lib/appUrlUtil') var chaiAsPromised = require('chai-as-promised') chai.should() @@ -83,7 +83,7 @@ var exports = { defaultTimeout: 10000, - browserWindowUrl: 'file://' + path.resolve(__dirname, '..', '..') + '/app/extensions/brave/index.html', + browserWindowUrl: getBraveExtIndexHTML(), newTabUrl: 'chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/about-newtab.html', fixtureUrl: function (filename) { return 'file://' + path.resolve(__dirname, '..', 'fixtures', filename) @@ -200,7 +200,7 @@ var exports = { // ignore extension urls unless they are "about" pages if (!(urls[i].startsWith('chrome-extension') && !urls[i].match(/about-.*\.html(#.*)?$/)) && // ignore window urls - !urls[i].startsWith('file:')) { + !urls[i].startsWith('chrome://brave')) { newHandles.push(handles[i]) } } From 25ef8a6b2dc1e98b7a1bb8dfae44cffb128aa5ab Mon Sep 17 00:00:00 2001 From: bridiver Date: Sun, 27 Nov 2016 23:11:10 -0700 Subject: [PATCH 17/80] update npmrc for brave headers --- .npmrc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.npmrc b/.npmrc index 8d06ade0567..76a0b285a95 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,5 @@ -#runtime = electron -#target = 1.4.0 +runtime = electron +target = 2.0.0 target_arch = x64 brave_electron_version = 2.0.0 -#disturl = https://atom.io/download/atom-shell +disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell From 1ef27daba888c43be221d7bd3a4cdcce56281fa8 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 28 Nov 2016 11:07:28 -0500 Subject: [PATCH 18/80] Use electron-prebuilt 2.0.0 Auditors: @bridiver --- package.json | 2 +- tools/cibuild.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 38b7fb3c3f2..f75be730a3a 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "aphrodite": "^1.0.0", "async": "^2.0.1", "electron-localshortcut": "^0.6.0", - "electron-prebuilt": "brave/electron-prebuilt", + "electron-prebuilt": "brave/electron-prebuilt#2.0.0", "electron-squirrel-startup": "brave/electron-squirrel-startup", "file-loader": "^0.8.5", "font-awesome": "^4.5.0", diff --git a/tools/cibuild.py b/tools/cibuild.py index 38c166667cd..77115e3d0f9 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -6,7 +6,7 @@ import os.path BRAVE_ELECTRON = '2.0.0' -UPSTREAM_ELECTRON = '1.4.0' +UPSTREAM_ELECTRON = '2.0.0' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) TARGET_ARCH= os.environ['TARGET_ARCH'] if os.environ.has_key('TARGET_ARCH') else 'x64' os.environ['npm_config_arch'] = TARGET_ARCH From d55d53b040c8b1ea80ef1c24bcef854c12b18775 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 28 Nov 2016 11:27:58 -0500 Subject: [PATCH 19/80] Use brave download location Auditors: @bridiver --- tools/cibuild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cibuild.py b/tools/cibuild.py index 77115e3d0f9..4f1c13329a1 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -27,7 +27,7 @@ def write_npmrc(): 'target = %s\n' \ 'target_arch = %s\n' \ 'brave_electron_version = %s\n' \ - 'disturl = https://atom.io/download/atom-shell\n' % (UPSTREAM_ELECTRON, TARGET_ARCH, BRAVE_ELECTRON) + 'disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell\n' % (UPSTREAM_ELECTRON, TARGET_ARCH, BRAVE_ELECTRON) f = open('.npmrc','wb') f.write(data) f.close() From 9bab7dcf59af690f195fbc2df0601bd715f192c8 Mon Sep 17 00:00:00 2001 From: bridiver Date: Mon, 28 Nov 2016 10:15:07 -0700 Subject: [PATCH 20/80] fix img paths for extension --- .npmrc | 2 +- less/about/newtab.less | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.npmrc b/.npmrc index 76a0b285a95..474ce5a9258 100644 --- a/.npmrc +++ b/.npmrc @@ -2,4 +2,4 @@ runtime = electron target = 2.0.0 target_arch = x64 brave_electron_version = 2.0.0 -disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell +disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist diff --git a/less/about/newtab.less b/less/about/newtab.less index 6180c87c362..1e123daca9d 100644 --- a/less/about/newtab.less +++ b/less/about/newtab.less @@ -177,13 +177,13 @@ ul { cursor: default; &.hasThreeRows { - background: url('../../img/newtab/topsites_btn_3.svg'); + background: url('/img/newtab/topsites_btn_3.svg'); } &.hasTwoRows { - background: url('../../img/newtab/topsites_btn_2.svg'); + background: url('/img/newtab/topsites_btn_2.svg'); } &.hasOneRow { - background: url('../../img/newtab/topsites_btn_1.svg'); + background: url('/img/newtab/topsites_btn_1.svg'); } } @@ -399,13 +399,13 @@ ul { } &.settingsIcon { - -webkit-mask-image: url('../../img/newtab/settings_prefs_btn.svg'); + -webkit-mask-image: url('/img/newtab/settings_prefs_btn.svg'); } &.bookmarksIcon { - -webkit-mask-image: url('../../img/newtab/bookmarks_btn.svg'); + -webkit-mask-image: url('/img/newtab/bookmarks_btn.svg'); } &.historyIcon { - -webkit-mask-image: url('../../img/newtab/history_btn.svg'); + -webkit-mask-image: url('/img/newtab/history_btn.svg'); } } } From 5ed7bf7696589323874d24151e4158c037619f7e Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 28 Nov 2016 12:26:05 -0500 Subject: [PATCH 21/80] Append dist dir name Auditors: @bridiver --- tools/cibuild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cibuild.py b/tools/cibuild.py index 4f1c13329a1..12951e416d5 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -27,7 +27,7 @@ def write_npmrc(): 'target = %s\n' \ 'target_arch = %s\n' \ 'brave_electron_version = %s\n' \ - 'disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell\n' % (UPSTREAM_ELECTRON, TARGET_ARCH, BRAVE_ELECTRON) + 'disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist\n' % (UPSTREAM_ELECTRON, TARGET_ARCH, BRAVE_ELECTRON) f = open('.npmrc','wb') f.write(data) f.close() From edcf55e2f6aa1e05a9a89b1a35bcea15f21f12c9 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 28 Nov 2016 12:38:18 -0500 Subject: [PATCH 22/80] 0.13.0 --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ba85cdd769..524d51342d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [0.13.0](https://github.com/brave/browser-laptop/releases/v0.13.0dev) +- (TODO) + ## [0.12.15](https://github.com/brave/browser-laptop/releases/v0.12.15dev) - Added Yandex as a new search engine. ([#2703](https://github.com/brave/browser-laptop/issues/2703)) - Added Qwant as a new search engine. ([#2701](https://github.com/brave/browser-laptop/issues/2701)) diff --git a/package.json b/package.json index f75be730a3a..fd5a50676a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "brave", - "version": "0.12.14", + "version": "0.13.0", "description": "Brave laptop and desktop browser", "main": "./app/index.js", "config": { From 86212b64e747808ec46bf532a149ac47e811320d Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 28 Nov 2016 13:07:37 -0500 Subject: [PATCH 23/80] Fix about page Auditors: @bridiver --- js/about/brave.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/about/brave.js b/js/about/brave.js index 71ecba9286e..d2f0fefc324 100644 --- a/js/about/brave.js +++ b/js/about/brave.js @@ -8,7 +8,7 @@ const messages = require('../constants/messages') const SortableTable = require('../components/sortableTable') const aboutActions = require('./aboutActions') -const ipc = window.chrome.ipc +const ipc = window.chrome.ipcRenderer require('../../less/about/history.less') require('../../node_modules/font-awesome/css/font-awesome.css') From 89609a9a966290aad58de4a78de6a8c10b5c93c5 Mon Sep 17 00:00:00 2001 From: bridiver Date: Mon, 28 Nov 2016 16:19:36 -0700 Subject: [PATCH 24/80] don't send binary data over ipc auditors: @bbondy --- app/filtering.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/filtering.js b/app/filtering.js index b1b5df43557..e6ada02dee5 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -138,7 +138,10 @@ function registerForBeforeRequest (session, partition) { } BrowserWindow.getAllWindows().forEach((wnd) => - wnd.webContents.send(message, parentResourceName, details)) + wnd.webContents.send(message, parentResourceName, { + tabId: details.tabId, + url: details.url + })) if (details.resourceType === 'image') { cb({ redirectURL: transparent1pxGif }) } else { @@ -159,7 +162,10 @@ function registerForBeforeRequest (session, partition) { appActions.addResourceCount(results.resourceName, 1) } BrowserWindow.getAllWindows().forEach((wnd) => - wnd.webContents.send(messages.HTTPSE_RULE_APPLIED, results.ruleset, details)) + wnd.webContents.send(messages.HTTPSE_RULE_APPLIED, results.ruleset, { + tabId: details.tabId, + url: details.url + })) } cb({redirectURL: results.redirectURL}) return From bda60d6712fae75037494dcb69e6873145e006b9 Mon Sep 17 00:00:00 2001 From: bridiver Date: Mon, 28 Nov 2016 22:46:16 -0700 Subject: [PATCH 25/80] fix flash checks for chromium 54 auditors: @bbondy @diractdeltas --- app/browser/basicAuth.js | 6 +- app/browser/webtorrent.js | 28 ++- app/browser/windows.js | 1 - .../brave/content/scripts/flashListener.js | 24 -- app/filtering.js | 111 ++++---- app/index.js | 21 -- js/about/preferences.js | 9 +- js/components/frame.js | 161 +----------- js/constants/appConfig.js | 13 +- js/constants/messages.js | 2 - js/constants/settings.js | 1 + js/flash.js | 237 ++++++++++++++++-- js/lib/urlutil.js | 28 --- js/state/siteSettings.js | 2 +- js/stores/appStore.js | 15 +- 15 files changed, 340 insertions(+), 319 deletions(-) diff --git a/app/browser/basicAuth.js b/app/browser/basicAuth.js index b6a25e5ac98..938e1cc0ac3 100644 --- a/app/browser/basicAuth.js +++ b/app/browser/basicAuth.js @@ -1,4 +1,4 @@ -const {app} = require('electron') +const { app } = require('electron') const appActions = require('../../js/actions/appActions') const basicAuthState = require('../common/state/basicAuthState') const { makeImmutable } = require('../common/state/immutableUtil') @@ -11,7 +11,7 @@ const cleanupAuthCallback = (tabId) => { } const basicAuth = { - init: () => { + init: (state, action) => { app.on('login', (e, webContents, request, authInfo, cb) => { e.preventDefault() let tabId = webContents.getId() @@ -29,6 +29,8 @@ const basicAuth = { }) }) }) + + return state }, setLoginResponseDetail: (state, action) => { diff --git a/app/browser/webtorrent.js b/app/browser/webtorrent.js index c3200142055..395e166865c 100644 --- a/app/browser/webtorrent.js +++ b/app/browser/webtorrent.js @@ -1,8 +1,8 @@ const electron = require('electron') const ipc = electron.ipcMain const messages = require('../../js/constants/messages') - -module.exports = {init} +const Filtering = require('../filtering') +const { getTargetMagnetUrl } = require('../../js/lib/appUrlUtil') // Set to see communication between WebTorrent and torrent viewer tabs const DEBUG_IPC = false @@ -13,6 +13,25 @@ if (DEBUG_IPC) console.log('WebTorrent IPC debugging enabled') let server = null let channels = {} +function handleMangetUrl (details, isPrivate) { + const result = { + resourceName: module.exports.resourceName, + redirectURL: null, + cancel: false + } + + if (details.resourceType !== 'mainFrame') { + return result + } + + const magnetUrl = getTargetMagnetUrl(details.url) + if (magnetUrl) { + result.redirectUrl = magnetUrl + } + + return result +} + // Receive messages via the window process, ultimately from the UI in a process function init () { if (DEBUG_IPC) console.log('WebTorrent IPC init') @@ -42,3 +61,8 @@ function send (msg) { } channel.send(messages.TORRENT_MESSAGE, msg) } + +module.exports = { + init, + resourceName: 'webtorrent' +} diff --git a/app/browser/windows.js b/app/browser/windows.js index 2448043c707..cd61f18e5f0 100644 --- a/app/browser/windows.js +++ b/app/browser/windows.js @@ -73,7 +73,6 @@ const api = { cleanupWindow(windowId) }) win.webContents.on('new-window', (e, url, frameName, disposition, options = {}) => { - console.log(options) let userGesture = options.userGesture if (userGesture === false) { e.preventDefault() diff --git a/app/extensions/brave/content/scripts/flashListener.js b/app/extensions/brave/content/scripts/flashListener.js index bd6c4f0a4b9..d80ca59bcd6 100644 --- a/app/extensions/brave/content/scripts/flashListener.js +++ b/app/extensions/brave/content/scripts/flashListener.js @@ -12,12 +12,6 @@ function isAdobeLink (href) { return adobeRegex.test(href) } -function showFlashNotification (origin, e) { - chrome.ipcRenderer.sendToHost('show-flash-notification', origin) - e.preventDefault() - e.stopPropagation() -} - /** * Whether a src is a .swf file. * If so, returns the origin of the file. Otherwise returns false. @@ -137,24 +131,6 @@ function insertFlashPlaceholders (elem = document.documentElement) { if (chrome.contentSettings.flashActive != 'allow' || chrome.contentSettings.flashEnabled != 'allow') { // Open flash links in the same tab so we can intercept them correctly - (function () { - function replaceAdobeLinks () { - Array.from(document.querySelectorAll('a')).forEach((elem) => { - const href = elem.getAttribute('href') - if (isAdobeLink(href)) { - elem.onclick = showFlashNotification.bind(null, window.location.origin) - } - }) - } - replaceAdobeLinks() - let interval = setInterval(replaceAdobeLinks, 3000) - document.addEventListener('visibilitychange', () => { - clearInterval(interval) - if (document.visibilityState !== 'hidden') { - interval = setInterval(replaceAdobeLinks, 3000) - } - }) - })() insertFlashPlaceholders() let interval = setInterval(insertFlashPlaceholders, 3000) document.addEventListener('visibilitychange', () => { diff --git a/app/filtering.js b/app/filtering.js index e6ada02dee5..ac0077df761 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -9,7 +9,6 @@ const electron = require('electron') const session = electron.session const BrowserWindow = electron.BrowserWindow const webContents = electron.webContents -const appStore = require('../js/stores/appStore') const appActions = require('../js/actions/appActions') const appConfig = require('../js/constants/appConfig') const downloadStates = require('../js/constants/downloadStates') @@ -33,6 +32,8 @@ const path = require('path') const getOrigin = require('../js/state/siteUtil').getOrigin const {adBlockResourceName} = require('./adBlock') +let appStore = null + const beforeSendHeadersFilteringFns = [] const beforeRequestFilteringFns = [] const beforeRedirectFilteringFns = [] @@ -571,47 +572,62 @@ function shouldIgnoreUrl (url) { return true } -module.exports.init = () => { - ['default'].forEach((partition) => { - initForPartition(partition) - }) - ipcMain.on(messages.INITIALIZE_PARTITION, (e, partition) => { - if (initializedPartitions[partition]) { +module.exports.init = (state, action, store) => { + appStore = store + + setImmediate(() => { + ['default'].forEach((partition) => { + initForPartition(partition) + }) + ipcMain.on(messages.INITIALIZE_PARTITION, (e, partition) => { + if (initializedPartitions[partition]) { + e.returnValue = true + return e.returnValue + } + initForPartition(partition) e.returnValue = true return e.returnValue - } - initForPartition(partition) - e.returnValue = true - return e.returnValue - }) - ipcMain.on(messages.DOWNLOAD_ACTION, (e, downloadId, action) => { - const item = downloadMap[downloadId] - switch (action) { - case downloadActions.CANCEL: - updateDownloadState(downloadId, item, downloadStates.CANCELLED) - if (item) { - item.cancel() - } - break - case downloadActions.PAUSE: - if (item) { - item.pause() - } - updateDownloadState(downloadId, item, downloadStates.PAUSED) - break - case downloadActions.RESUME: - if (item) { - item.resume() - } - updateDownloadState(downloadId, item, downloadStates.IN_PROGRESS) - break - } - }) - ipcMain.on(messages.NOTIFICATION_RESPONSE, (e, message, buttonIndex, persist) => { - if (permissionCallbacks[message]) { - permissionCallbacks[message](buttonIndex, persist) - } + }) + ipcMain.on(messages.DOWNLOAD_ACTION, (e, downloadId, action) => { + const item = downloadMap[downloadId] + switch (action) { + case downloadActions.CANCEL: + updateDownloadState(downloadId, item, downloadStates.CANCELLED) + if (item) { + item.cancel() + } + break + case downloadActions.PAUSE: + if (item) { + item.pause() + } + updateDownloadState(downloadId, item, downloadStates.PAUSED) + break + case downloadActions.RESUME: + if (item) { + item.resume() + } + updateDownloadState(downloadId, item, downloadStates.IN_PROGRESS) + break + } + }) + ipcMain.on(messages.NOTIFICATION_RESPONSE, (e, message, buttonIndex, persist) => { + if (permissionCallbacks[message]) { + permissionCallbacks[message](buttonIndex, persist) + } + }) }) + + return state +} + +module.exports.getSiteSettings = (url, isPrivate) => { + const appState = appStore.getState() + let settings = appState.get('siteSettings') + if (isPrivate) { + settings = settings.mergeDeep(appState.get('temporarySiteSettings')) + } + return siteSettings.getSiteSettingsForURL(settings, url) } module.exports.isResourceEnabled = (resourceName, url, isPrivate) => { @@ -619,6 +635,13 @@ module.exports.isResourceEnabled = (resourceName, url, isPrivate) => { return true } + // TODO(bridiver) - need to clean up the rest of this so web can + // remove this because it duplicates checks made in siteSettings + // and not all resources are controlled by shields up/down + if (resourceName === 'flash' || resourceName === 'webtorrent') { + return true + } + const appState = appStore.getState() const settings = siteSettings.getSiteSettingsForURL(appState.get('siteSettings'), url) const tempSettings = siteSettings.getSiteSettingsForURL(appState.get('temporarySiteSettings'), url) @@ -702,13 +725,9 @@ module.exports.getMainFrameUrl = (details) => { if (details.resourceType === 'mainFrame') { return details.url } - const tabId = details.tabId - const wc = webContents.getAllWebContents() - if (wc && tabId) { - const content = wc.find((item) => item.getId() === tabId) - if (content) { - return content.getURL() - } + const tab = webContents.fromTabID(details.tabId) + if (tab) { + return tab.getURL() } return null } diff --git a/app/index.js b/app/index.js index c9123e41cdc..3d1e92f7044 100644 --- a/app/index.js +++ b/app/index.js @@ -58,7 +58,6 @@ const AppStore = require('../js/stores/appStore') const PackageLoader = require('./package-loader') const Autofill = require('./autofill') const Extensions = require('./extensions') -const Filtering = require('./filtering') const TrackingProtection = require('./trackingProtection') const AdBlock = require('./adBlock') const AdInsertion = require('./browser/ads/adInsertion') @@ -73,12 +72,10 @@ const siteSettings = require('../js/state/siteSettings') const spellCheck = require('./spellCheck') const locale = require('./locale') const ledger = require('./ledger') -const flash = require('../js/flash') const contentSettings = require('../js/state/contentSettings') const privacy = require('../js/state/privacy') const async = require('async') const settings = require('../js/constants/settings') -const webtorrent = require('./browser/webtorrent') // temporary fix for #4517, #4518 and #4472 app.commandLine.appendSwitch('enable-use-zoom-for-dsf', 'false') @@ -240,8 +237,6 @@ const initiateSessionStateSave = (beforeQuit) => { let loadAppStatePromise = SessionStore.loadAppState() -let flashInitialized = false - // Some settings must be set right away on startup, those settings should be handled here. loadAppStatePromise.then((initialState) => { const {HARDWARE_ACCELERATION_ENABLED, SMOOTH_SCROLL_ENABLED, SEND_CRASH_REPORTS} = require('../js/constants/settings') @@ -257,13 +252,6 @@ loadAppStatePromise.then((initialState) => { if (initialState.settings[SMOOTH_SCROLL_ENABLED] === false) { app.commandLine.appendSwitch('disable-smooth-scrolling') } - if (initialState.flash && initialState.flash.enabled === true) { - if (flash.init()) { - // Flash was initialized successfully - flashInitialized = true - return - } - } }) const notifyCertError = (webContents, url, error, cert) => { @@ -410,7 +398,6 @@ app.on('ready', () => { // For tests we always want to load default app state const loadedPerWindowState = initialState.perWindowState delete initialState.perWindowState - initialState.flashInitialized = flashInitialized appActions.setState(Immutable.fromJS(initialState)) Menu.init(initialState, null) return loadedPerWindowState @@ -419,14 +406,12 @@ app.on('ready', () => { privacy.init() Autofill.init() Extensions.init() - Filtering.init() SiteHacks.init() spellCheck.init() HttpsEverywhere.init() TrackingProtection.init() AdBlock.init() AdInsertion.init() - webtorrent.init() if (!loadedPerWindowState || loadedPerWindowState.length === 0) { if (!CmdLine.newWindowURL()) { @@ -498,12 +483,6 @@ app.on('ready', () => { electron.clipboard.writeText(text) }) - ipcMain.on(messages.CHECK_FLASH_INSTALLED, (e) => { - flash.checkFlashInstalled((installed) => { - e.sender.send(messages.FLASH_UPDATED, installed) - }) - }) - ipcMain.on(messages.OPEN_DOWNLOAD_PATH, (e, download) => { downloadActions.openDownloadPath(Immutable.fromJS(download)) }) diff --git a/js/about/preferences.js b/js/about/preferences.js index 19be7a12cda..c9c2841a5d8 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -1552,6 +1552,7 @@ class SecurityTab extends ImmutableComponent { const isLinux = navigator.appVersion.indexOf('Linux') !== -1 + const flashInstalled = getSetting(settings.FLASH_INSTALLED, this.props.settings) return
@@ -1608,8 +1609,9 @@ class SecurityTab extends ImmutableComponent {
- -
+ + + { isDarwin || isWindows ?
@@ -1803,9 +1805,6 @@ class AboutPreferences extends React.Component { ipc.on(messages.BRAVERY_DEFAULTS_UPDATED, (e, braveryDefaults) => { this.setState({ braveryDefaults: Immutable.fromJS(braveryDefaults || {}) }) }) - ipc.on(messages.FLASH_UPDATED, (e, flashInstalled) => { - this.setState({ flashInstalled }) - }) ipc.on(messages.LANGUAGE, (e, {langCode, languageCodes}) => { this.setState({ languageCodes }) }) diff --git a/js/components/frame.js b/js/components/frame.js index 0d345511465..3c4d65e6c97 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -23,12 +23,11 @@ const debounce = require('../lib/debounce') const getSetting = require('../settings').getSetting const config = require('../constants/config') const settings = require('../constants/settings') -const {aboutUrls, isSourceMagnetUrl, getTargetMagnetUrl, isSourceAboutUrl, isTargetAboutUrl, getTargetAboutUrl, getBaseUrl, isIntermediateAboutPage} = require('../lib/appUrlUtil') +const {aboutUrls, getTargetMagnetUrl, isSourceMagnetUrl, isSourceAboutUrl, isTargetAboutUrl, getTargetAboutUrl, getBaseUrl, isIntermediateAboutPage} = require('../lib/appUrlUtil') const {isFrameError} = require('../../app/common/lib/httpUtil') const locale = require('../l10n') const appConfig = require('../constants/appConfig') const {getSiteSettingsForHostPattern} = require('../state/siteSettings') -// const flash = require('../flash') const currentWindow = require('../../app/renderer/currentWindow') const windowStore = require('../stores/windowStore') const appStoreRenderer = require('../stores/appStoreRenderer') @@ -204,26 +203,6 @@ class Frame extends ImmutableComponent { ? false : activeSiteSettings.get('runInsecureContent') } - allowRunningFlashPlugin (url) { - if (!this.props.flashInitialized) { - return false - } - const origin = url ? siteUtil.getOrigin(url) : this.origin - if (!origin) { - return false - } - // Check for at least one CtP allowed on this origin - if (!this.props.allSiteSettings) { - return false - } - const activeSiteSettings = getSiteSettingsForHostPattern(this.props.allSiteSettings, - origin) - if (activeSiteSettings && typeof activeSiteSettings.get('flash') === 'number') { - return true - } - return false - } - allowRunningWidevinePlugin (url) { if (!this.props.widevine || !this.props.widevine.get('enabled')) { return false @@ -333,9 +312,6 @@ class Frame extends ImmutableComponent { if (hack && hack.userAgent) { this.webview.setUserAgentOverride(hack.userAgent) } - if (this.allowRunningFlashPlugin() || this.allowRunningWidevinePlugin()) { - this.webview.allowRunningPlugins = true - } if (!guestInstanceId || newSrc !== 'about:blank') { let webviewSrc @@ -583,88 +559,6 @@ class Frame extends ImmutableComponent { } } - /** - * Shows a Flash CtP notification if Flash is installed and enabled. - * If not enabled, alert user that Flash is installed. - * @param {string} origin - frame origin that is requesting to run flash. - * can either be main frame or subframe. - * @param {function=} noFlashCallback - Optional callback to run if Flash is not - * installed - * @param {function=} flashCallback - Optional callback to run if Flash is - * accepted - */ - showFlashNotification (origin, noFlashCallback, flashCallback) { - if (!origin || !UrlUtil.shouldInterceptFlash(origin)) { - noFlashCallback() - return - } - - // Generate a random string that is unlikely to collide. Not - // cryptographically random. - const nonce = Math.random().toString() - if (this.props.flashInitialized) { - const message = locale.translation('allowFlashPlayer').replace(/{{\s*origin\s*}}/, this.origin) - // Show Flash notification bar - appActions.showMessageBox({ - buttons: [ - {text: locale.translation('deny')}, - {text: locale.translation('allow')} - ], - message, - frameOrigin: this.origin, - options: { - nonce, - persist: true - } - }) - this.notificationCallbacks[message] = (buttonIndex, persist) => { - if (buttonIndex === 1) { - if (persist) { - appActions.changeSiteSetting(this.origin, 'flash', Date.now() + 7 * 24 * 1000 * 3600) - } else { - appActions.changeSiteSetting(this.origin, 'flash', 1) - } - if (flashCallback) { - flashCallback() - } - } else { - if (persist) { - appActions.changeSiteSetting(this.origin, 'flash', false) - } - } - appActions.hideMessageBox(message) - } - } else { - // flash.checkFlashInstalled((installed) => { - // if (installed) { - // let message = locale.translation('flashInstalled') - // appActions.showMessageBox({ - // buttons: [ - // {text: locale.translation('goToPrefs')}, - // {text: locale.translation('goToAdobe')} - // ], - // message: message, - // options: {nonce} - // }) - // this.notificationCallbacks[message] = (buttonIndex) => { - // appActions.hideMessageBox(message) - // const location = buttonIndex === 0 ? 'about:preferences#security' : appConfig.flash.installUrl - // windowActions.newFrame({ location }, true) - // } - // } else if (noFlashCallback) { - // noFlashCallback() - // } - // }) - } - - ipc.once(messages.NOTIFICATION_RESPONSE + nonce, (e, msg, buttonIndex, persist) => { - const cb = this.notificationCallbacks[msg] - if (cb) { - cb(buttonIndex, persist) - } - }) - } - /** * Shows a Widevine CtP notification if Widevine is installed and enabled. * If not enabled, alert user that Widevine is installed. @@ -860,11 +754,6 @@ class Frame extends ImmutableComponent { case messages.GO_FORWARD: method = () => this.webview.goForward() break - case messages.SHOW_FLASH_NOTIFICATION: - method = (origin) => this.showFlashNotification(origin, () => { - windowActions.loadUrl(this.frame, appConfig.flash.installUrl) - }) - break case messages.RELOAD: method = () => { this.reloadCounter[this.props.location] = this.reloadCounter[this.props.location] || 0 @@ -890,50 +779,8 @@ class Frame extends ImmutableComponent { method.apply(this, e.args) }) - const interceptFlash = (stopCurrentLoad, adobeUrl, redirectUrl) => { - if (!this.origin) { - return - } - const activeSiteSettings = getSiteSettingsForHostPattern(this.props.allSiteSettings, - this.origin) - if (activeSiteSettings && activeSiteSettings.get('flash') === false) { - return - } - - if (stopCurrentLoad) { - this.webview.stop() - } - - this.showFlashNotification(this.origin, () => { - if (stopCurrentLoad && adobeUrl) { - windowActions.loadUrl(this.frame, adobeUrl) - } - }, () => { - if (redirectUrl) { - windowActions.loadUrl(this.frame, redirectUrl) - } - }) - } - const loadStart = (e) => { - // We have two kinds of special URLs: magnet links and about pages - // When the user clicks on a magnet link, navigate to the corresponding local URL - // (The address bar will still show the magnet URL. See appUrlUtil.getSourceMagnetUrl.) - if (isTorrentViewerURL(e.url)) { - var targetURL = getTargetMagnetUrl(e.url) - // Return right away. loadStart will be called again with targetURL - return windowActions.loadUrl(this.frame, targetURL) - } - - const parsedUrl = urlParse(e.url) - - // Instead of telling person to install Flash, ask them if they want to - // run Flash if it's installed. if (e.isMainFrame && !e.isErrorPage && !e.isFrameSrcDoc) { - if (UrlUtil.isFlashInstallUrl(e.url) && - UrlUtil.shouldInterceptFlash(this.props.provisionalLocation)) { - interceptFlash(true, e.url) - } windowActions.onWebviewLoadStart(this.frame, e.url) // Clear security state windowActions.setBlockedRunInsecureContent(this.frame) @@ -942,6 +789,7 @@ class Frame extends ImmutableComponent { runInsecureContent: false }) } + const parsedUrl = urlParse(e.url) const hack = siteHacks[parsedUrl.hostname] if (hack && hack.pageLoadStartScript) { this.webview.executeJavaScript(hack.pageLoadStartScript) @@ -979,11 +827,6 @@ class Frame extends ImmutableComponent { if (hack && hack.pageLoadEndScript) { this.webview.executeJavaScript(hack.pageLoadEndScript) } - if (hack && hack.enableFlashCTP && - !this.webview.allowRunningPlugins && this.props.flashInitialized) { - // Fix #3011 - interceptFlash(false, undefined, hack.redirectURL) - } if (this.props.location.startsWith(pdfjsOrigin)) { let displayLocation = UrlUtil.getLocationIfPDF(this.props.location) windowActions.setSecurityState(this.frame, { diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js index 3952c4e345e..3b60f8269ad 100644 --- a/js/constants/appConfig.js +++ b/js/constants/appConfig.js @@ -22,7 +22,9 @@ module.exports = { NOSCRIPT: 'noScript', FLASH: 'flash', WIDEVINE: 'widevine', - COOKIEBLOCK: 'cookieblock' // block 3p cookies and referer + COOKIEBLOCK: 'cookieblock', // block 3p cookies and referer + SITEHACK: 'siteHacks', + WEBTORRENT: 'webtorrent' // ... other optional resource files are identified by uuid such as for regional adblock }, cookieblock: { @@ -34,12 +36,14 @@ module.exports = { flash: { enabled: false, installUrl: 'https://get.adobe.com/flashplayer/', - url: getTargetAboutUrl('about:flash') + url: getTargetAboutUrl('about:flash'), + shields: false }, widevine: { enabled: false, moreInfoUrl: 'https://www.eff.org/issues/drm', - licenseUrl: 'https://www.google.com/policies/terms/' + licenseUrl: 'https://www.google.com/policies/terms/', + shields: false }, adblock: { alternateDataFiles: 'https://s3.amazonaws.com/adblock-data/{version}/{uuid}.dat', @@ -69,6 +73,9 @@ module.exports = { siteHacks: { enabled: true }, + webtorrent: { + enabled: true + }, adInsertion: { enabled: false, url: adHost diff --git a/js/constants/messages.js b/js/constants/messages.js index 0631a009aff..7430b4fcca0 100644 --- a/js/constants/messages.js +++ b/js/constants/messages.js @@ -76,7 +76,6 @@ const messages = { RELOAD: _, ENABLE_SWIPE_GESTURE: _, DISABLE_SWIPE_GESTURE: _, - SHOW_FLASH_NOTIFICATION: _, // Password manager GET_PASSWORDS: _, /** @arg {string} formOrigin, @arg {string} action */ GOT_PASSWORD: _, /** @arg {string} username, @arg {string} password, @arg {string} origin, @arg {string} action, @arg {boolean} isUnique */ @@ -110,7 +109,6 @@ const messages = { EXTENSIONS_UPDATED: _, ADBLOCK_UPDATED: _, DOWNLOADS_UPDATED: _, - FLASH_UPDATED: _, NEWTAB_DATA_UPDATED: _, VERSION_INFORMATION_UPDATED: _, // About pages from contentScript diff --git a/js/constants/settings.js b/js/constants/settings.js index c2ca6980839..2716085f178 100644 --- a/js/constants/settings.js +++ b/js/constants/settings.js @@ -41,6 +41,7 @@ const settings = { SHUTDOWN_CLEAR_AUTOCOMPLETE_DATA: 'shutdown.clear-autocomplete-data', SHUTDOWN_CLEAR_AUTOFILL_DATA: 'shutdown.clear-autofill-data', SHUTDOWN_CLEAR_SITE_SETTINGS: 'shutdown.clear-site-settings', + FLASH_INSTALLED: 'security.flash.installed', // Autofill AUTOFILL_ENABLED: 'privacy.autofill-enabled', // Payments Tab diff --git a/js/flash.js b/js/flash.js index 04c5d13b912..f7c2736a352 100644 --- a/js/flash.js +++ b/js/flash.js @@ -6,12 +6,21 @@ const fs = require('fs') const path = require('path') const electron = require('electron') -let app -if (process.type === 'browser') { - app = electron.app -} else { - app = electron.remote.app -} +const app = electron.app +const ipcMain = electron.ipcMain +const webContents = electron.webContents +const appActions = require('./actions/appActions') +const appConfig = require('./constants/appConfig') +const Filtering = require('../app/filtering') +const locale = require('../app/locale') +const messages = require('./constants/messages') +const siteUtil = require('./state/siteUtil') +const urlParse = require('url').parse +const settings = require('./constants/settings') +const { siteHacks } = require('./data/siteHacks') + +let flashInstalled = false +const notificationCallbacks = {} const getPepperFlashPath = () => { if (['darwin', 'win32'].includes(process.platform)) { @@ -34,23 +43,209 @@ const getPepperFlashPath = () => { return pluginPath } -module.exports.init = () => { - // TODO: This only works if sync currently - try { - const pepperFlashSystemPluginPath = getPepperFlashPath() - const pepperFlashManifestPath = path.resolve(pepperFlashSystemPluginPath, '..', 'manifest.json') - const data = fs.readFileSync(pepperFlashManifestPath) - if (!data) { - return false +/** + * Checks whether a link is an Flash installer URL. + * @param {string} url + * @return {boolean} + */ +const isFlashInstallUrl = (url) => { + const adobeRegex = new RegExp('//(get\\.adobe\\.com/([a-z_-]+/)*flashplayer|www\\.macromedia\\.com/go/getflash|www\\.adobe\\.com/go/getflash)', 'i') + return adobeRegex.test(url) +} + +/** + * Shows a Flash CtP notification if Flash is installed and enabled. + * If not enabled, alert user that Flash is installed. + * @param {string} origin - frame origin that is requesting to run flash. + * can either be main frame or subframe. + */ +const showFlashNotification = (origin, tabId, url, noFlashUrl) => { + // Generate a random string that is unlikely to collide. Not + // cryptographically random. + const nonce = Math.random().toString() + + if (flashInstalled) { + const message = locale.translation('allowFlashPlayer', { origin }) + // Show Flash notification bar + appActions.showMessageBox({ + buttons: [ + {text: locale.translation('deny')}, + {text: locale.translation('allow')} + ], + message, + frameOrigin: origin, + options: { + nonce, + persist: true + } + }) + notificationCallbacks[message] = (buttonIndex, persist) => { + let newUrl = null + if (buttonIndex === 1) { + if (persist) { + appActions.changeSiteSetting(origin, 'flash', Date.now() + 7 * 24 * 1000 * 3600) + } else { + appActions.changeSiteSetting(origin, 'flash', 1) + } + newUrl = url + } else { + if (persist) { + appActions.changeSiteSetting(origin, 'flash', false) + } + if (noFlashUrl) { + newUrl = noFlashUrl + } + } + + if (!newUrl) { + return + } + + let tab = webContents.fromTabID(tabId) + if (tab && !tab.isDestroyed()) { + tab.loadURL(newUrl) + } } + } else { + module.exports.checkFlashInstalled((installed) => { + if (installed) { + let message = locale.translation('flashInstalled') + appActions.showMessageBox({ + buttons: [ + {text: locale.translation('goToPrefs')}, + {text: locale.translation('goToAdobe')} + ], + message: message, + options: {nonce} + }) + notificationCallbacks[message] = (buttonIndex, persist) => { + const location = buttonIndex === 0 ? 'about:preferences#security' : appConfig.flash.installUrl + appActions.newTab({ location }) + } + } else if (noFlashUrl) { + let tab = webContents.fromTabID(tabId) + if (tab && !tab.isDestroyed()) { + tab.loadURL(noFlashUrl) + } + } + }) + } - const pepperFlashManifest = JSON.parse(data) - app.commandLine.appendSwitch('ppapi-flash-path', pepperFlashSystemPluginPath) - app.commandLine.appendSwitch('ppapi-flash-version', pepperFlashManifest.version) - return true - } catch (e) { + ipcMain.once(messages.NOTIFICATION_RESPONSE + nonce, (e, msg, buttonIndex, persist) => { + try { + const cb = notificationCallbacks[msg] + delete notificationCallbacks[msg] + if (cb) { + cb(buttonIndex, persist) + } + } catch (e) { + console.error(e) + } + appActions.hideMessageBox(msg) + }) +} + +const flashSetting = (url, isPrivate) => { + let activeSiteSettings = Filtering.getSiteSettings(url, isPrivate) + return activeSiteSettings && activeSiteSettings.get('flash') +} + +const allowRunningFlash = (url, isPrivate) => { + return typeof flashSetting(url, isPrivate) === 'number' +} + +/** + * Checks whether the first-party page is one that should have Flash install + * URL interception. + * @param {string} url + * @return {boolean} + */ +const shouldInterceptFlash = (url, isPrivate) => { + if (!url) { return false } + + if (flashSetting(url, isPrivate) === false) { + return false + } + + const parsed = urlParse(url) + const exemptHostPattern = new RegExp('(\\.adobe\\.com|www\\.google(\\.\\w+){1,2}|^duckduckgo\\.com|^search\\.yahoo\\.com)$') + return parsed.hostname && + ['http:', 'https:'].includes(parsed.protocol) && + !exemptHostPattern.test(parsed.hostname) && + !['/search', '/search/'].includes(parsed.pathname) +} + +function handleFlashCTP (details, isPrivate) { + // we never do anything with the result because this is after page load + const result = { + resourceName: module.exports.resourceName + } + + if (!flashInstalled || details.resourceType !== 'mainFrame' || !allowRunningFlash(details.url, isPrivate)) { + return result + } + + const mainFrameUrl = Filtering.getMainFrameUrl(details) + if (!mainFrameUrl) { + return result + } + + const origin = siteUtil.getOrigin(mainFrameUrl) + const parsed = urlParse(mainFrameUrl) + const hack = siteHacks[parsed.hostname] + + if (origin && hack && hack.enableFlashCTP) { + // Fix #3011 + showFlashNotification(origin, details.tabId, null, hack.redirectURL) + } + + return result +} + +function handleFlashInstallUrl (details, isPrivate) { + const result = { + resourceName: module.exports.resourceName, + redirectURL: null, + cancel: false + } + + if (details.resourceType !== 'mainFrame') { + return result + } + + const mainFrameUrl = Filtering.getMainFrameUrl(details) + if (!mainFrameUrl) { + return result + } + + const origin = siteUtil.getOrigin(mainFrameUrl) + if (origin && isFlashInstallUrl(details.url) && + shouldInterceptFlash(mainFrameUrl, isPrivate)) { + result.cancel = true + showFlashNotification(origin, details.tabId, details.url) + } + + return result +} + +module.exports.init = (state, action) => { + setImmediate(() => { + module.exports.checkFlashInstalled((result, path, manifest) => { + if (result) { + flashInstalled = true + Filtering.registerBeforeRequestFilteringCB(handleFlashInstallUrl) + Filtering.registerHeadersReceivedFilteringCB(handleFlashCTP) + app.commandLine.appendSwitch('ppapi-flash-path', path) + app.commandLine.appendSwitch('ppapi-flash-version', manifest.version) + } + setImmediate(() => { + appActions.changeSetting(settings.FLASH_INSTALLED, result) + }) + }) + }) + return state } module.exports.checkFlashInstalled = (cb) => { @@ -61,10 +256,12 @@ module.exports.checkFlashInstalled = (cb) => { if (err || !data) { cb(false) } else { - cb(true) + cb(true, pepperFlashSystemPluginPath, JSON.parse(data)) } }) } catch (e) { cb(false) } } + +module.exports.resourceName = 'flash' diff --git a/js/lib/urlutil.js b/js/lib/urlutil.js index dfda8da489c..72edde93716 100644 --- a/js/lib/urlutil.js +++ b/js/lib/urlutil.js @@ -290,34 +290,6 @@ const UrlUtil = { return hostPatterns }, - /** - * Checks whether a link is an Flash installer URL. - * @param {string} url - * @return {boolean} - */ - isFlashInstallUrl: function (url) { - const adobeRegex = new RegExp('//(get\\.adobe\\.com/([a-z_-]+/)*flashplayer|www\\.macromedia\\.com/go/getflash|www\\.adobe\\.com/go/getflash)', 'i') - return adobeRegex.test(url) - }, - - /** - * Checks whether the first-party page is one that should have Flash install - * URL interception. - * @param {string} url - * @return {boolean} - */ - shouldInterceptFlash: function (url) { - if (!url) { - return false - } - const parsed = urlParse(url) - const exemptHostPattern = new RegExp('(\\.adobe\\.com|www\\.google(\\.\\w+){1,2}|^duckduckgo\\.com|^search\\.yahoo\\.com)$') - return parsed.hostname && - ['http:', 'https:'].includes(parsed.protocol) && - !exemptHostPattern.test(parsed.hostname) && - !['/search', '/search/'].includes(parsed.pathname) - }, - /** * Gets PDF location from a potential PDFJS URL * @param {string} url diff --git a/js/state/siteSettings.js b/js/state/siteSettings.js index 401698a6f22..6e67bbb73eb 100644 --- a/js/state/siteSettings.js +++ b/js/state/siteSettings.js @@ -50,7 +50,7 @@ module.exports.activeSettings = (siteSettings, appState, appConfig) => { Object.keys(appConfig.resourceNames).forEach((resourceName) => { let name = appConfig.resourceNames[resourceName] settings[name] = (() => { - if (settings.shieldsUp === false) { + if (settings.shieldsUp === false && appConfig[resourceName].shields !== false) { return false } diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 91d6afac752..43ecd182fef 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -32,7 +32,7 @@ const locale = require('../../app/locale') const path = require('path') const autofill = require('../../app/autofill') const nativeImage = require('../../app/nativeImage') - +const Filtering = require('../../app/filtering') const basicAuth = require('../../app/browser/basicAuth') const tabs = require('../../app/browser/tabs') const windows = require('../../app/browser/windows') @@ -45,6 +45,9 @@ const aboutNewTabState = require('../../app/common/state/aboutNewTabState') const aboutHistoryState = require('../../app/common/state/aboutHistoryState') const windowState = require('../../app/common/state/windowState') +const flash = require('../flash.js') +const webtorrent = require('../../app/browser/webtorrent') + const isDarwin = process.platform === 'darwin' const isWindows = process.platform === 'win32' @@ -345,7 +348,6 @@ function handleChangeSettingAction (settingKey, settingValue) { }) break case settings.DEFAULT_ZOOM_LEVEL: - const Filtering = require('../../app/filtering') Filtering.setDefaultZoomLevel(settingValue) break default: @@ -362,9 +364,12 @@ const handleAppAction = (action) => { switch (action.actionType) { case AppConstants.APP_SET_STATE: appState = action.appState - windows.init(appState, action) - tabs.init(appState, action) - basicAuth.init(appState, action) + appState = Filtering.init(appState, action, appStore) + appState = windows.init(appState, action, appStore) + appState = tabs.init(appState, action, appStore) + appState = basicAuth.init(appState, action, appStore) + appState = flash.init(appState, action, appStore) + appState = webtorrent.init(appState, action, appStore) break case AppConstants.APP_SHUTTING_DOWN: shuttingDown = true From 2175ac2371cafbe0be1104f9ed64ef1789aeabfc Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Tue, 29 Nov 2016 10:55:57 -0500 Subject: [PATCH 26/80] Use forked winstaller Auditors: @bridiver --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd5a50676a8..ccc6a2d6afb 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "css-loader": "^0.23.0", "electron-builder": "^2.3.1", "electron-packager": "brave/electron-packager", - "electron-winstaller": "2.5.1", + "electron-winstaller": "brave/windows-installer", "empty-port": "0.0.2", "flow-bin": "^0.22.1", "gulp": "^3.9.0", From 3d928b38f5d138afd09996d7ccfad21501eabc99 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Tue, 29 Nov 2016 13:38:47 -0500 Subject: [PATCH 27/80] Use muon-winstaller instead of electron-winstaller There was a prepublish command so I couldn't use the direct github repo. I decided to fork it and publish it. Changing the prepublish to postinstall was also undesirable because it would add more time to npm installs Auditors: @bridiver --- package.json | 2 +- tools/buildInstaller.js | 4 ++-- tools/lib/ignoredPaths.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ccc6a2d6afb..c93354b9fd2 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,6 @@ "css-loader": "^0.23.0", "electron-builder": "^2.3.1", "electron-packager": "brave/electron-packager", - "electron-winstaller": "brave/windows-installer", "empty-port": "0.0.2", "flow-bin": "^0.22.1", "gulp": "^3.9.0", @@ -153,6 +152,7 @@ "mkdirp": "^0.5.1", "mocha": "^2.3.4", "mockery": "^1.7.0", + "muon-winstaller": "^2.4.0", "ncp": "^2.0.0", "node-gyp": "^3.2.1", "node-libs-browser": "^1.0.0", diff --git a/tools/buildInstaller.js b/tools/buildInstaller.js index 48e68a91006..f68f84f72e1 100644 --- a/tools/buildInstaller.js +++ b/tools/buildInstaller.js @@ -61,8 +61,8 @@ if (isDarwin) { // need to store the output files in separate directories outDir = path.join(outDir, arch) - var electronInstaller = require('electron-winstaller') - var resultPromise = electronInstaller.createWindowsInstaller({ + var muonInstaller = require('muon-winstaller') + var resultPromise = muonInstaller.createWindowsInstaller({ appDirectory: buildDir, outputDirectory: outDir, title: 'Brave', diff --git a/tools/lib/ignoredPaths.js b/tools/lib/ignoredPaths.js index 14707d2fc92..d1c751995bf 100644 --- a/tools/lib/ignoredPaths.js +++ b/tools/lib/ignoredPaths.js @@ -42,7 +42,7 @@ module.exports = [ 'electron-builder', 'electron-prebuilt', 'electron-rebuild', - 'electron-winstaller', + 'muon-winstaller', 'electron-winstaller-fixed', 'electron-installer-redhat', 'flow-bin', From 592ddd9692a18021c7baf20ed1fc95586c777c74 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 30 Nov 2016 00:20:59 -0500 Subject: [PATCH 28/80] Use muon 2.0.1 --- .npmrc | 4 ++-- package.json | 2 +- tools/cibuild.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.npmrc b/.npmrc index 474ce5a9258..70fe2bd496c 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,5 @@ runtime = electron -target = 2.0.0 +target = 2.0.1 target_arch = x64 -brave_electron_version = 2.0.0 +brave_electron_version = 2.0.1 disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist diff --git a/package.json b/package.json index c93354b9fd2..a2f6283108f 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "aphrodite": "^1.0.0", "async": "^2.0.1", "electron-localshortcut": "^0.6.0", - "electron-prebuilt": "brave/electron-prebuilt#2.0.0", + "electron-prebuilt": "brave/electron-prebuilt#2.0.1", "electron-squirrel-startup": "brave/electron-squirrel-startup", "file-loader": "^0.8.5", "font-awesome": "^4.5.0", diff --git a/tools/cibuild.py b/tools/cibuild.py index 12951e416d5..d8a2d5d0085 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -5,8 +5,8 @@ import sys import os.path -BRAVE_ELECTRON = '2.0.0' -UPSTREAM_ELECTRON = '2.0.0' +BRAVE_ELECTRON = '2.0.1' +UPSTREAM_ELECTRON = '2.0.1' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) TARGET_ARCH= os.environ['TARGET_ARCH'] if os.environ.has_key('TARGET_ARCH') else 'x64' os.environ['npm_config_arch'] = TARGET_ARCH From dd0a066b928a4b73c87d908d8c1e8af7d64f6082 Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 30 Nov 2016 15:17:19 -0700 Subject: [PATCH 29/80] ignore internal and extension generated requests maybe fixes #5930 fix #5934 auditors: @bbondy --- app/filtering.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/app/filtering.js b/app/filtering.js index ac0077df761..cdb6df8f2d5 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -96,7 +96,7 @@ function registerForBeforeRequest (session, partition) { } } - if (shouldIgnoreUrl(details.url)) { + if (shouldIgnoreUrl(details)) { cb({}) return } @@ -195,7 +195,7 @@ function registerForBeforeRedirect (session, partition) { // Note that onBeforeRedirect listener doesn't take a callback session.webRequest.onBeforeRedirect(function (details) { // Using an electron binary which isn't from Brave - if (shouldIgnoreUrl(details.url)) { + if (shouldIgnoreUrl(details)) { return } for (let i = 0; i < beforeRedirectFilteringFns.length; i++) { @@ -222,7 +222,7 @@ function registerForBeforeSendHeaders (session, partition) { session.webRequest.onBeforeSendHeaders(function (details, cb) { // Using an electron binary which isn't from Brave - if (shouldIgnoreUrl(details.url)) { + if (shouldIgnoreUrl(details)) { cb({}) return } @@ -295,7 +295,7 @@ function registerForHeadersReceived (session, partition) { // Note that onBeforeRedirect listener doesn't take a callback session.webRequest.onHeadersReceived(function (details, cb) { // Using an electron binary which isn't from Brave - if (shouldIgnoreUrl(details.url)) { + if (shouldIgnoreUrl(details)) { cb({}) return } @@ -558,16 +558,30 @@ function initForPartition (partition) { const filterableProtocols = ['http:', 'https:'] -function shouldIgnoreUrl (url) { +function shouldIgnoreUrl (details) { + // internal requests + if (details.tabId === -1) { + return true + } + // Ensure host is well-formed (RFC 1035) and has a non-empty hostname + try { + const firstPartyUrl = urlParse(details.firstPartyUrl) + if (!filterableProtocols.includes(firstPartyUrl.protocol)) { + return true + } + } catch (e) { + console.warn('Error parsing ' + details.firstPartyUrl) + } + try { // TODO(bridiver) - handle RFS check and cancel http/https requests with 0 or > 255 length hostames - const parsedUrl = urlParse(url) + const parsedUrl = urlParse(details.url) if (filterableProtocols.includes(parsedUrl.protocol)) { return false } } catch (e) { - console.warn('Error parsing ' + url) + console.warn('Error parsing ' + details.url) } return true } From b494ed183d6ccd6afe964ac6e5f814c40a89e3e5 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Thu, 1 Dec 2016 13:44:11 +0800 Subject: [PATCH 30/80] hide-autofill-popup only when webcontent is focused also fix frontend id typo leads to crash fix #5939 Auditor: @bridiver --- js/components/frame.js | 5 ++++- js/stores/windowStore.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 3c4d65e6c97..59cbf4e19ea 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -722,7 +722,10 @@ class Frame extends ImmutableComponent { contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) }) this.webview.addEventListener('hide-autofill-popup', (e) => { - windowActions.autofillPopupHidden(this.props.tabId) + let webContents = this.webview.getWebContents() + if (webContents && webContents.isFocused()) { + windowActions.autofillPopupHidden(this.props.tabId) + } }) this.webview.addEventListener('ipc-message', (e) => { let method = () => {} diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index a557996dd90..dc857426662 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -636,7 +636,7 @@ const doAction = (action) => { windowStore.emitChanges() return case WindowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED: - ipc.send('autofill-selection-clicked', action.tabId, action.value, action.frontendId, action.index) + ipc.send('autofill-selection-clicked', action.tabId, action.value, action.frontEndId, action.index) windowState = windowState.delete('contextMenuDetail') break case WindowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN: From 2063236383186150a34758defd8bc6da2897b462 Mon Sep 17 00:00:00 2001 From: bridiver Date: Fri, 2 Dec 2016 16:26:13 -0700 Subject: [PATCH 31/80] use JDM methods from https://github.com/brave/electron/commit/072e85f425f1168e504a036f53aef03b03f5594a auditors @bbondy --- app/index.js | 75 ++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/app/index.js b/app/index.js index 3d1e92f7044..e0d925a2c41 100644 --- a/app/index.js +++ b/app/index.js @@ -347,44 +347,51 @@ app.on('ready', () => { } }) - ipcMain.removeAllListeners('window-alert') - ipcMain.on('window-alert', function (event, message, title) { - var buttons - - buttons = ['OK'] - message = message ? message.toString() : '' - title = title ? title.toString() : '' - dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { - message: message, - title: title, - buttons: buttons + process.on('window-alert', + (webContents, extraData, title, message, defaultPromptText, + shouldDisplaySuppressCheckbox, isBeforeUnloadDialog, isReload, cb) => { + let suppress = false + const buttons = ['OK'] + if (!webContents || webContents.isDestroyed()) { + cb(false, '', suppress) + } else { + cb(true, '', suppress) + } + + const hostWebContents = webContents.hostWebContents || webContents + dialog.showMessageBox(BrowserWindow.fromWebContents(hostWebContents), { + message, + title, + buttons: buttons + }) }) - // Alert should always return undefined. - }) - ipcMain.removeAllListeners('window-confirm') - ipcMain.on('window-confirm', function (event, message, title) { - var buttons, cancelId - - buttons = ['OK', 'Cancel'] - message = message ? message.toString() : '' - title = title ? title.toString() : '' - cancelId = 1 - event.returnValue = !dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { - message: message, - title: title, - buttons: buttons, - cancelId: cancelId + process.on('window-confirm', + (webContents, extraData, title, message, defaultPromptText, + shouldDisplaySuppressCheckbox, isBeforeUnloadDialog, isReload, cb) => { + let suppress = false + const buttons = ['OK', 'Cancel'] + if (!webContents || webContents.isDestroyed()) { + cb(false, '', suppress) + } + + const hostWebContents = webContents.hostWebContents || webContents + const response = dialog.showMessageBox(BrowserWindow.fromWebContents(hostWebContents), { + message, + title, + buttons: buttons, + cancelId: 1 + }) + cb(!response, '', suppress) }) - return event.returnValue - }) - ipcMain.removeAllListeners('window-prompt') - ipcMain.on('window-prompt', function (event, text, defaultText) { - console.warn('window.prompt is not supported yet') - event.returnValue = null - return event.returnValue - }) + process.on('window-prompt', + (webContents, extraData, title, message, defaultPromptText, + shouldDisplaySuppressCheckbox, isBeforeUnloadDialog, isReload, cb) => { + console.warn('window.prompt is not supported yet') + let suppress = false + cb(false, '', suppress) + }) process.on(messages.UNDO_CLOSED_WINDOW, () => { if (lastWindowState) { From 3091d4fa65675dfc82038dafd27bc45b164db8c2 Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Fri, 2 Dec 2016 16:00:09 -0700 Subject: [PATCH 32/80] Fix platformUtil tests after https://github.com/brave/browser-laptop/commit/24a0493421cf0448ebda4dd035ce665b44a6adfc#diff-fd09a6dc151769bdeaaf61fb423090f5 Set a default value (false) for 'security.flash.installed' --- js/constants/appConfig.js | 1 + js/lib/urlutil.js | 28 ++++++++++ test/unit/app/common/lib/platformUtilTest.js | 58 +++++++++++--------- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js index 3b60f8269ad..3670374eef5 100644 --- a/js/constants/appConfig.js +++ b/js/constants/appConfig.js @@ -141,6 +141,7 @@ module.exports = { 'security.passwords.one-password-enabled': false, 'security.passwords.dashlane-enabled': false, 'security.passwords.last-pass-enabled': false, + 'security.flash.installed': false, 'general.downloads.default-save-path': null, 'general.disable-title-mode': process.platform === 'linux', 'advanced.hardware-acceleration-enabled': true, diff --git a/js/lib/urlutil.js b/js/lib/urlutil.js index 72edde93716..dfda8da489c 100644 --- a/js/lib/urlutil.js +++ b/js/lib/urlutil.js @@ -290,6 +290,34 @@ const UrlUtil = { return hostPatterns }, + /** + * Checks whether a link is an Flash installer URL. + * @param {string} url + * @return {boolean} + */ + isFlashInstallUrl: function (url) { + const adobeRegex = new RegExp('//(get\\.adobe\\.com/([a-z_-]+/)*flashplayer|www\\.macromedia\\.com/go/getflash|www\\.adobe\\.com/go/getflash)', 'i') + return adobeRegex.test(url) + }, + + /** + * Checks whether the first-party page is one that should have Flash install + * URL interception. + * @param {string} url + * @return {boolean} + */ + shouldInterceptFlash: function (url) { + if (!url) { + return false + } + const parsed = urlParse(url) + const exemptHostPattern = new RegExp('(\\.adobe\\.com|www\\.google(\\.\\w+){1,2}|^duckduckgo\\.com|^search\\.yahoo\\.com)$') + return parsed.hostname && + ['http:', 'https:'].includes(parsed.protocol) && + !exemptHostPattern.test(parsed.hostname) && + !['/search', '/search/'].includes(parsed.pathname) + }, + /** * Gets PDF location from a potential PDFJS URL * @param {string} url diff --git a/test/unit/app/common/lib/platformUtilTest.js b/test/unit/app/common/lib/platformUtilTest.js index b6bffc2ff55..1f88b7c931e 100644 --- a/test/unit/app/common/lib/platformUtilTest.js +++ b/test/unit/app/common/lib/platformUtilTest.js @@ -1,40 +1,56 @@ -/* global describe, it */ -const mockery = require('mockery') +/* global describe, it, afterEach */ const assert = require('assert') let platformUtil = require('../../../../../app/common/lib/platformUtil') require('../../../braveUnit') describe('platformUtil', function () { + // see atom_extensions_dispatcher_delegate.cc for all values const mockWin7 = { - platform: () => 'win32', - release: () => '6.1.7601' + platform: 'win32', + platformVersion: 'win7' } const mockWin8 = { - platform: () => 'win32', - release: () => '6.3.9600' + platform: 'win32', + platformVersion: 'win8' } const mockWin10 = { - platform: () => 'win32', - release: () => '10.0.10586' + platform: 'win32', + platformVersion: 'win10' } const mockMacOS = { - platform: () => 'darwin' + platform: 'darwin', + platformVersion: '' } - - // For more details on Mockery, see https://github.com/mfncooper/mockery const loadMocks = (osMock) => { - mockery.enable({ warnOnReplace: false, warnOnUnregistered: false, useCleanCache: true }) - mockery.registerMock('os', osMock) - platformUtil = require('../../../../../app/common/lib/platformUtil') + this.originalPlatform = process.platform + this.originalPlatformVersion = process.platformVersion + Object.defineProperty(process, 'platform', { + value: osMock.platform, + configurable: true + }) + Object.defineProperty(process, 'platformVersion', { + value: osMock.platformVersion, + configurable: true + }) } const unloadMocks = () => { - mockery.disable() - platformUtil = require('../../../../../app/common/lib/platformUtil') + Object.defineProperty(process, 'platform', { + value: this.originalPlatform + }) + Object.defineProperty(process, 'platformVersion', { + value: this.originalPlatformVersion + }) } + afterEach(function () { + unloadMocks() + }) + describe('getPlatformStyles', function () { it('prepends style with platform--', function () { + loadMocks(mockWin7) + const result = platformUtil.getPlatformStyles() assert.equal(result[0].match(/^platform--/), 'platform--') }) @@ -44,8 +60,6 @@ describe('platformUtil', function () { const result = platformUtil.getPlatformStyles() assert.equal(result.length, 2) assert.equal(result[1], 'win7') - - unloadMocks() }) it('returns the style "win10" for Windows 8', function () { loadMocks(mockWin8) @@ -53,8 +67,6 @@ describe('platformUtil', function () { const result = platformUtil.getPlatformStyles() assert.equal(result.length, 2) assert.equal(result[1], 'win10') - - unloadMocks() }) it('returns the style "win10" for Windows 10', function () { loadMocks(mockWin10) @@ -62,8 +74,6 @@ describe('platformUtil', function () { const result = platformUtil.getPlatformStyles() assert.equal(result.length, 2) assert.equal(result[1], 'win10') - - unloadMocks() }) }) @@ -71,12 +81,10 @@ describe('platformUtil', function () { it('returns true if using macOS', function () { loadMocks(mockMacOS) assert.equal(platformUtil.isDarwin(), true) - unloadMocks() }) it('returns false if not using macOS', function () { loadMocks(mockWin10) assert.equal(platformUtil.isDarwin(), false) - unloadMocks() }) }) @@ -84,12 +92,10 @@ describe('platformUtil', function () { it('returns true if using Windows', function () { loadMocks(mockWin10) assert.equal(platformUtil.isWindows(), true) - unloadMocks() }) it('returns false if not using Windows', function () { loadMocks(mockMacOS) assert.equal(platformUtil.isWindows(), false) - unloadMocks() }) }) }) From 6d2c81ce1ec316205884ace4598d2a134e2058ae Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Sat, 3 Dec 2016 02:15:40 -0700 Subject: [PATCH 33/80] Updated version of chromedriver Noteworthy commits from other repos: (chromedriver) https://github.com/brave/electron-chromedriver/commit/402e6bdfb6f09f412c20fde011d06553aa650378 (spectron) https://github.com/brave/spectron/commit/44394296d75e5d972eedfc64361921df42b4fa7f Auditors: @bridiver, @darkdh Test Plan: 1. `npm install` 2. `./node_modules/electron-chromedriver/bin/chromedriver -v` 3. Notice version is 2.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2f6283108f..dc0058c58fc 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,7 @@ "nsp": "^2.2.0", "pre-commit": "brave/pre-commit", "react-addons-perf": "^15.2.1", - "spectron": "brave/spectron", + "spectron": "brave/spectron#chromium54", "sqlite3": "^3.1.1", "standard": "8.1.0", "style-loader": "^0.13.0", From f569e94db3f3bd1b63cc05224b2370b4cb7bd036 Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Sat, 3 Dec 2016 02:34:49 -0700 Subject: [PATCH 34/80] First steps at getting the spectron/webdriver tests working Auditors: @bridiver --- app/extensions/brave/index-dev.html | 1 + app/extensions/brave/index-load-script.js | 2 ++ app/extensions/brave/index.html | 1 + js/devTools.js | 10 ++++++ test/lib/brave.js | 42 ++++++++++++----------- webpack.config.js | 27 +++++++++------ 6 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 js/devTools.js diff --git a/app/extensions/brave/index-dev.html b/app/extensions/brave/index-dev.html index 89e4637cfe7..0a96194525e 100644 --- a/app/extensions/brave/index-dev.html +++ b/app/extensions/brave/index-dev.html @@ -11,6 +11,7 @@ Brave + diff --git a/app/extensions/brave/index-load-script.js b/app/extensions/brave/index-load-script.js index 3ea41c5b38c..cf6190712fa 100644 --- a/app/extensions/brave/index-load-script.js +++ b/app/extensions/brave/index-load-script.js @@ -21,4 +21,6 @@ document.querySelector('#webpackLoading').style.display = 'block' createScript(appEntry).catch(function () { document.querySelector('#webpackLoading').style.display = 'none' document.querySelector('#setupError').style.display = 'block' +}).then(() => { + createScript(baseHref + '/gen/lib.devTools.js') }) diff --git a/app/extensions/brave/index.html b/app/extensions/brave/index.html index e1f4b7aa5ae..a973dd02cf9 100644 --- a/app/extensions/brave/index.html +++ b/app/extensions/brave/index.html @@ -11,6 +11,7 @@ Brave + diff --git a/js/devTools.js b/js/devTools.js new file mode 100644 index 00000000000..83e61c7274a --- /dev/null +++ b/js/devTools.js @@ -0,0 +1,10 @@ +const electron = require('electron') +const appActions = require('./actions/appActions') + +module.exports = function (name) { + if (name === 'electron') { + return electron + } else if (name === 'appActions') { + return appActions + } +} diff --git a/test/lib/brave.js b/test/lib/brave.js index 1382abccb62..bcdbb686a11 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -1,3 +1,4 @@ +/* globals devTools */ var Application = require('spectron').Application var chai = require('chai') require('./coMocha') @@ -153,13 +154,13 @@ var exports = { addCommands: function () { this.app.client.addCommand('ipcSend', function (message, ...param) { return this.execute(function (message, ...param) { - return require('electron').remote.getCurrentWindow().webContents.send(message, ...param) + return devTools('electron').remote.getCurrentWindow().webContents.send(message, ...param) }, message, ...param).then((response) => response.value) }) this.app.client.addCommand('ipcSendRenderer', function (message, ...param) { return this.execute(function (message, ...param) { - return require('electron').ipcRenderer.send(message, ...param) + return devTools('electron').ipcRenderer.send(message, ...param) }, message, ...param).then((response) => response.value) }) @@ -310,7 +311,7 @@ var exports = { this.app.client.addCommand('showFindbar', function (show, key = 1) { return this.execute(function (show, key) { window.windowActions.setFindbarShown(Object.assign({ - windowId: require('electron').remote.getCurrentWindow().id, + windowId: devTools('electron').remote.getCurrentWindow().id, key }), show !== false) }, show, key) @@ -328,7 +329,7 @@ var exports = { return this.execute(function (location, isPinned, options) { var Immutable = require('immutable') window.windowActions.setPinned(Immutable.fromJS(Object.assign({ - windowId: require('electron').remote.getCurrentWindow().id, + windowId: devTools('electron').remote.getCurrentWindow().id, location }, options)), isPinned) }, location, isPinned, options) @@ -336,13 +337,13 @@ var exports = { this.app.client.addCommand('ipcOn', function (message, fn) { return this.execute(function (message, fn) { - return require('electron').remote.getCurrentWindow().webContents.on(message, fn) + return devTools('electron').remote.getCurrentWindow().webContents.on(message, fn) }, message, fn).then((response) => response.value) }) this.app.client.addCommand('newWindowAction', function (frameOpts, browserOpts) { return this.execute(function () { - return require('../../../js/actions/appActions').newWindow() + return devTools('appActions').newWindow() }, frameOpts, browserOpts).then((response) => response.value) }) @@ -354,7 +355,7 @@ var exports = { */ this.app.client.addCommand('addSite', function (siteDetail, tag) { return this.execute(function (siteDetail, tag) { - return require('../../../js/actions/appActions').addSite(siteDetail, tag) + return devTools('appActions').addSite(siteDetail, tag) }, siteDetail, tag).then((response) => response.value) }) @@ -365,7 +366,7 @@ var exports = { */ this.app.client.addCommand('addSiteList', function (siteDetail) { return this.execute(function (siteDetail) { - return require('../../../js/actions/appActions').addSite(siteDetail) + return devTools('appActions').addSite(siteDetail) }, siteDetail).then((response) => response.value) }) @@ -377,7 +378,7 @@ var exports = { */ this.app.client.addCommand('setResourceEnabled', function (resourceName, enabled) { return this.execute(function (resourceName, enabled) { - return require('../../../js/actions/appActions').setResourceEnabled(resourceName, enabled) + return devTools('appActions').setResourceEnabled(resourceName, enabled) }, resourceName, enabled).then((response) => response.value) }) @@ -389,7 +390,7 @@ var exports = { */ this.app.client.addCommand('removeSite', function (siteDetail, tag) { return this.execute(function (siteDetail, tag) { - return require('../../../js/actions/appActions').removeSite(siteDetail, tag) + return devTools('appActions').removeSite(siteDetail, tag) }, siteDetail, tag).then((response) => response.value) }) @@ -401,7 +402,7 @@ var exports = { */ this.app.client.addCommand('changeSetting', function (key, value) { return this.execute(function (key, value) { - return require('../../../js/actions/appActions').changeSetting(key, value) + return devTools('appActions').changeSetting(key, value) }, key, value).then((response) => response.value) }) @@ -413,7 +414,7 @@ var exports = { */ this.app.client.addCommand('changeSiteSetting', function (hostPattern, key, value) { return this.execute(function (hostPattern, key, value) { - return require('../../../js/actions/appActions').changeSiteSetting(hostPattern, key, value) + return devTools('appActions').changeSiteSetting(hostPattern, key, value) }, hostPattern, key, value).then((response) => response.value) }) @@ -424,13 +425,13 @@ var exports = { */ this.app.client.addCommand('clearAppData', function (clearDataDetail) { return this.execute(function (clearDataDetail) { - return require('../../../js/actions/appActions').clearAppData(clearDataDetail) + return devTools('appActions').clearAppData(clearDataDetail) }, clearDataDetail).then((response) => response.value) }) this.app.client.addCommand('getDefaultWindowHeight', function () { return this.execute(function () { - let screen = require('electron').screen + let screen = devTools('electron').screen let primaryDisplay = screen.getPrimaryDisplay() return primaryDisplay.workAreaSize.height }).then((response) => response.value) @@ -438,7 +439,7 @@ var exports = { this.app.client.addCommand('getDefaultWindowWidth', function () { return this.execute(function () { - let screen = require('electron').screen + let screen = devTools('electron').screen let primaryDisplay = screen.getPrimaryDisplay() return primaryDisplay.workAreaSize.width }).then((response) => response.value) @@ -446,7 +447,7 @@ var exports = { this.app.client.addCommand('getPrimaryDisplayHeight', function () { return this.execute(function () { - let screen = require('electron').screen + let screen = devTools('electron').screen return screen.getPrimaryDisplay().bounds.height }).then((response) => response.value) }) @@ -459,14 +460,14 @@ var exports = { this.app.client.addCommand('getPrimaryDisplayWidth', function () { return this.execute(function () { - let screen = require('electron').screen + let screen = devTools('electron').screen return screen.getPrimaryDisplay().bounds.width }).then((response) => response.value) }) this.app.client.addCommand('resizeWindow', function (width, height) { return this.execute(function (width, height) { - return require('electron').remote.getCurrentWindow().setSize(width, height) + return devTools('electron').remote.getCurrentWindow().setSize(width, height) }, width, height).then((response) => response.value) }) @@ -527,7 +528,7 @@ var exports = { internal.viewInstanceId // This allows you to send more args than just the event itself like would only // be possible with dispatchEvent. - require('electron').ipcRenderer.emit('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + internal.viewInstanceId, ...params) + devTools('electron').ipcRenderer.emit('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + internal.viewInstanceId, ...params) }, frameKey, eventName, ...params).then((response) => response.value) }) @@ -570,7 +571,8 @@ var exports = { quitTimeout: 0, path: './node_modules/.bin/electron', env, - args: ['./', '--debug=5858', '--enable-logging', '--v=1'] + args: ['./', '--debug=5858', '--enable-logging', '--v=1'], + requireName: 'devTools' }) return this.app.start() }, diff --git a/webpack.config.js b/webpack.config.js index f7ec3da168e..9d3b5696df5 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,6 +20,7 @@ function config () { exclude: [ /node_modules/, /\.min.js$/, + path.resolve(__dirname, 'app', 'browser', '*'), path.resolve(__dirname, 'app', 'extensions', '*') ], loader: 'babel' @@ -106,24 +107,28 @@ function merge (config, env) { } var app = { - name: 'app', target: 'web', - entry: ['./js/entry.js'], + entry: { + app: [ path.resolve(__dirname, 'js', 'entry.js') ], + aboutPages: [ path.resolve(__dirname, 'js', 'about', 'entry.js') ] + }, output: { path: path.resolve(__dirname, 'app', 'extensions', 'brave', 'gen'), - filename: 'app.entry.js', + filename: '[name].entry.js', publicPath: './gen/' } } -var aboutPages = { - name: 'about', +var devTools = { target: 'web', - entry: ['./js/about/entry.js'], + entry: { + devTools: [ path.resolve(__dirname, 'js', 'devTools.js') ] + }, output: { path: path.resolve(__dirname, 'app', 'extensions', 'brave', 'gen'), - filename: 'aboutPages.entry.js', - publicPath: './gen/' + filename: 'lib.[name].js', + publicPath: './gen/', + library: '[name]' } } @@ -141,17 +146,17 @@ var webtorrentPage = { module.exports = { development: [ merge(app, development()), - merge(aboutPages, development()), + merge(devTools, development()), merge(webtorrentPage, development()) ], production: [ merge(app, production()), - merge(aboutPages, production()), + merge(devTools, development()), merge(webtorrentPage, production()) ], test: [ merge(app, production()), - merge(aboutPages, production()), + merge(devTools, development()), merge(webtorrentPage, production()) ] }[env] From 5d311bd4699f27506223d148ccd2a3f24c921fbe Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Sun, 4 Dec 2016 00:07:02 -0700 Subject: [PATCH 35/80] Updated js/flash.js to use the methods in lib/urlutil.js (which have unit tests) Auditors: @bridiver --- js/flash.js | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/js/flash.js b/js/flash.js index f7c2736a352..b2ed5ae0e27 100644 --- a/js/flash.js +++ b/js/flash.js @@ -17,7 +17,8 @@ const messages = require('./constants/messages') const siteUtil = require('./state/siteUtil') const urlParse = require('url').parse const settings = require('./constants/settings') -const { siteHacks } = require('./data/siteHacks') +const {siteHacks} = require('./data/siteHacks') +const urlutil = require('./lib/urlutil') let flashInstalled = false const notificationCallbacks = {} @@ -43,16 +44,6 @@ const getPepperFlashPath = () => { return pluginPath } -/** - * Checks whether a link is an Flash installer URL. - * @param {string} url - * @return {boolean} - */ -const isFlashInstallUrl = (url) => { - const adobeRegex = new RegExp('//(get\\.adobe\\.com/([a-z_-]+/)*flashplayer|www\\.macromedia\\.com/go/getflash|www\\.adobe\\.com/go/getflash)', 'i') - return adobeRegex.test(url) -} - /** * Shows a Flash CtP notification if Flash is installed and enabled. * If not enabled, alert user that Flash is installed. @@ -169,12 +160,7 @@ const shouldInterceptFlash = (url, isPrivate) => { return false } - const parsed = urlParse(url) - const exemptHostPattern = new RegExp('(\\.adobe\\.com|www\\.google(\\.\\w+){1,2}|^duckduckgo\\.com|^search\\.yahoo\\.com)$') - return parsed.hostname && - ['http:', 'https:'].includes(parsed.protocol) && - !exemptHostPattern.test(parsed.hostname) && - !['/search', '/search/'].includes(parsed.pathname) + return urlutil.shouldInterceptFlash(url) } function handleFlashCTP (details, isPrivate) { @@ -221,7 +207,7 @@ function handleFlashInstallUrl (details, isPrivate) { } const origin = siteUtil.getOrigin(mainFrameUrl) - if (origin && isFlashInstallUrl(details.url) && + if (origin && urlutil.isFlashInstallUrl(details.url) && shouldInterceptFlash(mainFrameUrl, isPrivate)) { result.cancel = true showFlashNotification(origin, details.tabId, details.url) From 8feebec2966f7f1240e8a7eb398962d48dd62200 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Thu, 1 Dec 2016 13:36:37 -0500 Subject: [PATCH 36/80] Refactor download handling so it works with node removal from window renderer Auditors: @bsclifton Fix #5947 --- app/browser/electronDownloadItem.js | 27 ++ app/browser/reducers/downloadsReducer.js | 96 +++++++ .../constants/electronDownloadItemActions.js | 6 +- app/filtering.js | 36 +-- app/index.js | 5 - docs/appActions.md | 79 ++++++ js/about/aboutActions.js | 7 +- js/about/downloads.js | 2 +- js/actions/appActions.js | 199 ++++++++++----- js/actions/downloadActions.js | 85 ------- js/components/downloadsBar.js | 64 ++++- js/constants/appConstants.js | 9 +- js/constants/messages.js | 1 - js/contextMenus.js | 19 +- js/stores/appStore.js | 19 +- package.json | 1 + .../browser/reducers/downloadsReducerTest.js | 237 ++++++++++++++++++ test/unit/lib/fakeElectron.js | 18 ++ tools/lib/ignoredPaths.js | 1 + 19 files changed, 684 insertions(+), 227 deletions(-) create mode 100644 app/browser/electronDownloadItem.js create mode 100644 app/browser/reducers/downloadsReducer.js rename js/constants/downloadActions.js => app/common/constants/electronDownloadItemActions.js (59%) delete mode 100644 js/actions/downloadActions.js create mode 100644 test/unit/app/browser/reducers/downloadsReducerTest.js diff --git a/app/browser/electronDownloadItem.js b/app/browser/electronDownloadItem.js new file mode 100644 index 00000000000..01b6721b875 --- /dev/null +++ b/app/browser/electronDownloadItem.js @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const downloadStates = require('../../js/constants/downloadStates') + +/** + * Maps downloadId to an electron download-item + */ +const downloadMap = {} + +module.exports.updateElectronDownloadItem = (downloadId, item, state) => { + if (state === downloadStates.INTERRUPTED || state === downloadStates.CANCELLED || state === downloadStates.COMPLETED) { + delete downloadMap[downloadId] + } else { + downloadMap[downloadId] = item + } +} + +module.exports.cancelDownload = (downloadId) => + downloadMap[downloadId] && downloadMap[downloadId].cancel() + +module.exports.pauseDownload = (downloadId) => + downloadMap[downloadId] && downloadMap[downloadId].pause() + +module.exports.resumeDownload = (downloadId) => + downloadMap[downloadId] && downloadMap[downloadId].resume() diff --git a/app/browser/reducers/downloadsReducer.js b/app/browser/reducers/downloadsReducer.js new file mode 100644 index 00000000000..02547ab1200 --- /dev/null +++ b/app/browser/reducers/downloadsReducer.js @@ -0,0 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict' + +const appConstants = require('../../../js/constants/appConstants') +const downloadStates = require('../../../js/constants/downloadStates') +const {clipboard, BrowserWindow, shell} = require('electron') +const fs = require('fs') +const path = require('path') +const {cancelDownload, pauseDownload, resumeDownload} = require('../electronDownloadItem') +const {CANCEL, PAUSE, RESUME} = require('../../common/constants/electronDownloadItemActions') + +const downloadsReducer = (state, action) => { + const download = action.downloadId ? state.getIn(['downloads', action.downloadId]) : undefined + if (!download && + ![appConstants.APP_MERGE_DOWNLOAD_DETAIL, + appConstants.APP_CLEAR_COMPLETED_DOWNLOADS].includes(action.actionType)) { + return state + } + switch (action.actionType) { + case appConstants.APP_DOWNLOAD_REVEALED: + fs.exists(download.get('savePath'), (exists) => { + if (exists) { + shell.showItemInFolder(download.get('savePath')) + } else { + shell.openItem(path.dirname(download.get('savePath'))) + } + }) + break + case appConstants.APP_DOWNLOAD_OPENED: + fs.exists(download.get('savePath'), (exists) => { + if (exists) { + shell.openItem(download.get('savePath')) + } else { + shell.beep() + } + }) + break + case appConstants.APP_DOWNLOAD_ACTION_PERFORMED: + switch (action.downloadAction) { + case CANCEL: + // It's important to update state before the cancel since it'll remove the reference + state = state.setIn(['downloads', action.downloadId, 'state'], downloadStates.CANCELLED) + cancelDownload(action.downloadId) + break + case PAUSE: + pauseDownload(action.downloadId) + state = state.setIn(['downloads', action.downloadId, 'state'], downloadStates.PAUSED) + break + case RESUME: + resumeDownload(action.downloadId) + state = state.setIn(['downloads', action.downloadId, 'state'], downloadStates.IN_PROGRESS) + break + } + break + case appConstants.APP_DOWNLOAD_COPIED_TO_CLIPBOARD: + clipboard.writeText(download.get('url')) + break + case appConstants.APP_DOWNLOAD_DELETED: + shell.moveItemToTrash(download.get('savePath')) + state = state.deleteIn(['downloads', action.downloadId]) + break + case appConstants.APP_DOWNLOAD_CLEARED: + state = state.deleteIn(['downloads', action.downloadId]) + break + case appConstants.APP_DOWNLOAD_REDOWNLOADED: + const win = BrowserWindow.getFocusedWindow() + if (win) { + win.webContents.downloadURL(download.get('url')) + state = state.deleteIn(['downloads', action.downloadId]) + } else { + shell.beep() + } + break + case appConstants.APP_MERGE_DOWNLOAD_DETAIL: + if (action.downloadDetail) { + state = state.mergeIn(['downloads', action.downloadId], action.downloadDetail) + } else { + state = state.deleteIn(['downloads', action.downloadId]) + } + break + case appConstants.APP_CLEAR_COMPLETED_DOWNLOADS: + if (state.get('downloads')) { + const downloads = state.get('downloads') + .filter((download) => + ![downloadStates.COMPLETED, downloadStates.INTERRUPTED, downloadStates.CANCELLED].includes(download.get('state'))) + state = state.set('downloads', downloads) + } + break + } + return state +} + +module.exports = downloadsReducer diff --git a/js/constants/downloadActions.js b/app/common/constants/electronDownloadItemActions.js similarity index 59% rename from js/constants/downloadActions.js rename to app/common/constants/electronDownloadItemActions.js index 3c662abbe61..48af3c48785 100644 --- a/js/constants/downloadActions.js +++ b/app/common/constants/electronDownloadItemActions.js @@ -2,13 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -const mapValuesByKeys = require('../lib/functional').mapValuesByKeys +const mapValuesByKeys = require('../../../js/lib/functional').mapValuesByKeys const _ = null -const downloadActions = { +const electronDownloadItemActions = { PAUSE: _, RESUME: _, CANCEL: _ } -module.exports = mapValuesByKeys(downloadActions) +module.exports = mapValuesByKeys(electronDownloadItemActions) diff --git a/app/filtering.js b/app/filtering.js index cdb6df8f2d5..77054d25b1a 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -12,7 +12,6 @@ const webContents = electron.webContents const appActions = require('../js/actions/appActions') const appConfig = require('../js/constants/appConfig') const downloadStates = require('../js/constants/downloadStates') -const downloadActions = require('../js/constants/downloadActions') const urlParse = require('url').parse const getBaseDomain = require('../js/lib/baseDomain').getBaseDomain const getSetting = require('../js/settings').getSetting @@ -31,6 +30,7 @@ const uuid = require('node-uuid') const path = require('path') const getOrigin = require('../js/state/siteUtil').getOrigin const {adBlockResourceName} = require('./adBlock') +const {updateElectronDownloadItem} = require('./browser/electronDownloadItem') let appStore = null @@ -46,11 +46,6 @@ const pdfjsOrigin = `chrome-extension://${config.PDFJSExtensionId}` // Third party domains that require a valid referer to work const refererExceptions = ['use.typekit.net', 'cloud.typography.com'] -/** - * Maps downloadId to an electron download-item - */ -const downloadMap = {} - /** * Maps partition name to the session object */ @@ -467,11 +462,7 @@ module.exports.isThirdPartyHost = (baseContextHost, testHost) => { } function updateDownloadState (downloadId, item, state) { - if (state === downloadStates.INTERRUPTED || state === downloadStates.CANCELLED || state === downloadStates.COMPLETED) { - delete downloadMap[downloadId] - } else { - downloadMap[downloadId] = item - } + updateElectronDownloadItem(downloadId, item, state) if (!item) { appActions.mergeDownloadDetail(downloadId, { state: downloadStates.INTERRUPTED }) @@ -602,29 +593,6 @@ module.exports.init = (state, action, store) => { e.returnValue = true return e.returnValue }) - ipcMain.on(messages.DOWNLOAD_ACTION, (e, downloadId, action) => { - const item = downloadMap[downloadId] - switch (action) { - case downloadActions.CANCEL: - updateDownloadState(downloadId, item, downloadStates.CANCELLED) - if (item) { - item.cancel() - } - break - case downloadActions.PAUSE: - if (item) { - item.pause() - } - updateDownloadState(downloadId, item, downloadStates.PAUSED) - break - case downloadActions.RESUME: - if (item) { - item.resume() - } - updateDownloadState(downloadId, item, downloadStates.IN_PROGRESS) - break - } - }) ipcMain.on(messages.NOTIFICATION_RESPONSE, (e, message, buttonIndex, persist) => { if (permissionCallbacks[message]) { permissionCallbacks[message](buttonIndex, persist) diff --git a/app/index.js b/app/index.js index e0d925a2c41..c9abcdece2a 100644 --- a/app/index.js +++ b/app/index.js @@ -52,7 +52,6 @@ const Importer = require('./importer') const messages = require('../js/constants/messages') const appConfig = require('../js/constants/appConfig') const appActions = require('../js/actions/appActions') -const downloadActions = require('../js/actions/downloadActions') const SessionStore = require('./sessionStore') const AppStore = require('../js/stores/appStore') const PackageLoader = require('./package-loader') @@ -490,10 +489,6 @@ app.on('ready', () => { electron.clipboard.writeText(text) }) - ipcMain.on(messages.OPEN_DOWNLOAD_PATH, (e, download) => { - downloadActions.openDownloadPath(Immutable.fromJS(download)) - }) - ipcMain.on(messages.CERT_ERROR_ACCEPTED, (event, url) => { try { let host = urlParse(url).host diff --git a/docs/appActions.md b/docs/appActions.md index 8f52d4397e2..744628cb03c 100644 --- a/docs/appActions.md +++ b/docs/appActions.md @@ -541,6 +541,85 @@ Dispatch a message to copy data URL to clipboard +### shuttingDown() + +Dispatches a message when the app is shutting down. + + + +### downloadRevealed(downloadId) + +Dispatches a message when a download is being revealed. +Typically this will open the download directory in finder / explorer and select the icon. + +**Parameters** + +**downloadId**: `string`, ID of the download being revealed + + + +### downloadOpened(downloadId) + +Dispatches a message when a download is being opened. + +**Parameters** + +**downloadId**: `string`, ID of the download being opened + + + +### downloadActionPerformed(downloadId, downloadAction) + +Dispatches a message when an electron download action is being performed (pause, resume, cancel) + +**Parameters** + +**downloadId**: `string`, ID of the download item the action is being performed to + +**downloadAction**: `string`, the action to perform from constants/electronDownloadItemActions.js + + + +### downloadCopiedToClipboard(downloadId) + +Dispatches a message when a download URL is being copied to the clipboard + +**Parameters** + +**downloadId**: `string`, ID of the download item being copied to the clipboard + + + +### downloadDeleted(downloadId) + +Dispatches a message when a download is being deleted + +**Parameters** + +**downloadId**: `string`, ID of the download item being deleted + + + +### downloadCleared(downloadId) + +Dispatches a message when a download is being cleared + +**Parameters** + +**downloadId**: `string`, ID of the download item being cleared + + + +### downloadRedownloaded(downloadId) + +Dispatches a message when a download is being redownloaded + +**Parameters** + +**downloadId**: `string`, ID of the download item being redownloaded + + + * * * diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js index 4a5e6bab9cf..9e871f0e1d9 100644 --- a/js/about/aboutActions.js +++ b/js/about/aboutActions.js @@ -154,8 +154,11 @@ const aboutActions = { }) }, - openDownloadPath: function (download) { - ipc.send(messages.OPEN_DOWNLOAD_PATH, download.toJS()) + downloadRevealed: function (downloadId) { + aboutActions.dispatchAction({ + actionType: appConstants.APP_DOWNLOAD_REVEALED, + downloadId + }) }, decryptPassword: function (encryptedPassword, authTag, iv, id) { diff --git a/js/about/downloads.js b/js/about/downloads.js index 5d4b1a3577f..ce8fc001681 100644 --- a/js/about/downloads.js +++ b/js/about/downloads.js @@ -29,7 +29,7 @@ class DownloadItem extends ImmutableComponent { className='listItem' onContextMenu={aboutActions.contextMenu.bind(this, contextMenuDownload, 'download')} data-context-menu-disable - onDoubleClick={aboutActions.openDownloadPath.bind(this, this.props.download)}> + onDoubleClick={aboutActions.downloadRevealed.bind(this, this.props.downloadId)}> {
{this.props.download.get('filename')}
diff --git a/js/actions/appActions.js b/js/actions/appActions.js index fc7ddee7b45..b1aa8df48c7 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -4,7 +4,7 @@ 'use strict' const AppDispatcher = require('../dispatcher/appDispatcher') -const AppConstants = require('../constants/appConstants') +const appConstants = require('../constants/appConstants') const appActions = { /** @@ -15,7 +15,7 @@ const appActions = { */ setState: function (appState) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_STATE, + actionType: appConstants.APP_SET_STATE, appState }) }, @@ -29,7 +29,7 @@ const appActions = { */ newWindow: function (frameOpts, browserOpts, restoredState, cb) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_NEW_WINDOW, + actionType: appConstants.APP_NEW_WINDOW, frameOpts, browserOpts, restoredState, @@ -39,28 +39,28 @@ const appActions = { closeWindow: function (windowId) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CLOSE_WINDOW, + actionType: appConstants.APP_CLOSE_WINDOW, windowId }) }, windowClosed: function (windowValue) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_WINDOW_CLOSED, + actionType: appConstants.APP_WINDOW_CLOSED, windowValue }) }, windowCreated: function (windowValue) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_WINDOW_CREATED, + actionType: appConstants.APP_WINDOW_CREATED, windowValue }) }, windowUpdated: function (windowValue) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_WINDOW_UPDATED, + actionType: appConstants.APP_WINDOW_UPDATED, windowValue }) }, @@ -71,7 +71,7 @@ const appActions = { */ newTab: function (frameProps) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_NEW_TAB, + actionType: appConstants.APP_NEW_TAB, frameProps }) }, @@ -82,7 +82,7 @@ const appActions = { */ tabCreated: function (tabValue) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_TAB_CREATED, + actionType: appConstants.APP_TAB_CREATED, tabValue }) }, @@ -93,7 +93,7 @@ const appActions = { */ tabUpdated: function (tabValue) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_TAB_UPDATED, + actionType: appConstants.APP_TAB_UPDATED, tabValue }) }, @@ -104,7 +104,7 @@ const appActions = { */ tabClosed: function (tabValue) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_TAB_CLOSED, + actionType: appConstants.APP_TAB_CLOSED, tabValue }) }, @@ -119,7 +119,7 @@ const appActions = { */ addSite: function (siteDetail, tag, originalSiteDetail, destinationDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_ADD_SITE, + actionType: appConstants.APP_ADD_SITE, siteDetail, tag, originalSiteDetail, @@ -132,7 +132,7 @@ const appActions = { */ clearHistory: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CLEAR_HISTORY + actionType: appConstants.APP_CLEAR_HISTORY }) }, @@ -143,7 +143,7 @@ const appActions = { */ removeSite: function (siteDetail, tag) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_REMOVE_SITE, + actionType: appConstants.APP_REMOVE_SITE, siteDetail, tag }) @@ -160,7 +160,7 @@ const appActions = { */ moveSite: function (sourceDetail, destinationDetail, prepend, destinationIsParent) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_MOVE_SITE, + actionType: appConstants.APP_MOVE_SITE, sourceDetail, destinationDetail, prepend, @@ -176,7 +176,7 @@ const appActions = { */ mergeDownloadDetail: function (downloadId, downloadDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_MERGE_DOWNLOAD_DETAIL, + actionType: appConstants.APP_MERGE_DOWNLOAD_DETAIL, downloadId, downloadDetail }) @@ -187,7 +187,7 @@ const appActions = { */ clearCompletedDownloads: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CLEAR_COMPLETED_DOWNLOADS + actionType: appConstants.APP_CLEAR_COMPLETED_DOWNLOADS }) }, @@ -196,7 +196,7 @@ const appActions = { */ ledgerRecoverySucceeded: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_LEDGER_RECOVERY_SUCCEEDED + actionType: appConstants.APP_LEDGER_RECOVERY_SUCCEEDED }) }, @@ -205,7 +205,7 @@ const appActions = { */ ledgerRecoveryFailed: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_LEDGER_RECOVERY_FAILED + actionType: appConstants.APP_LEDGER_RECOVERY_FAILED }) }, @@ -216,7 +216,7 @@ const appActions = { */ defaultWindowParamsChanged: function (size, position) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED, + actionType: appConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED, size, position }) @@ -231,7 +231,7 @@ const appActions = { */ setResourceETag: function (resourceName, etag) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_DATA_FILE_ETAG, + actionType: appConstants.APP_SET_DATA_FILE_ETAG, resourceName, etag }) @@ -244,7 +244,7 @@ const appActions = { */ setResourceLastCheck: function (resourceName, lastCheckVersion, lastCheckDate) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_DATA_FILE_LAST_CHECK, + actionType: appConstants.APP_SET_DATA_FILE_LAST_CHECK, resourceName, lastCheckVersion, lastCheckDate @@ -258,7 +258,7 @@ const appActions = { */ setResourceEnabled: function (resourceName, enabled) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_RESOURCE_ENABLED, + actionType: appConstants.APP_SET_RESOURCE_ENABLED, resourceName, enabled }) @@ -270,7 +270,7 @@ const appActions = { */ resourceReady: function (resourceName) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_RESOURCE_READY, + actionType: appConstants.APP_RESOURCE_READY, resourceName }) }, @@ -282,7 +282,7 @@ const appActions = { */ addResourceCount: function (resourceName, count) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_ADD_RESOURCE_COUNT, + actionType: appConstants.APP_ADD_RESOURCE_COUNT, resourceName, count }) @@ -294,7 +294,7 @@ const appActions = { */ setUpdateLastCheck: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_UPDATE_LAST_CHECK + actionType: appConstants.APP_UPDATE_LAST_CHECK }) }, @@ -306,7 +306,7 @@ const appActions = { */ setUpdateStatus: function (status, verbose, metadata) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_UPDATE_STATUS, + actionType: appConstants.APP_SET_UPDATE_STATUS, status, verbose, metadata @@ -319,7 +319,7 @@ const appActions = { */ savePassword: function (passwordDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_ADD_PASSWORD, + actionType: appConstants.APP_ADD_PASSWORD, passwordDetail }) }, @@ -330,7 +330,7 @@ const appActions = { */ deletePassword: function (passwordDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_REMOVE_PASSWORD, + actionType: appConstants.APP_REMOVE_PASSWORD, passwordDetail }) }, @@ -340,7 +340,7 @@ const appActions = { */ clearPasswords: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CLEAR_PASSWORDS + actionType: appConstants.APP_CLEAR_PASSWORDS }) }, @@ -351,7 +351,7 @@ const appActions = { */ changeSetting: function (key, value) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CHANGE_SETTING, + actionType: appConstants.APP_CHANGE_SETTING, key, value }) @@ -367,7 +367,7 @@ const appActions = { */ changeSiteSetting: function (hostPattern, key, value, temp) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CHANGE_SITE_SETTING, + actionType: appConstants.APP_CHANGE_SITE_SETTING, hostPattern, key, value, @@ -384,7 +384,7 @@ const appActions = { */ removeSiteSetting: function (hostPattern, key, temp) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_REMOVE_SITE_SETTING, + actionType: appConstants.APP_REMOVE_SITE_SETTING, hostPattern, key, temporary: temp || false @@ -397,7 +397,7 @@ const appActions = { */ updateLedgerInfo: function (ledgerInfo) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_UPDATE_LEDGER_INFO, + actionType: appConstants.APP_UPDATE_LEDGER_INFO, ledgerInfo }) }, @@ -408,7 +408,7 @@ const appActions = { */ updatePublisherInfo: function (publisherInfo) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_UPDATE_PUBLISHER_INFO, + actionType: appConstants.APP_UPDATE_PUBLISHER_INFO, publisherInfo }) }, @@ -419,7 +419,7 @@ const appActions = { */ showMessageBox: function (detail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SHOW_MESSAGE_BOX, + actionType: appConstants.APP_SHOW_MESSAGE_BOX, detail }) }, @@ -430,7 +430,7 @@ const appActions = { */ hideMessageBox: function (message) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_HIDE_MESSAGE_BOX, + actionType: appConstants.APP_HIDE_MESSAGE_BOX, message }) }, @@ -441,7 +441,7 @@ const appActions = { */ clearMessageBoxes: function (origin) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CLEAR_MESSAGE_BOXES, + actionType: appConstants.APP_CLEAR_MESSAGE_BOXES, origin }) }, @@ -453,7 +453,7 @@ const appActions = { */ addWord: function (word, learn) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_ADD_WORD, + actionType: appConstants.APP_ADD_WORD, word, learn }) @@ -465,7 +465,7 @@ const appActions = { */ setDictionary: function (locale) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_DICTIONARY, + actionType: appConstants.APP_SET_DICTIONARY, locale }) }, @@ -477,7 +477,7 @@ const appActions = { */ setLoginRequiredDetail: function (tabId, detail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_LOGIN_REQUIRED_DETAIL, + actionType: appConstants.APP_SET_LOGIN_REQUIRED_DETAIL, tabId, detail }) @@ -485,7 +485,7 @@ const appActions = { setLoginResponseDetail: function (tabId, detail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_LOGIN_RESPONSE_DETAIL, + actionType: appConstants.APP_SET_LOGIN_RESPONSE_DETAIL, tabId, detail }) @@ -497,7 +497,7 @@ const appActions = { */ clearAppData: function (clearDataDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_CLEAR_DATA, + actionType: appConstants.APP_CLEAR_DATA, clearDataDetail }) }, @@ -508,7 +508,7 @@ const appActions = { */ importBrowserData: function (selected) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_IMPORT_BROWSER_DATA, + actionType: appConstants.APP_IMPORT_BROWSER_DATA, selected }) }, @@ -520,7 +520,7 @@ const appActions = { */ addAutofillAddress: function (detail, originalDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_ADD_AUTOFILL_ADDRESS, + actionType: appConstants.APP_ADD_AUTOFILL_ADDRESS, detail, originalDetail }) @@ -532,7 +532,7 @@ const appActions = { */ removeAutofillAddress: function (detail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_REMOVE_AUTOFILL_ADDRESS, + actionType: appConstants.APP_REMOVE_AUTOFILL_ADDRESS, detail }) }, @@ -544,7 +544,7 @@ const appActions = { */ addAutofillCreditCard: function (detail, originalDetail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_ADD_AUTOFILL_CREDIT_CARD, + actionType: appConstants.APP_ADD_AUTOFILL_CREDIT_CARD, detail, originalDetail }) @@ -556,7 +556,7 @@ const appActions = { */ removeAutofillCreditCard: function (detail) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD, + actionType: appConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD, detail }) }, @@ -568,7 +568,7 @@ const appActions = { */ autofillDataChanged: function (addressGuids, creditCardGuids) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_AUTOFILL_DATA_CHANGED, + actionType: appConstants.APP_AUTOFILL_DATA_CHANGED, addressGuids, creditCardGuids }) @@ -582,7 +582,7 @@ const appActions = { */ windowBlurred: function (windowId) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_WINDOW_BLURRED, + actionType: appConstants.APP_WINDOW_BLURRED, windowId: windowId }) }, @@ -593,7 +593,7 @@ const appActions = { */ setMenubarTemplate: function (menubarTemplate) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SET_MENUBAR_TEMPLATE, + actionType: appConstants.APP_SET_MENUBAR_TEMPLATE, menubarTemplate }) }, @@ -604,7 +604,7 @@ const appActions = { */ networkConnected: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_NETWORK_CONNECTED + actionType: appConstants.APP_NETWORK_CONNECTED }) }, @@ -613,7 +613,7 @@ const appActions = { */ networkDisconnected: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_NETWORK_DISCONNECTED + actionType: appConstants.APP_NETWORK_DISCONNECTED }) }, @@ -624,7 +624,7 @@ const appActions = { */ defaultBrowserUpdated: function (useBrave) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_DEFAULT_BROWSER_UPDATED, + actionType: appConstants.APP_DEFAULT_BROWSER_UPDATED, useBrave }) }, @@ -634,7 +634,7 @@ const appActions = { */ defaultBrowserCheckComplete: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE + actionType: appConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE }) }, @@ -643,7 +643,7 @@ const appActions = { */ populateHistory: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_POPULATE_HISTORY + actionType: appConstants.APP_POPULATE_HISTORY }) }, @@ -652,16 +652,99 @@ const appActions = { **/ dataURLCopied: function (dataURL, html, text) { AppDispatcher.dispatch({ - actionType: AppConstants.APP_DATA_URL_COPIED, + actionType: appConstants.APP_DATA_URL_COPIED, dataURL, html, text }) }, + /** + * Dispatches a message when the app is shutting down. + */ shuttingDown: function () { AppDispatcher.dispatch({ - actionType: AppConstants.APP_SHUTTING_DOWN + actionType: appConstants.APP_SHUTTING_DOWN + }) + }, + + /** + * Dispatches a message when a download is being revealed. + * Typically this will open the download directory in finder / explorer and select the icon. + * @param {string} downloadId - ID of the download being revealed + */ + downloadRevealed: function (downloadId) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_REVEALED, + downloadId + }) + }, + + /** + * Dispatches a message when a download is being opened. + * @param {string} downloadId - ID of the download being opened + */ + downloadOpened: function (downloadId) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_OPENED, + downloadId + }) + }, + + /** + * Dispatches a message when an electron download action is being performed (pause, resume, cancel) + * @param {string} downloadId - ID of the download item the action is being performed to + * @param {string} downloadAction - the action to perform from constants/electronDownloadItemActions.js + */ + downloadActionPerformed: function (downloadId, downloadAction) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_ACTION_PERFORMED, + downloadId, + downloadAction + }) + }, + + /** + * Dispatches a message when a download URL is being copied to the clipboard + * @param {string} downloadId - ID of the download item being copied to the clipboard + */ + downloadCopiedToClipboard: function (downloadId) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_COPIED_TO_CLIPBOARD, + downloadId + }) + }, + + /** + * Dispatches a message when a download is being deleted + * @param {string} downloadId - ID of the download item being deleted + */ + downloadDeleted: function (downloadId) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_DELETED, + downloadId + }) + }, + + /** + * Dispatches a message when a download is being cleared + * @param {string} downloadId - ID of the download item being cleared + */ + downloadCleared: function (downloadId) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_CLEARED, + downloadId + }) + }, + + /** + * Dispatches a message when a download is being redownloaded + * @param {string} downloadId - ID of the download item being redownloaded + */ + downloadRedownloaded: function (downloadId) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_DOWNLOAD_REDOWNLOADED, + downloadId }) } } diff --git a/js/actions/downloadActions.js b/js/actions/downloadActions.js deleted file mode 100644 index d22a8bb4bef..00000000000 --- a/js/actions/downloadActions.js +++ /dev/null @@ -1,85 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict' - -const electron = require('electron') - -let shell, ipc, clipboard, getCurrentWebContents -if (process.type === 'browser') { - shell = electron.shell - ipc = electron.ipcRenderer - clipboard = electron.clipboard - getCurrentWebContents = electron.getCurrentWebContents -} else { - shell = electron.remote.shell - ipc = electron.ipcRenderer - clipboard = electron.remote.clipboard - getCurrentWebContents = electron.remote.getCurrentWebContents -} - -const appDownloadActions = require('../constants/downloadActions') -const appActions = require('../actions/appActions') -const messages = require('../constants/messages') -// const fs = require('fs') -// const path = require('path') - -/** - * Creates an action function for the specified app download action - * @param {string} appDownloadAction - The ID of the app action to send - */ -const appActionForDownload = (appDownloadAction) => (downloadId) => - ipc.send(messages.DOWNLOAD_ACTION, downloadId, appDownloadAction) - -const downloadActions = { - cancelDownload: appActionForDownload(appDownloadActions.CANCEL), - pauseDownload: appActionForDownload(appDownloadActions.PAUSE), - resumeDownload: appActionForDownload(appDownloadActions.RESUME), - copyLinkToClipboard: function (download) { - clipboard.writeText(download.get('url')) - // disabling notificiations from the main window until we have a - // better way to do it - // void new window.Notification(locale.translation('urlCopied')) - }, - openDownloadPath: function (download) { - // fs.exists(download.get('savePath'), (exists) => { - // if (exists) { - // shell.openItem(download.get('savePath')) - // } else { - // shell.beep() - // } - // }) - }, - locateShellPath: function (download) { - // fs.exists(download.get('savePath'), (exists) => { - // if (exists) { - // shell.showItemInFolder(download.get('savePath')) - // } else { - // shell.openItem(path.dirname(download.get('savePath'))) - // } - // }) - }, - hideDownloadsToolbar: function () { - if (process.type === 'renderer') { - const windowActions = require('../actions/windowActions') - windowActions.setDownloadsToolbarVisible(false) - } - }, - deleteDownload: function (downloads, download, downloadId) { - shell.moveItemToTrash(download.get('savePath')) - downloadActions.clearDownload(downloads, downloadId) - }, - clearDownload: function (downloads, downloadId) { - if (downloads && downloads.size === 1) { - downloadActions.hideDownloadsToolbar() - } - appActions.mergeDownloadDetail(downloadId) - }, - redownloadURL: function (download, downloadId) { - getCurrentWebContents().downloadURL(download.get('url')) - downloadActions.clearDownload(undefined, downloadId) - } -} - -module.exports = downloadActions diff --git a/js/components/downloadsBar.js b/js/components/downloadsBar.js index 3123163eb57..56899af1100 100644 --- a/js/components/downloadsBar.js +++ b/js/components/downloadsBar.js @@ -7,11 +7,46 @@ const ImmutableComponent = require('./immutableComponent') const Button = require('./button') const contextMenus = require('../contextMenus') const downloadStates = require('../constants/downloadStates') -const downloadActions = require('../actions/downloadActions') +const {PAUSE, RESUME, CANCEL} = require('../../app/common/constants/electronDownloadItemActions') +const appActions = require('../actions/appActions') +const windowActions = require('../actions/windowActions') const downloadUtil = require('../state/downloadUtil') const cx = require('../lib/classSet') class DownloadItem extends ImmutableComponent { + constructor () { + super() + this.onRevealDownload = this.onRevealDownload.bind(this) + this.onOpenDownload = this.onOpenDownload.bind(this) + this.onPauseDownload = this.onDownloadActionPerformed.bind(this, PAUSE) + this.onResumeDownload = this.onDownloadActionPerformed.bind(this, RESUME) + this.onCancelDownload = this.onDownloadActionPerformed.bind(this, CANCEL) + this.onClearDownload = this.onClearDownload.bind(this) + this.onDeleteDownload = this.onDeleteDownload.bind(this) + this.onRedownload = this.onRedownload.bind(this) + this.onCopyLinkToClipboard = this.onCopyLinkToClipboard.bind(this) + } + onRevealDownload () { + appActions.downloadRevealed(this.props.downloadId) + } + onOpenDownload () { + appActions.downloadOpened(this.props.downloadId) + } + onClearDownload () { + appActions.downloadCleared(this.props.downloadId) + } + onDeleteDownload () { + appActions.downloadDeleted(this.props.downloadId) + } + onDownloadActionPerformed (downloadAction) { + appActions.downloadActionPerformed(this.props.downloadId, downloadAction) + } + onCopyLinkToClipboard () { + appActions.downloadCopiedToClipboard(this.props.downloadId) + } + onRedownload () { + appActions.downloadRedownloaded(this.props.downloadId) + } get isInterrupted () { return this.props.download.get('state') === downloadStates.INTERRUPTED } @@ -39,7 +74,7 @@ class DownloadItem extends ImmutableComponent { } return { downloadUtil.shouldAllowPause(this.props.download) - ?
@@ -112,6 +147,13 @@ class DownloadItem extends ImmutableComponent { } class DownloadsBar extends ImmutableComponent { + constructor () { + super() + this.onHideDownloadsToolbar = this.onHideDownloadsToolbar.bind(this) + } + onHideDownloadsToolbar () { + windowActions.setDownloadsToolbarVisible(false) + } render () { const downloadItemWidth = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-item-width'), 10) const downloadItemMargin = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-item-margin'), 10) @@ -135,7 +177,7 @@ class DownloadsBar extends ImmutableComponent {
} diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 65979266f61..60d3d2e10a0 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -73,7 +73,14 @@ const AppConstants = { APP_POPULATE_HISTORY: _, APP_RENDER_URL_TO_PDF: _, APP_DATA_URL_COPIED: _, - APP_SHUTTING_DOWN: _ + APP_SHUTTING_DOWN: _, + APP_DOWNLOAD_REVEALED: _, + APP_DOWNLOAD_OPENED: _, + APP_DOWNLOAD_ACTION_PERFORMED: _, + APP_DOWNLOAD_COPIED_TO_CLIPBOARD: _, + APP_DOWNLOAD_DELETED: _, + APP_DOWNLOAD_CLEARED: _, + APP_DOWNLOAD_REDOWNLOADED: _ } module.exports = mapValuesByKeys(AppConstants) diff --git a/js/constants/messages.js b/js/constants/messages.js index 7430b4fcca0..e5265dc1a67 100644 --- a/js/constants/messages.js +++ b/js/constants/messages.js @@ -112,7 +112,6 @@ const messages = { NEWTAB_DATA_UPDATED: _, VERSION_INFORMATION_UPDATED: _, // About pages from contentScript - OPEN_DOWNLOAD_PATH: _, RELOAD_URL: _, DISPATCH_ACTION: _, CHECK_FLASH_INSTALLED: _, diff --git a/js/contextMenus.js b/js/contextMenus.js index e44bc026187..318a0ea43a1 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -12,9 +12,9 @@ const windowStore = require('./stores/windowStore') const windowActions = require('./actions/windowActions') const webviewActions = require('./actions/webviewActions') const bookmarkActions = require('./actions/bookmarkActions') -const downloadActions = require('./actions/downloadActions') const appActions = require('./actions/appActions') const siteTags = require('./constants/siteTags') +const electronDownloadItemActions = require('../app/common/constants/electronDownloadItemActions') const dragTypes = require('./constants/dragTypes') const siteUtil = require('./state/siteUtil') const downloadUtil = require('./state/downloadUtil') @@ -145,60 +145,59 @@ function downloadsToolbarTemplateInit (downloadId, downloadItem) { const template = [] if (downloadItem) { - const downloads = appStoreRenderer.state.get('downloads') if (downloadUtil.shouldAllowPause(downloadItem)) { template.push({ label: locale.translation('downloadItemPause'), - click: downloadActions.pauseDownload.bind(null, downloadId) + click: appActions.downloadActionPerformed.bind(null, downloadId, electronDownloadItemActions.PAUSE) }) } if (downloadUtil.shouldAllowResume(downloadItem)) { template.push({ label: locale.translation('downloadItemResume'), - click: downloadActions.resumeDownload.bind(null, downloadId) + click: appActions.downloadActionPerformed.bind(null, downloadId, electronDownloadItemActions.RESUME) }) } if (downloadUtil.shouldAllowCancel(downloadItem)) { template.push({ label: locale.translation('downloadItemCancel'), - click: downloadActions.cancelDownload.bind(null, downloadId) + click: appActions.downloadActionPerformed.bind(null, downloadId, electronDownloadItemActions.CANCEL) }) } if (downloadUtil.shouldAllowRedownload(downloadItem)) { template.push({ label: locale.translation('downloadItemRedownload'), - click: downloadActions.redownloadURL.bind(null, downloadItem, downloadId) + click: appActions.downloadRedownloaded.bind(null, downloadId) }) } if (downloadUtil.shouldAllowCopyLink(downloadItem)) { template.push({ label: locale.translation('downloadItemCopyLink'), - click: downloadActions.copyLinkToClipboard.bind(null, downloadItem) + click: appActions.downloadCopiedToClipboard.bind(null, downloadId) }) } if (downloadUtil.shouldAllowOpenDownloadLocation(downloadItem)) { template.push({ label: locale.translation('downloadItemPath'), - click: downloadActions.locateShellPath.bind(null, downloadItem) + click: appActions.downloadRevealed.bind(null, downloadId) }) } if (downloadUtil.shouldAllowDelete(downloadItem)) { template.push({ label: locale.translation('downloadItemDelete'), - click: downloadActions.deleteDownload.bind(null, downloads, downloadItem, downloadId) + click: appActions.downloadDeleted.bind(null, downloadId) }) } if (downloadUtil.shouldAllowRemoveFromList(downloadItem)) { template.push({ label: locale.translation('downloadItemClear'), - click: downloadActions.clearDownload.bind(null, downloads, downloadId) + click: appActions.downloadCleared.bind(null, downloadId) }) } } diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 43ecd182fef..eda76ff7d50 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -17,7 +17,6 @@ const app = electron.app const ipcMain = electron.ipcMain const messages = require('../constants/messages') const UpdateStatus = require('../constants/updateStatus') -const downloadStates = require('../constants/downloadStates') const BrowserWindow = electron.BrowserWindow const LocalShortcuts = require('../../app/localShortcuts') const appActions = require('../actions/appActions') @@ -36,6 +35,7 @@ const Filtering = require('../../app/filtering') const basicAuth = require('../../app/browser/basicAuth') const tabs = require('../../app/browser/tabs') const windows = require('../../app/browser/windows') +const downloadsReducer = require('../../app/browser/reducers/downloadsReducer') // state helpers const basicAuthState = require('../../app/common/state/basicAuthState') @@ -361,6 +361,8 @@ const handleAppAction = (action) => { const ledger = require('../../app/ledger') + appState = downloadsReducer(appState, action) + switch (action.actionType) { case AppConstants.APP_SET_STATE: appState = action.appState @@ -498,21 +500,6 @@ const handleAppAction = (action) => { case AppConstants.APP_MOVE_SITE: appState = appState.set('sites', siteUtil.moveSite(appState.get('sites'), action.sourceDetail, action.destinationDetail, action.prepend, action.destinationIsParent, false)) break - case AppConstants.APP_MERGE_DOWNLOAD_DETAIL: - if (action.downloadDetail) { - appState = appState.mergeIn(['downloads', action.downloadId], action.downloadDetail) - } else { - appState = appState.deleteIn(['downloads', action.downloadId]) - } - break - case AppConstants.APP_CLEAR_COMPLETED_DOWNLOADS: - if (appState.get('downloads')) { - const downloads = appState.get('downloads') - .filter((download) => - ![downloadStates.COMPLETED, downloadStates.INTERRUPTED, downloadStates.CANCELLED].includes(download.get('state'))) - appState = appState.set('downloads', downloads) - } - break case AppConstants.APP_CLEAR_HISTORY: appState = appState.set('sites', siteUtil.clearHistory(appState.get('sites'))) appState = aboutNewTabState.setSites(appState, action) diff --git a/package.json b/package.json index dc0058c58fc..3490d3bb0d5 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,7 @@ "nsp": "^2.2.0", "pre-commit": "brave/pre-commit", "react-addons-perf": "^15.2.1", + "sinon": "^1.17.6", "spectron": "brave/spectron#chromium54", "sqlite3": "^3.1.1", "standard": "8.1.0", diff --git a/test/unit/app/browser/reducers/downloadsReducerTest.js b/test/unit/app/browser/reducers/downloadsReducerTest.js new file mode 100644 index 00000000000..1248b26cc63 --- /dev/null +++ b/test/unit/app/browser/reducers/downloadsReducerTest.js @@ -0,0 +1,237 @@ +/* global describe, it, before, after, beforeEach */ +const mockery = require('mockery') +const sinon = require('sinon') +const Immutable = require('immutable') +const process = require('process') +const assert = require('assert') +const uuid = require('uuid') +const path = require('path') +const fakeElectron = require('../../../lib/fakeElectron') + +const appConstants = require('../../../../../js/constants/appConstants') +const {PENDING, IN_PROGRESS, RESUMING, PAUSED, COMPLETED, CANCELLED, INTERRUPTED} = require('../../../../../js/constants/downloadStates') +const {CANCEL, PAUSE, RESUME} = require('../../../../../app/common/constants/electronDownloadItemActions') +require('../../../braveUnit') + +const downloadId = (state, i = 0) => Object.keys(state.get('downloads').toJS())[i] +const downloadUrl = 'http://www.bradrichter.com/mostHatedPrimes.txt' +const savePath = path.join(require('os').tmpdir(), 'mostHatedPrimes.txt') +const oneDownloadWithState = (state) => Immutable.fromJS({ + downloads: { + [uuid.v4()]: { + startTime: new Date().getTime(), + filename: 'mostHatedPrimes.txt', + savePath, + url: downloadUrl, + totalBytes: 104729, + receivedBytes: 96931, + state + } + } +}) + +describe('downloadsReducer', function () { + let downloadsReducer + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + mockery.registerMock('electron', fakeElectron) + downloadsReducer = require('../../../../../app/browser/reducers/downloadsReducer') + }) + + beforeEach(function () { + }) + + after(function () { + mockery.disable() + }) + + it('returns original state for unhandled actions', function () { + const oldState = oneDownloadWithState(IN_PROGRESS) + const newState = downloadsReducer(oldState, {actionType: uuid.v4()}) + assert.deepEqual(newState.toJS(), oldState.toJS()) + }) + + describe('APP_DOWNLOAD_REVEALED', function () { + it('Reveals file for paths that does not exist exist', function (cb) { + sinon.stub(fakeElectron.shell, 'showItemInFolder', (path) => { + fakeElectron.shell.showItemInFolder.restore() + assert.equal(path, process.cwd()) + cb() + }) + let oldState = oneDownloadWithState(IN_PROGRESS) + oldState = oldState.setIn(['downloads', downloadId(oldState), 'savePath'], process.cwd()) + downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_REVEALED, downloadId: downloadId(oldState)}) + }) + it('Reveals file for paths that does not exist exist', function (cb) { + const saveDir = path.dirname(savePath) + sinon.stub(fakeElectron.shell, 'openItem', (path) => { + fakeElectron.shell.openItem.restore() + assert.equal(path, saveDir) + cb() + }) + const oldState = oneDownloadWithState(IN_PROGRESS) + downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_REVEALED, downloadId: downloadId(oldState)}) + }) + }) + + describe('APP_DOWNLOAD_OPENED', function () { + it('Opens a downloaded file', function (cb) { + sinon.stub(fakeElectron.shell, 'openItem', (path) => { + fakeElectron.shell.openItem.restore() + assert.equal(path, process.cwd()) + cb() + }) + let oldState = oneDownloadWithState(IN_PROGRESS) + oldState = oldState.setIn(['downloads', downloadId(oldState), 'savePath'], process.cwd()) + downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_OPENED, downloadId: downloadId(oldState)}) + }) + it('Beeps when a downloaded file is trying to be opened', function (cb) { + sinon.stub(fakeElectron.shell, 'beep', () => { + fakeElectron.shell.beep.restore() + cb() + }) + const oldState = oneDownloadWithState(IN_PROGRESS) + downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_OPENED, downloadId: downloadId(oldState)}) + }) + }) + + describe('APP_DOWNLOAD_ACTION_PERFORMED', function () { + it('CANCEL causes CANCELLED state', function () { + const oldState = oneDownloadWithState(IN_PROGRESS) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_ACTION_PERFORMED, downloadId: downloadId(oldState), downloadAction: CANCEL}) + assert.equal(newState.getIn(['downloads', downloadId(oldState), 'state']), CANCELLED) + }) + it('PAUSE causes PAUSED state', function () { + const oldState = oneDownloadWithState(IN_PROGRESS) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_ACTION_PERFORMED, downloadId: downloadId(oldState), downloadAction: PAUSE}) + assert.equal(newState.getIn(['downloads', downloadId(oldState), 'state']), PAUSED) + }) + it('RESUME causes an IN_PROGRESS state', function () { + const oldState = oneDownloadWithState(PAUSED) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_ACTION_PERFORMED, downloadId: downloadId(oldState), downloadAction: RESUME}) + assert.equal(newState.getIn(['downloads', downloadId(oldState), 'state']), IN_PROGRESS) + }) + }) + + describe('APP_DOWNLOAD_COPIED_TO_CLIPBOARD', function () { + it('copies the download URL to the clipboard', function () { + const spy = sinon.spy(fakeElectron.clipboard, 'writeText') + spy.withArgs(downloadUrl) + const oldState = oneDownloadWithState(IN_PROGRESS) + downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_COPIED_TO_CLIPBOARD, downloadId: downloadId(oldState)}) + assert(spy.withArgs(downloadUrl).calledOnce) + }) + }) + + describe('APP_DOWNLOAD_DELETED', function () { + it('deletes a downloadId that exists', function (cb) { + let oldState = oneDownloadWithState(IN_PROGRESS) + const existingPath = process.cwd() + oldState = oldState.setIn(['downloads', downloadId(oldState), 'savePath'], existingPath) + sinon.stub(fakeElectron.shell, 'moveItemToTrash', (path) => { + assert.equal(path, existingPath) + fakeElectron.shell.moveItemToTrash.restore() + cb() + }) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_DELETED, downloadId: downloadId(oldState)}) + assert.equal(Object.keys(newState.get('downloads').toJS()).length, 0) + }) + it('does nothing for a downloadId that does not exist', function () { + const oldState = oneDownloadWithState(IN_PROGRESS) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_DELETED, downloadId: uuid.v4()}) + assert.deepEqual(newState.toJS(), oldState.toJS()) + }) + }) + + describe('APP_DOWNLOAD_CLEARED', function () { + it('clears download item', function () { + const oldState = oneDownloadWithState(IN_PROGRESS) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_DELETED, downloadId: downloadId(oldState)}) + assert.equal(Object.keys(newState.get('downloads').toJS()).length, 0) + }) + it('does nothing for a downloadId that does not exist', function () { + const oldState = oneDownloadWithState(IN_PROGRESS) + const newState = downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_DELETED, downloadId: uuid.v4()}) + assert.deepEqual(newState.toJS(), oldState.toJS()) + }) + }) + + describe('APP_DOWNLOAD_REDOWNLOADED', function () { + it('should redownload the same URL', function (cb) { + const win = { + webContents: { + downloadURL: function () { + } + } + } + sinon.stub(win.webContents, 'downloadURL', (redownloadUrl) => { + assert.equal(redownloadUrl, downloadUrl) + cb() + }) + sinon.stub(fakeElectron.BrowserWindow, 'getFocusedWindow', (path) => { + return win + }) + const oldState = oneDownloadWithState(CANCELLED) + downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_REDOWNLOADED, downloadId: downloadId(oldState)}) + }) + }) + + describe('APP_MERGE_DOWNLOAD_DETAIL', function () { + it('should update downloads', function () { + const oldState = oneDownloadWithState(PENDING) + const newState = downloadsReducer(oldState, + { + actionType: appConstants.APP_MERGE_DOWNLOAD_DETAIL, + downloadId: downloadId(oldState), + downloadDetail: {state: COMPLETED} + } + ) + assert.equal(newState.getIn(['downloads', downloadId(oldState), 'state']), COMPLETED) + }) + it('should not update for invalid download Ids', function () { + const oldState = oneDownloadWithState(PENDING) + const newState = downloadsReducer(oldState, + { + actionType: appConstants.APP_MERGE_DOWNLOAD_DETAIL, + downloadId: uuid.v4(), + downloadDetail: {state: COMPLETED} + } + ) + assert.equal(newState.getIn(['downloads', downloadId(oldState), 'state']), PENDING) + }) + it('should add new download IDs as needed', function () { + const oldState = oneDownloadWithState(PENDING) + const downloadId = uuid.v4() + const newState = downloadsReducer(oldState, + { + actionType: appConstants.APP_MERGE_DOWNLOAD_DETAIL, + downloadId, + downloadDetail: {state: COMPLETED} + } + ) + assert.equal(newState.getIn(['downloads', downloadId, 'state']), COMPLETED) + assert.equal(Object.keys(newState.get('downloads').toJS()).length, 2) + }) + }) + + describe('APP_CLEAR_COMPLETED_DOWNLOADS', function () { + it('should clear completed downloads', function () { + const states = [COMPLETED, CANCELLED, INTERRUPTED] + states.forEach((state) => { + const newState = downloadsReducer(oneDownloadWithState(state), {actionType: appConstants.APP_CLEAR_COMPLETED_DOWNLOADS}) + assert.equal(Object.keys(newState.get('downloads').toJS()).length, 0) + }) + }) + it('should not clear downloads when they are still in progress', function () { + const states = [PENDING, IN_PROGRESS, RESUMING, PAUSED] + states.forEach((state) => { + const newState = downloadsReducer(oneDownloadWithState(state), {actionType: appConstants.APP_CLEAR_COMPLETED_DOWNLOADS}) + assert.equal(Object.keys(newState.get('downloads').toJS()).length, 1) + }) + }) + }) +}) diff --git a/test/unit/lib/fakeElectron.js b/test/unit/lib/fakeElectron.js index 3db52fc9458..2e4d444f6c6 100644 --- a/test/unit/lib/fakeElectron.js +++ b/test/unit/lib/fakeElectron.js @@ -1,4 +1,7 @@ const fakeElectron = { + BrowserWindow: { + getFocusedWindow: function () {} + }, ipcMain: { on: function () { } }, @@ -11,6 +14,21 @@ const fakeElectron = { app: { on: function () { } + }, + clipboard: { + writeText: function () { + } + }, + shell: { + showItemInFolder: function () { + }, + openItem: function () { + }, + beep: function () { + }, + moveItemToTrash: function () { + } } } + module.exports = fakeElectron diff --git a/tools/lib/ignoredPaths.js b/tools/lib/ignoredPaths.js index d1c751995bf..abefdc84a4b 100644 --- a/tools/lib/ignoredPaths.js +++ b/tools/lib/ignoredPaths.js @@ -36,6 +36,7 @@ module.exports = [ '.github', 'jsdoc', 'docs', + 'sinon', 'electron-download', 'electron-rebuild', 'electron-packager', From 95b1e32fe6553a4d42c4b106541d8d440fd68762 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Sun, 4 Dec 2016 23:09:24 -0500 Subject: [PATCH 37/80] Fix clean script Auditors: @bridiver --- tools/lib/utilApp/index.js | 1 - tools/utilAppRunner.js | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/lib/utilApp/index.js b/tools/lib/utilApp/index.js index 963c1b8ecc0..59ac0f1e976 100644 --- a/tools/lib/utilApp/index.js +++ b/tools/lib/utilApp/index.js @@ -3,7 +3,6 @@ const electron = require('electron') const app = electron.app app.setName('brave') -require('../../../app/browser/lib/patchUserDataDir') const path = require('path') const rimraf = require('../rimraf') diff --git a/tools/utilAppRunner.js b/tools/utilAppRunner.js index bcfb70ac792..42004e04e64 100644 --- a/tools/utilAppRunner.js +++ b/tools/utilAppRunner.js @@ -12,6 +12,9 @@ function runUtilApp (cmd, file, stdioOptions) { stdio: stdioOptions } cmd = cmd.split(' ') + if (process.env.NODE_ENV === 'development') { + cmd.push('--user-data-dir=brave-development') + } const utilApp = proc.spawnSync('electron', [utilAppDir].concat(cmd), options) if (utilApp.error) { console.log('Could not run utilApp - run `npm install electron-prebuilt` and try again', utilApp.error) From 33965fce9a889fc829ee4e17383dec7d633c29a6 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Mon, 5 Dec 2016 16:30:13 +0800 Subject: [PATCH 38/80] Enable swiping back/forward and disable system setting of swipe check for now Auditors: @bridiver, @bsclifton --- js/components/main.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/js/components/main.js b/js/components/main.js index bc3c81da036..ade0973465e 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -206,7 +206,7 @@ class Main extends ImmutableComponent { registerSwipeListener () { // Navigates back/forward on macOS two-finger swipe var trackingFingers = false - // var swipeGesture = false + var swipeGesture = false var isSwipeOnEdge = false var deltaX = 0 var deltaY = 0 @@ -247,18 +247,19 @@ class Main extends ImmutableComponent { } }) ipc.on(messages.ENABLE_SWIPE_GESTURE, (e) => { - // swipeGesture = true + swipeGesture = true }) ipc.on(messages.DISABLE_SWIPE_GESTURE, (e) => { - // swipeGesture = false + swipeGesture = false }) ipc.on('scroll-touch-begin', function () { - // if (swipeGesture && - // systemPreferences.isSwipeTrackingFromScrollEventsEnabled()) { - // trackingFingers = true - // isSwipeOnEdge = false - // startTime = (new Date()).getTime() - // } + if (swipeGesture) { + // TODO(Anthony): respecting system settings on cr54 + // systemPreferences.isSwipeTrackingFromScrollEventsEnabled()) { + trackingFingers = true + isSwipeOnEdge = false + startTime = (new Date()).getTime() + } }) ipc.on('scroll-touch-end', function () { if (time > 50 && trackingFingers && Math.abs(deltaY) < 50 && isSwipeOnEdge) { From f9ca52fbc5bf431bd81dc7991cc258ec85872546 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 5 Dec 2016 19:56:48 -0500 Subject: [PATCH 39/80] Fix shields down crashing Brave Fix #6034 Auditors: @bridiver --- js/state/siteSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/state/siteSettings.js b/js/state/siteSettings.js index 6e67bbb73eb..ca3fde9bce3 100644 --- a/js/state/siteSettings.js +++ b/js/state/siteSettings.js @@ -50,7 +50,7 @@ module.exports.activeSettings = (siteSettings, appState, appConfig) => { Object.keys(appConfig.resourceNames).forEach((resourceName) => { let name = appConfig.resourceNames[resourceName] settings[name] = (() => { - if (settings.shieldsUp === false && appConfig[resourceName].shields !== false) { + if (settings.shieldsUp === false && appConfig[name].shields !== false) { return false } From a540f2bb8e90cff504513a57da4a2d36f9172cea Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 7 Dec 2016 11:19:00 -0500 Subject: [PATCH 40/80] Add React unit tests for downloads Audtors: @bsclifton --- .../renderer/components/downloadItem.js | 70 +++------- app/renderer/components/downloadsBar.js | 50 +++++++ js/components/main.js | 2 +- package.json | 2 + test/unit/app/renderer/downloadItemTest.js | 124 ++++++++++++++++++ .../unit/app/renderer/downloadsToolbarTest.js | 115 ++++++++++++++++ test/unit/lib/fakeElectron.js | 6 + tools/lib/ignoredPaths.js | 2 + 8 files changed, 316 insertions(+), 55 deletions(-) rename js/components/downloadsBar.js => app/renderer/components/downloadItem.js (59%) create mode 100644 app/renderer/components/downloadsBar.js create mode 100644 test/unit/app/renderer/downloadItemTest.js create mode 100644 test/unit/app/renderer/downloadsToolbarTest.js diff --git a/js/components/downloadsBar.js b/app/renderer/components/downloadItem.js similarity index 59% rename from js/components/downloadsBar.js rename to app/renderer/components/downloadItem.js index 56899af1100..9d3e948bca9 100644 --- a/js/components/downloadsBar.js +++ b/app/renderer/components/downloadItem.js @@ -3,15 +3,14 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ const React = require('react') -const ImmutableComponent = require('./immutableComponent') -const Button = require('./button') -const contextMenus = require('../contextMenus') -const downloadStates = require('../constants/downloadStates') -const {PAUSE, RESUME, CANCEL} = require('../../app/common/constants/electronDownloadItemActions') -const appActions = require('../actions/appActions') -const windowActions = require('../actions/windowActions') -const downloadUtil = require('../state/downloadUtil') -const cx = require('../lib/classSet') +const ImmutableComponent = require('../../../js/components/immutableComponent') +const Button = require('../../../js/components/button') +const contextMenus = require('../../../js/contextMenus') +const downloadStates = require('../../../js/constants/downloadStates') +const {PAUSE, RESUME, CANCEL} = require('../../common/constants/electronDownloadItemActions') +const appActions = require('../../../js/actions/appActions') +const downloadUtil = require('../../../js/state/downloadUtil') +const cx = require('../../../js/lib/classSet') class DownloadItem extends ImmutableComponent { constructor () { @@ -82,37 +81,37 @@ class DownloadItem extends ImmutableComponent {
{ downloadUtil.shouldAllowPause(this.props.download) - ?
-
- } -} - -module.exports = DownloadsBar +module.exports = DownloadItem diff --git a/app/renderer/components/downloadsBar.js b/app/renderer/components/downloadsBar.js new file mode 100644 index 00000000000..2e520c6648e --- /dev/null +++ b/app/renderer/components/downloadsBar.js @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const React = require('react') +const ImmutableComponent = require('../../../js/components/immutableComponent') +const Button = require('../../../js/components/button') +const contextMenus = require('../../../js/contextMenus') +const windowActions = require('../../../js/actions/windowActions') +const DownloadItem = require('./downloadItem') + +class DownloadsBar extends ImmutableComponent { + constructor () { + super() + this.onHideDownloadsToolbar = this.onHideDownloadsToolbar.bind(this) + } + onHideDownloadsToolbar () { + windowActions.setDownloadsToolbarVisible(false) + } + render () { + const downloadItemWidth = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-item-width'), 10) + const downloadItemMargin = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-item-margin'), 10) + const downloadBarPadding = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-bar-padding'), 10) + const downloadBarButtons = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-bar-buttons'), 10) + const numItems = Math.floor((this.props.windowWidth - (downloadBarPadding * 2) - downloadBarButtons) / (downloadItemWidth + downloadItemMargin)) + return
+
+ { + this.props.downloads + .sort((x, y) => x.get('startTime') - y.get('startTime')) + .skip(this.props.downloads.size - numItems) + .reverse() + .map((download, downloadId) => + ) + } +
+
+
+
+ } +} + +module.exports = DownloadsBar diff --git a/js/components/main.js b/js/components/main.js index ade0973465e..c8fab0c55f8 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -24,7 +24,7 @@ const TabsToolbar = require('./tabsToolbar') const FindBar = require('./findbar') const UpdateBar = require('./updateBar') const NotificationBar = require('./notificationBar') -const DownloadsBar = require('./downloadsBar') +const DownloadsBar = require('../../app/renderer/components/downloadsBar') const Button = require('./button') const BrowserActionButton = require('../../app/renderer/components/browserActionButton') const SiteInfo = require('./siteInfo') diff --git a/package.json b/package.json index 3490d3bb0d5..ec5e1497937 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "electron-builder": "^2.3.1", "electron-packager": "brave/electron-packager", "empty-port": "0.0.2", + "enzyme": "^2.6.0", "flow-bin": "^0.22.1", "gulp": "^3.9.0", "jsdom": "9.4.1", @@ -161,6 +162,7 @@ "nsp": "^2.2.0", "pre-commit": "brave/pre-commit", "react-addons-perf": "^15.2.1", + "react-addons-test-utils": "^15.4.1", "sinon": "^1.17.6", "spectron": "brave/spectron#chromium54", "sqlite3": "^3.1.1", diff --git a/test/unit/app/renderer/downloadItemTest.js b/test/unit/app/renderer/downloadItemTest.js new file mode 100644 index 00000000000..d2eaaf69e7e --- /dev/null +++ b/test/unit/app/renderer/downloadItemTest.js @@ -0,0 +1,124 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* global describe, before, after, it */ + +const mockery = require('mockery') +const {mount} = require('enzyme') +const assert = require('assert') +const sinon = require('sinon') +const fakeElectron = require('../../lib/fakeElectron') +const path = require('path') +const uuid = require('uuid') +const Immutable = require('immutable') +const downloadStates = require('../../../../js/constants/downloadStates') +const {CANCEL, PAUSE, RESUME} = require('../../../../app/common/constants/electronDownloadItemActions') +let DownloadItem, appActions +require('../../braveUnit') + +const savePath = path.join(require('os').tmpdir(), 'mostHatedPrimes.txt') +const downloadUrl = 'http://www.bradrichter.com/mostHatedPrimes.txt' +const newDownload = (state) => Immutable.fromJS({ + startTime: new Date().getTime(), + filename: 'mostHatedPrimes.txt', + savePath, + url: downloadUrl, + totalBytes: 104729, + receivedBytes: 96931, + state +}) + +describe('downloadItem component', function () { + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + mockery.registerMock('electron', fakeElectron) + DownloadItem = require('../../../../app/renderer/components/downloadItem') + appActions = require('../../../../js/actions/appActions') + }) + after(function () { + mockery.disable() + }) + + Object.values(downloadStates).forEach(function (state) { + describe(`${state} download item`, function () { + before(function () { + this.downloadId = uuid.v4() + this.download = newDownload(state) + this.result = mount() + }) + + const shouldProgressBarExist = [downloadStates.IN_PROGRESS, downloadStates.PAUSED].includes(state) + it('filename exists and matches download filename', function () { + assert.equal(this.result.find('.downloadFilename').text(), this.download.get('filename')) + }) + it(shouldProgressBarExist ? 'progress bar should exist' : 'progress bar should not exist', function () { + assert.equal(this.result.find('.downloadProgress').length, shouldProgressBarExist ? 1 : 0) + }) + + const testButton = function (buttonSelector, allowedStates, allowedFn) { + const exists = allowedStates.includes(state) + it(exists ? `${buttonSelector} button in state ${state} performs the correct action` : `${buttonSelector} is not shown`, function () { + const button = this.result.find(buttonSelector) + if (exists) { + allowedFn.call(this, button) + } else { + assert.equal(button.length, 0) + } + }) + } + + testButton('.pauseButton', [downloadStates.IN_PROGRESS], function (button) { + const spy = sinon.spy(appActions, 'downloadActionPerformed') + button.simulate('click') + assert(spy.withArgs(this.downloadId, PAUSE).calledOnce) + appActions.downloadActionPerformed.restore() + }) + + testButton('.resumeButton', [downloadStates.PAUSED], function (button) { + const spy = sinon.spy(appActions, 'downloadActionPerformed') + button.simulate('click') + assert(spy.withArgs(this.downloadId, RESUME).calledOnce) + appActions.downloadActionPerformed.restore() + }) + + testButton('.cancelButton', [downloadStates.IN_PROGRESS, downloadStates.PAUSED], function (button) { + const spy = sinon.spy(appActions, 'downloadActionPerformed') + button.simulate('click') + assert(spy.withArgs(this.downloadId, CANCEL).calledOnce) + appActions.downloadActionPerformed.restore() + }) + + testButton('.redownloadButton', [downloadStates.CANCELLED, downloadStates.INTERRUPTED, downloadStates.COMPLETED], function (button) { + const spy = sinon.spy(appActions, 'downloadRedownloaded') + button.simulate('click') + assert(spy.withArgs(this.downloadId).calledOnce) + appActions.downloadRedownloaded.restore() + }) + + testButton('.copyLinkButton', Object.values(downloadStates), function (button) { + const spy = sinon.spy(appActions, 'downloadCopiedToClipboard') + button.simulate('click') + assert(spy.withArgs(this.downloadId).calledOnce) + appActions.downloadCopiedToClipboard.restore() + }) + + testButton('.revealButton', [downloadStates.IN_PROGRESS, downloadStates.PAUSED, downloadStates.COMPLETED], function (button) { + const spy = sinon.spy(appActions, 'downloadRevealed') + button.simulate('click') + assert(spy.withArgs(this.downloadId).calledOnce) + appActions.downloadRevealed.restore() + }) + + testButton('.deleteButton', [downloadStates.CANCELLED, downloadStates.INTERRUPTED, downloadStates.COMPLETED], function (button) { + const spy = sinon.spy(appActions, 'downloadDeleted') + button.simulate('click') + assert(spy.withArgs(this.downloadId).calledOnce) + appActions.downloadDeleted.restore() + }) + }) + }) +}) diff --git a/test/unit/app/renderer/downloadsToolbarTest.js b/test/unit/app/renderer/downloadsToolbarTest.js new file mode 100644 index 00000000000..9c8d2665f61 --- /dev/null +++ b/test/unit/app/renderer/downloadsToolbarTest.js @@ -0,0 +1,115 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* global describe, before, after, it */ + +const mockery = require('mockery') +const {mount} = require('enzyme') +const assert = require('assert') +const sinon = require('sinon') +const fakeElectron = require('../../lib/fakeElectron') +const path = require('path') +const uuid = require('uuid') +const Immutable = require('immutable') +const downloadStates = require('../../../../js/constants/downloadStates') +let DownloadItem, DownloadsBar +require('../../braveUnit') + +const mostRecentlyDownloadedId = uuid.v4() +const newDownloads = () => Immutable.fromJS({ + [uuid.v4()]: { + startTime: new Date().getTime(), + filename: 'mostHatedPrimes.txt', + savePath: path.join(require('os').tmpdir(), 'mostHatedPrimes.txt'), + url: 'http://www.bradrichter.com/mostHatedPrimes.txt', + totalBytes: 104729, + receivedBytes: 96931, + state: downloadStates.IN_PROGRESS + }, + [mostRecentlyDownloadedId]: { + startTime: new Date().getTime() + 1000, + filename: 'compositeNumbersFTW.txt', + savePath: path.join(require('os').tmpdir(), 'compositeNumbersFTW.txt'), + url: 'http://www.bradrichter.com/compositeNumbersTW.txt', + totalBytes: 42, + receivedBytes: 1024, + state: downloadStates.COMPLETED + }, + [uuid.v4()]: { + startTime: new Date().getTime() - 1000, + filename: 'guideToIntegers.txt', + savePath: path.join(require('os').tmpdir(), 'guideToInegers.txt'), + url: 'http://www.bradrichter.com/guideToInegers.txt', + totalBytes: 72, + receivedBytes: 1, + state: downloadStates.IN_PROGRESS + } +}) + +describe('downloadsBar component', function () { + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + mockery.registerMock('electron', fakeElectron) + DownloadItem = require('../../../../app/renderer/components/downloadItem') + DownloadsBar = require('../../../../app/renderer/components/downloadsBar') + }) + after(function () { + mockery.disable() + }) + + describe('multiple downloads with space', function () { + before(function () { + this.result = mount() + }) + + it('renders each download as a DownloadItem', function () { + assert.equal(this.result.find(DownloadItem).length, 3) + }) + + it('renders more recent items first', function () { + assert.equal(this.result.find(DownloadItem).at(0).props().downloadId, mostRecentlyDownloadedId) + }) + + it('hide downloads button is shown', function () { + assert.equal(this.result.find('.hideDownloadsToolbar').length, 1) + }) + }) + + describe('no downloads', function () { + before(function () { + this.result = mount() + }) + + it('renders no DownloadItems when there are no downloads', function () { + assert.equal(this.result.find(DownloadItem).length, 0) + }) + + it('hide downloads button is shown', function () { + assert.equal(this.result.find('.hideDownloadsToolbar').length, 1) + }) + }) + + describe('very narrow downloads bar with items', function () { + before(function () { + // TODO: We can remove this once we're on Khan/aphrodite + sinon.stub(window, 'getComputedStyle', () => ({ + getPropertyValue: function () { + return 10 + } + })) + this.result = mount() + }) + + it('renders no downloads', function () { + assert.equal(this.result.find(DownloadItem).length, 0) + }) + + it('but still shows hide downloads button', function () { + assert.equal(this.result.find('.hideDownloadsToolbar').length, 1) + }) + }) +}) diff --git a/test/unit/lib/fakeElectron.js b/test/unit/lib/fakeElectron.js index 2e4d444f6c6..78a0e54140a 100644 --- a/test/unit/lib/fakeElectron.js +++ b/test/unit/lib/fakeElectron.js @@ -5,10 +5,16 @@ const fakeElectron = { ipcMain: { on: function () { } }, + ipcRenderer: { + on: function () { } + }, remote: { app: { on: function () { } + }, + getCurrentWindow: function () { + return {} } }, app: { diff --git a/tools/lib/ignoredPaths.js b/tools/lib/ignoredPaths.js index abefdc84a4b..6f511499014 100644 --- a/tools/lib/ignoredPaths.js +++ b/tools/lib/ignoredPaths.js @@ -51,6 +51,8 @@ module.exports = [ 'babel-(?!polyfill|regenerator-runtime)', 'jsdom-global', 'react-addons-perf', + 'react-addons-test-utils', + 'enzyme', 'leveldown', 'sqlite3' ] From 9d32757dfd7c5694badce67c01b6b18db139ce7e Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 7 Dec 2016 15:11:40 -0500 Subject: [PATCH 41/80] Only log an error for session loading when data exists Auditors: @bsclifton --- app/sessionStore.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/sessionStore.js b/app/sessionStore.js index 72dad5fa2cd..7907bf91266 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -465,7 +465,9 @@ module.exports.loadAppState = () => { } catch (e) { // TODO: Session state is corrupted, maybe we should backup this // corrupted value for people to report into support. - console.log('could not parse data: ', data, e) + if (data) { + console.log('could not parse data: ', data, e) + } data = exports.defaultAppState() data = setVersionInformation(data) } From eab2dea790956a35c9b561520ca0ee583199babf Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 7 Dec 2016 15:27:20 -0500 Subject: [PATCH 42/80] Add environment variables to enable test logging Auditors: @bsclifton --- docs/tests.md | 7 ++++--- test/lib/brave.js | 26 +++++++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/tests.md b/docs/tests.md index d55bbb31e2c..da3e9602d9a 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -120,8 +120,8 @@ the IPC message was received and processed). ## Debugging tests ### Enabling verbose mode -You can get more verbose output from some of our commands by toggling the `logVerboseEnabled` flag in [test/lib/brave.js](https://github.com/brave/browser-laptop/blob/3ede178b5f4655e53e6c55a916c271a89f20317d/test/lib/brave.js#L17). -When set to true, tests will output extra information which can be very valuable when trying to understand what is going wrong with a failing test (be sure to disable the flag before checking in). +You can get more verbose output from some of our commands by setting the `BRAVE_TEST_COMMAND_LOGS=1` env variable. +If `BRAVE_TEST_COMMAND_LOGS=1` is set, tests will output extra information which can be very valuable when trying to understand what is going wrong with a failing test. As an example, here's the output you get when running the `blocks custom adblock resources in private tab` test in `test/components/braveryPanelTest.js` with verbose logging enabled: ``` @@ -158,4 +158,5 @@ Or most of the time just append `.debug()` to a series of commands. This will pause the browser from running tests, and you can open up browser dev tools or content dev tools to inspect logs, console, and other things. You should act fast or else adjust the timeout or the test will fail though. -To get browser process logs just do `git grep this.app.client.getMainProcessLogs` and uncomment that block of code. +To get browser process logs, run tests with the `BRAVE_TEST_BROWSER_LOGS=1` envrionment variable. +To get renderer process logs, run tests with the `BRAVE_TEST_RENDERER_LOGS=1` envrionment variable. diff --git a/test/lib/brave.js b/test/lib/brave.js index bcdbb686a11..1d5a6851cbe 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -15,7 +15,7 @@ chai.use(chaiAsPromised) const Server = require('./server') // toggle me for more verbose logs! :) -const logVerboseEnabled = false +const logVerboseEnabled = process.env.BRAVE_TEST_ALL_LOGS || process.env.BRAVE_TEST_COMMAND_LOGS const logVerbose = (string) => { if (logVerboseEnabled) { console.log(string) @@ -588,16 +588,20 @@ var exports = { return app }) - // this.app.client.getMainProcessLogs().then(function (logs) { - // logs.forEach(function (log) { - // console.log(log) - // }) - // }) - // this.app.client.getRenderProcessLogs().then(function (logs) { - // logs.forEach(function (log) { - // console.log(log) - // }) - // }) + if (process.env.BRAVE_TEST_ALL_LOGS || process.env.BRAVE_TEST_BROWSER_LOGS) { + this.app.client.getMainProcessLogs().then(function (logs) { + logs.forEach(function (log) { + console.log(log) + }) + }) + } + if (process.env.BRAVE_TEST_ALL_LOGS || process.env.BRAVE_TEST_RENDERER_LOGS) { + this.app.client.getRenderProcessLogs().then(function (logs) { + logs.forEach(function (log) { + console.log(log) + }) + }) + } return stop } } From a61d5c7d50cd21035465ce316914a6289de1047f Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 7 Dec 2016 15:41:23 -0500 Subject: [PATCH 43/80] Allow variable args for logVerbose Auditors: @bsclifton --- test/lib/brave.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/brave.js b/test/lib/brave.js index 1d5a6851cbe..1082ec2488a 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -16,9 +16,9 @@ const Server = require('./server') // toggle me for more verbose logs! :) const logVerboseEnabled = process.env.BRAVE_TEST_ALL_LOGS || process.env.BRAVE_TEST_COMMAND_LOGS -const logVerbose = (string) => { +const logVerbose = (string, ...rest) => { if (logVerboseEnabled) { - console.log(string) + console.log(string, ...rest) } } From e16b44e3a2b1a8d0885983dcc6bfe886fb6db96c Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 7 Dec 2016 16:56:37 -0500 Subject: [PATCH 44/80] Fix lots of failing tests Auditors: @bsclifton Unfortunately if you use devTools.js way directly it maintains a different copy of window state so this is the only way I can think of to get it working --- js/entry.js | 13 +++++++------ test/lib/brave.js | 10 +++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/js/entry.js b/js/entry.js index 91472ae3f29..c498cf60a3b 100644 --- a/js/entry.js +++ b/js/entry.js @@ -63,11 +63,13 @@ ipc.on(messages.REQUEST_WINDOW_STATE, () => { ipc.send(messages.RESPONSE_WINDOW_STATE, windowStore.getState().toJS()) }) -// // if (process.env.NODE_ENV === 'test') { -// // window.appStoreRenderer = appStoreRenderer -// // window.windowActions = windowActions -// // window.windowStore = windowStore -// // } +if (process.env.NODE_ENV === 'test') { + electron.testData = { + appStoreRenderer, + windowActions, + windowStore + } +} ipc.on(messages.APP_STATE_CHANGE, (e, action) => { appStoreRenderer.state = action.stateDiff @@ -91,7 +93,6 @@ ipc.on(messages.INITIALIZE_WINDOW, (e, disposition, appState, frames, initWindow // disableCrashReporting() // } appStoreRenderer.state = Immutable.fromJS(appState) - // ReactDOM.render(
test
, document.getElementById('windowContainer')) ReactDOM.render( , document.getElementById('windowContainer')) diff --git a/test/lib/brave.js b/test/lib/brave.js index 1082ec2488a..48c29d67f98 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -292,25 +292,25 @@ var exports = { this.app.client.addCommand('getAppState', function () { return this.execute(function () { - return window.appStoreRenderer.state.toJS() + return devTools('electron').testData.appStoreRenderer.state.toJS() }) }) this.app.client.addCommand('getWindowState', function () { return this.execute(function () { - return window.windowStore.state.toJS() + return devTools('electron').testData.windowStore.state.toJS() }) }) this.app.client.addCommand('setContextMenuDetail', function () { return this.execute(function () { - return window.windowActions.setContextMenuDetail() + return devTools('electron').testData.windowActions.setContextMenuDetail() }) }) this.app.client.addCommand('showFindbar', function (show, key = 1) { return this.execute(function (show, key) { - window.windowActions.setFindbarShown(Object.assign({ + devTools('electron').testData.windowActions.setFindbarShown(Object.assign({ windowId: devTools('electron').remote.getCurrentWindow().id, key }), show !== false) @@ -328,7 +328,7 @@ var exports = { this.app.client.addCommand('setPinned', function (location, isPinned, options = {}) { return this.execute(function (location, isPinned, options) { var Immutable = require('immutable') - window.windowActions.setPinned(Immutable.fromJS(Object.assign({ + devTools('electron').testData.windowActions.setPinned(Immutable.fromJS(Object.assign({ windowId: devTools('electron').remote.getCurrentWindow().id, location }, options)), isPinned) From b2ad4a8c9a20e1d089eec75c72a901af64b7da91 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 7 Dec 2016 22:18:58 -0500 Subject: [PATCH 45/80] Do a clean reload for stats Tests fail when toggling between allow and block because the later blocked resources are already in cache and load correctly Auditors: @bsclifton --- js/components/braveryPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/braveryPanel.js b/js/components/braveryPanel.js index 8f6aeb53e50..748a029ee77 100644 --- a/js/components/braveryPanel.js +++ b/js/components/braveryPanel.js @@ -130,7 +130,7 @@ class BraveryPanel extends ImmutableComponent { }) } onReload () { - ipc.emit(messages.SHORTCUT_ACTIVE_FRAME_LOAD_URL, {}, this.props.activeRequestedLocation) + ipc.emit(messages.SHORTCUT_ACTIVE_FRAME_CLEAN_RELOAD, {}, this.props.activeRequestedLocation) } onEditGlobal () { ipc.emit(messages.SHORTCUT_NEW_FRAME, {}, 'about:preferences#shields') From 13649691e59c16c7a59709370e0d3520dd943177 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Thu, 8 Dec 2016 16:19:13 +0800 Subject: [PATCH 46/80] Temporary solution to post emitted webview event Auditors: @bbondy, @bridiver --- js/components/frame.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 59cbf4e19ea..ded53560759 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -706,14 +706,20 @@ class Frame extends ImmutableComponent { this.props.onCloseFrame(this.frame) }) this.webview.addEventListener('page-favicon-updated', (e) => { - if (e.favicons && e.favicons.length > 0) { + // TODO(Anthony): more general solution on muon to prevent weview event + // from emitting after tab closed + if (e.favicons && e.favicons.length > 0 && this.frame) { imageUtil.getWorkingImageUrl(e.favicons[0], (imageFound) => { windowActions.setFavicon(this.frame, imageFound ? e.favicons[0] : null) }) } }) this.webview.addEventListener('page-title-updated', ({title}) => { - windowActions.setFrameTitle(this.frame, title) + // TODO(Anthony): more general solution on muon to prevent weview event + // from emitting after tab closed + if (this.frame) { + windowActions.setFrameTitle(this.frame, title) + } }) this.webview.addEventListener('show-autofill-settings', (e) => { windowActions.newFrame({ location: 'about:autofill' }, true) @@ -722,9 +728,13 @@ class Frame extends ImmutableComponent { contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) }) this.webview.addEventListener('hide-autofill-popup', (e) => { - let webContents = this.webview.getWebContents() - if (webContents && webContents.isFocused()) { - windowActions.autofillPopupHidden(this.props.tabId) + // TODO(Anthony): more general solution on muon to prevent weview event + // from emitting after tab closed + if (this.frame) { + let webContents = this.webview.getWebContents() + if (webContents && webContents.isFocused()) { + windowActions.autofillPopupHidden(this.props.tabId) + } } }) this.webview.addEventListener('ipc-message', (e) => { From b800271e82cef6ad821a550f8e6426344bcdeada Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Thu, 8 Dec 2016 14:12:44 -0500 Subject: [PATCH 47/80] Fix casing on AppConstants and WindowConstants Auditors: @bsclifton --- app/common/state/extensionState.js | 4 +- js/about/certerror.js | 6 +- js/about/errorPage.js | 6 +- js/actions/windowActions.js | 166 ++++++++++++------------- js/constants/appConstants.js | 4 +- js/state/contentSettings.js | 10 +- js/state/privacy.js | 4 +- js/stores/appStore.js | 144 +++++++++++----------- js/stores/eventStore.js | 14 +-- js/stores/windowStore.js | 186 ++++++++++++++--------------- 10 files changed, 272 insertions(+), 272 deletions(-) diff --git a/app/common/state/extensionState.js b/app/common/state/extensionState.js index be8404a0c3d..2ee9d1255f7 100644 --- a/app/common/state/extensionState.js +++ b/app/common/state/extensionState.js @@ -4,7 +4,7 @@ const { makeImmutable } = require('./immutableUtil') const Immutable = require('immutable') -const WindowConstants = require('../../../js/constants/windowConstants') +const windowConstants = require('../../../js/constants/windowConstants') const browserActionDefaults = Immutable.fromJS({ tabs: {} @@ -52,7 +52,7 @@ const extensionState = { browserActionUpdated: (state, action) => { action = makeImmutable(action) state = makeImmutable(state) - if (action.get('actionType') === WindowConstants.WINDOW_SET_NAVIGATED && + if (action.get('actionType') === windowConstants.WINDOW_SET_NAVIGATED && action.get('tabId')) { let tabId = action.get('tabId') let extensions = extensionState.getEnabledExtensions(state) diff --git a/js/about/certerror.js b/js/about/certerror.js index ba7573a5f79..19ba58de06a 100644 --- a/js/about/certerror.js +++ b/js/about/certerror.js @@ -5,7 +5,7 @@ const React = require('react') const Button = require('../components/button') const aboutActions = require('./aboutActions') -const WindowConstants = require('../constants/windowConstants') +const windowConstants = require('../constants/windowConstants') const messages = require('../constants/messages') const ipc = window.chrome.ipcRenderer @@ -72,7 +72,7 @@ class CertErrorPage extends React.Component { onAccept () { aboutActions.acceptCertError(this.state.url) aboutActions.dispatchAction({ - actionType: WindowConstants.WINDOW_SET_URL, + actionType: windowConstants.WINDOW_SET_URL, location: this.state.url, key: this.state.frameKey }) @@ -80,7 +80,7 @@ class CertErrorPage extends React.Component { onSafety () { aboutActions.dispatchAction({ - actionType: WindowConstants.WINDOW_SET_URL, + actionType: windowConstants.WINDOW_SET_URL, location: this.state.previousLocation, key: this.state.frameKey }) diff --git a/js/about/errorPage.js b/js/about/errorPage.js index a935c2889e3..fb1ab09fad0 100644 --- a/js/about/errorPage.js +++ b/js/about/errorPage.js @@ -5,7 +5,7 @@ const React = require('react') const Button = require('../components/button') const aboutActions = require('./aboutActions') -const WindowConstants = require('../constants/windowConstants') +const windowConstants = require('../constants/windowConstants') require('../../less/button.less') require('../../less/window.less') @@ -19,7 +19,7 @@ class ErrorPage extends React.Component { reloadPrevious () { aboutActions.dispatchAction({ - actionType: WindowConstants.WINDOW_SET_URL, + actionType: windowConstants.WINDOW_SET_URL, location: this.state.previousLocation, key: this.state.frameKey }) @@ -27,7 +27,7 @@ class ErrorPage extends React.Component { reload () { aboutActions.dispatchAction({ - actionType: WindowConstants.WINDOW_SET_URL, + actionType: windowConstants.WINDOW_SET_URL, location: this.state.url, key: this.state.frameKey }) diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js index 44dbb391afe..e8d6a53c2ce 100644 --- a/js/actions/windowActions.js +++ b/js/actions/windowActions.js @@ -5,7 +5,7 @@ 'use strict' const AppDispatcher = require('../dispatcher/appDispatcher') -const WindowConstants = require('../constants/windowConstants') +const windowConstants = require('../constants/windowConstants') const appActions = require('../actions/appActions') const webviewActions = require('../actions/webviewActions') const messages = require('../constants/messages') @@ -28,7 +28,7 @@ const windowActions = { */ setState: function (windowState) { dispatch({ - actionType: WindowConstants.WINDOW_SET_STATE, + actionType: windowConstants.WINDOW_SET_STATE, windowState }) }, @@ -85,7 +85,7 @@ const windowActions = { */ setUrl: function (location, key) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL, + actionType: windowConstants.WINDOW_SET_URL, location, key }) @@ -101,7 +101,7 @@ const windowActions = { */ setNavigated: function (location, key, isNavigatedInPage, tabId) { dispatch({ - actionType: WindowConstants.WINDOW_SET_NAVIGATED, + actionType: windowConstants.WINDOW_SET_NAVIGATED, location, key, isNavigatedInPage, @@ -117,7 +117,7 @@ const windowActions = { */ setSecurityState: function (frameProps, securityState) { dispatch({ - actionType: WindowConstants.WINDOW_SET_SECURITY_STATE, + actionType: windowConstants.WINDOW_SET_SECURITY_STATE, securityState, frameProps }) @@ -130,7 +130,7 @@ const windowActions = { */ setFrameTabId: function (frameProps, tabId) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FRAME_TAB_ID, + actionType: windowConstants.WINDOW_SET_FRAME_TAB_ID, frameProps, tabId }) @@ -144,7 +144,7 @@ const windowActions = { */ setFrameError: function (frameProps, errorDetails) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FRAME_ERROR, + actionType: windowConstants.WINDOW_SET_FRAME_ERROR, frameProps, errorDetails }) @@ -158,7 +158,7 @@ const windowActions = { */ setNavBarUserInput: function (location) { dispatch({ - actionType: WindowConstants.WINDOW_SET_NAVBAR_INPUT, + actionType: windowConstants.WINDOW_SET_NAVBAR_INPUT, location }) }, @@ -172,7 +172,7 @@ const windowActions = { */ setFrameTitle: function (frameProps, title) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FRAME_TITLE, + actionType: windowConstants.WINDOW_SET_FRAME_TITLE, frameProps, title }) @@ -185,7 +185,7 @@ const windowActions = { */ setFindbarShown: function (frameProps, shown) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FINDBAR_SHOWN, + actionType: windowConstants.WINDOW_SET_FINDBAR_SHOWN, frameProps, shown }) @@ -198,7 +198,7 @@ const windowActions = { */ setFindbarSelected: function (frameProps, selected) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FINDBAR_SELECTED, + actionType: windowConstants.WINDOW_SET_FINDBAR_SELECTED, frameProps, selected }) @@ -211,7 +211,7 @@ const windowActions = { */ setPinned: function (frameProps, isPinned) { dispatch({ - actionType: WindowConstants.WINDOW_SET_PINNED, + actionType: windowConstants.WINDOW_SET_PINNED, frameProps, isPinned }) @@ -231,7 +231,7 @@ const windowActions = { */ onWebviewLoadStart: function (frameProps, location) { dispatch({ - actionType: WindowConstants.WINDOW_WEBVIEW_LOAD_START, + actionType: windowConstants.WINDOW_WEBVIEW_LOAD_START, frameProps, location }) @@ -244,7 +244,7 @@ const windowActions = { */ onWebviewLoadEnd: function (frameProps) { dispatch({ - actionType: WindowConstants.WINDOW_WEBVIEW_LOAD_END, + actionType: windowConstants.WINDOW_WEBVIEW_LOAD_END, frameProps }) }, @@ -258,7 +258,7 @@ const windowActions = { */ setFullScreen: function (frameProps, isFullScreen, showFullScreenWarning) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FULL_SCREEN, + actionType: windowConstants.WINDOW_SET_FULL_SCREEN, frameProps, isFullScreen, showFullScreenWarning @@ -272,7 +272,7 @@ const windowActions = { */ setNavBarFocused: function (focused) { dispatch({ - actionType: WindowConstants.WINDOW_SET_NAVBAR_FOCUSED, + actionType: windowConstants.WINDOW_SET_NAVBAR_FOCUSED, focused }) }, @@ -286,7 +286,7 @@ const windowActions = { */ newFrame: function (frameOpts, openInForeground) { dispatch({ - actionType: WindowConstants.WINDOW_NEW_FRAME, + actionType: windowConstants.WINDOW_NEW_FRAME, frameOpts: frameOpts, openInForeground }) @@ -300,7 +300,7 @@ const windowActions = { */ cloneFrame: function (frameProps, guestInstanceId, openInForeground) { dispatch({ - actionType: WindowConstants.WINDOW_CLONE_FRAME, + actionType: windowConstants.WINDOW_CLONE_FRAME, frameOpts: frameProps.toJS ? frameProps.toJS() : frameProps, guestInstanceId, openInForeground @@ -353,7 +353,7 @@ const windowActions = { // close attempts if (nonPinnedFrames.size > 1 || pinnedFrames.size > 0) { dispatch({ - actionType: WindowConstants.WINDOW_CLOSE_FRAME, + actionType: windowConstants.WINDOW_CLOSE_FRAME, frameProps }) } else { @@ -367,7 +367,7 @@ const windowActions = { */ undoClosedFrame: function () { dispatch({ - actionType: WindowConstants.WINDOW_UNDO_CLOSED_FRAME + actionType: windowConstants.WINDOW_UNDO_CLOSED_FRAME }) }, @@ -376,7 +376,7 @@ const windowActions = { */ clearClosedFrames: function () { dispatch({ - actionType: WindowConstants.WINDOW_CLEAR_CLOSED_FRAMES + actionType: windowConstants.WINDOW_CLEAR_CLOSED_FRAMES }) }, @@ -387,7 +387,7 @@ const windowActions = { */ setActiveFrame: function (frameProps) { dispatch({ - actionType: WindowConstants.WINDOW_SET_ACTIVE_FRAME, + actionType: windowConstants.WINDOW_SET_ACTIVE_FRAME, frameProps: frameProps }) }, @@ -400,7 +400,7 @@ const windowActions = { setFocusedFrame: function (frameProps) { if (frameProps) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FOCUSED_FRAME, + actionType: windowConstants.WINDOW_SET_FOCUSED_FRAME, frameProps: frameProps }) } @@ -414,7 +414,7 @@ const windowActions = { */ setPreviewFrame: function (frameProps) { dispatch({ - actionType: WindowConstants.WINDOW_SET_PREVIEW_FRAME, + actionType: windowConstants.WINDOW_SET_PREVIEW_FRAME, frameProps: frameProps }) }, @@ -426,7 +426,7 @@ const windowActions = { */ setTabPageIndex: function (index) { dispatch({ - actionType: WindowConstants.WINDOW_SET_TAB_PAGE_INDEX, + actionType: windowConstants.WINDOW_SET_TAB_PAGE_INDEX, index }) }, @@ -438,7 +438,7 @@ const windowActions = { */ setPreviewTabPageIndex: function (previewTabPageIndex) { dispatch({ - actionType: WindowConstants.WINDOW_SET_PREVIEW_TAB_PAGE_INDEX, + actionType: windowConstants.WINDOW_SET_PREVIEW_TAB_PAGE_INDEX, previewTabPageIndex }) }, @@ -450,7 +450,7 @@ const windowActions = { */ setTabPageIndexByFrame: function (frameProps) { dispatch({ - actionType: WindowConstants.WINDOW_SET_TAB_PAGE_INDEX, + actionType: windowConstants.WINDOW_SET_TAB_PAGE_INDEX, frameProps }) }, @@ -464,7 +464,7 @@ const windowActions = { */ updateBackForwardState: function (frameProps, canGoBack, canGoForward) { dispatch({ - actionType: WindowConstants.WINDOW_UPDATE_BACK_FORWARD, + actionType: windowConstants.WINDOW_UPDATE_BACK_FORWARD, frameProps, canGoBack, canGoForward @@ -481,7 +481,7 @@ const windowActions = { setIsBeingDraggedOverDetail: function (dragType, dragOverKey, dragDetail) { dispatch({ dragType, - actionType: WindowConstants.WINDOW_SET_IS_BEING_DRAGGED_OVER_DETAIL, + actionType: windowConstants.WINDOW_SET_IS_BEING_DRAGGED_OVER_DETAIL, dragOverKey, dragDetail }) @@ -496,7 +496,7 @@ const windowActions = { */ moveTab: function (sourceFrameProps, destinationFrameProps, prepend) { dispatch({ - actionType: WindowConstants.WINDOW_TAB_MOVE, + actionType: windowConstants.WINDOW_TAB_MOVE, sourceFrameProps, destinationFrameProps, prepend @@ -511,7 +511,7 @@ const windowActions = { */ setUrlBarSuggestions: function (suggestionList, selectedIndex) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_SUGGESTIONS, + actionType: windowConstants.WINDOW_SET_URL_BAR_SUGGESTIONS, suggestionList, selectedIndex }) @@ -528,7 +528,7 @@ const windowActions = { */ setUrlBarAutocompleteEnabled: function (enabled) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_AUTCOMPLETE_ENABLED, + actionType: windowConstants.WINDOW_SET_URL_BAR_AUTCOMPLETE_ENABLED, enabled }) }, @@ -540,7 +540,7 @@ const windowActions = { */ setRenderUrlBarSuggestions: function (enabled) { dispatch({ - actionType: WindowConstants.WINDOW_SET_RENDER_URL_BAR_SUGGESTIONS, + actionType: windowConstants.WINDOW_SET_RENDER_URL_BAR_SUGGESTIONS, enabled }) }, @@ -553,7 +553,7 @@ const windowActions = { */ setUrlBarPreview: function (value) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_PREVIEW, + actionType: windowConstants.WINDOW_SET_URL_BAR_PREVIEW, value }) }, @@ -567,7 +567,7 @@ const windowActions = { */ setUrlBarSuggestionSearchResults: function (searchResults) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_SUGGESTION_SEARCH_RESULTS, + actionType: windowConstants.WINDOW_SET_URL_BAR_SUGGESTION_SEARCH_RESULTS, searchResults }) }, @@ -579,7 +579,7 @@ const windowActions = { */ setUrlBarSelected: function (selected) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_SELECTED, + actionType: windowConstants.WINDOW_SET_URL_BAR_SELECTED, selected }) }, @@ -594,7 +594,7 @@ const windowActions = { */ setUrlBarActive: function (isActive) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_ACTIVE, + actionType: windowConstants.WINDOW_SET_URL_BAR_ACTIVE, isActive }) }, @@ -606,7 +606,7 @@ const windowActions = { */ setUrlBarFocused: function (isFocused) { dispatch({ - actionType: WindowConstants.WINDOW_SET_URL_BAR_FOCUSED, + actionType: windowConstants.WINDOW_SET_URL_BAR_FOCUSED, isFocused }) }, @@ -620,7 +620,7 @@ const windowActions = { */ setActiveFrameShortcut: function (frameProps, activeShortcut, activeShortcutDetails) { dispatch({ - actionType: WindowConstants.WINDOW_SET_ACTIVE_FRAME_SHORTCUT, + actionType: windowConstants.WINDOW_SET_ACTIVE_FRAME_SHORTCUT, frameProps, activeShortcut, activeShortcutDetails @@ -633,7 +633,7 @@ const windowActions = { */ setSearchDetail: function (searchDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_SEARCH_DETAIL, + actionType: windowConstants.WINDOW_SET_SEARCH_DETAIL, searchDetail }) }, @@ -645,7 +645,7 @@ const windowActions = { */ setFindDetail: function (frameProps, findDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FIND_DETAIL, + actionType: windowConstants.WINDOW_SET_FIND_DETAIL, frameProps, findDetail }) @@ -662,7 +662,7 @@ const windowActions = { */ setBookmarkDetail: function (currentDetail, originalDetail, destinationDetail, shouldShowLocation, isBookmarkHanger) { dispatch({ - actionType: WindowConstants.WINDOW_SET_BOOKMARK_DETAIL, + actionType: windowConstants.WINDOW_SET_BOOKMARK_DETAIL, currentDetail, originalDetail, destinationDetail, @@ -678,7 +678,7 @@ const windowActions = { */ setContextMenuDetail: function (detail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL, + actionType: windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL, detail }) }, @@ -690,7 +690,7 @@ const windowActions = { */ setPopupWindowDetail: function (detail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL, + actionType: windowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL, detail }) }, @@ -703,7 +703,7 @@ const windowActions = { */ setAudioMuted: function (frameProps, muted) { dispatch({ - actionType: WindowConstants.WINDOW_SET_AUDIO_MUTED, + actionType: windowConstants.WINDOW_SET_AUDIO_MUTED, frameProps, muted }) @@ -751,7 +751,7 @@ const windowActions = { */ setAudioPlaybackActive: function (frameProps, audioPlaybackActive) { dispatch({ - actionType: WindowConstants.WINDOW_SET_AUDIO_PLAYBACK_ACTIVE, + actionType: windowConstants.WINDOW_SET_AUDIO_PLAYBACK_ACTIVE, frameProps, audioPlaybackActive }) @@ -767,7 +767,7 @@ const windowActions = { */ setThemeColor: function (frameProps, themeColor, computedThemeColor) { dispatch({ - actionType: WindowConstants.WINDOW_SET_THEME_COLOR, + actionType: windowConstants.WINDOW_SET_THEME_COLOR, frameProps, themeColor, computedThemeColor @@ -782,7 +782,7 @@ const windowActions = { */ setFavicon: function (frameProps, favicon) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FAVICON, + actionType: windowConstants.WINDOW_SET_FAVICON, frameProps, favicon }) @@ -797,7 +797,7 @@ const windowActions = { */ setLastZoomPercentage: function (frameProps, percentage) { dispatch({ - actionType: WindowConstants.WINDOW_SET_LAST_ZOOM_PERCENTAGE, + actionType: windowConstants.WINDOW_SET_LAST_ZOOM_PERCENTAGE, frameProps, percentage }) @@ -809,7 +809,7 @@ const windowActions = { */ setMaximizeState: function (isMaximized) { dispatch({ - actionType: WindowConstants.WINDOW_SET_MAXIMIZE_STATE, + actionType: windowConstants.WINDOW_SET_MAXIMIZE_STATE, isMaximized }) }, @@ -820,7 +820,7 @@ const windowActions = { */ savePosition: function (position) { dispatch({ - actionType: WindowConstants.WINDOW_SAVE_POSITION, + actionType: windowConstants.WINDOW_SAVE_POSITION, position }) }, @@ -831,7 +831,7 @@ const windowActions = { */ saveSize: function (size) { dispatch({ - actionType: WindowConstants.WINDOW_SAVE_SIZE, + actionType: windowConstants.WINDOW_SAVE_SIZE, size }) }, @@ -842,7 +842,7 @@ const windowActions = { */ setWindowFullScreen: function (isFullScreen) { dispatch({ - actionType: WindowConstants.WINDOW_SET_FULLSCREEN_STATE, + actionType: windowConstants.WINDOW_SET_FULLSCREEN_STATE, isFullScreen }) }, @@ -854,7 +854,7 @@ const windowActions = { */ setMouseInTitlebar: function (mouseInTitlebar) { dispatch({ - actionType: WindowConstants.WINDOW_SET_MOUSE_IN_TITLEBAR, + actionType: windowConstants.WINDOW_SET_MOUSE_IN_TITLEBAR, mouseInTitlebar }) }, @@ -866,7 +866,7 @@ const windowActions = { */ setSiteInfoVisible: function (isVisible) { dispatch({ - actionType: WindowConstants.WINDOW_SET_SITE_INFO_VISIBLE, + actionType: windowConstants.WINDOW_SET_SITE_INFO_VISIBLE, isVisible }) }, @@ -879,7 +879,7 @@ const windowActions = { */ setBraveryPanelDetail: function (braveryPanelDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_BRAVERY_PANEL_DETAIL, + actionType: windowConstants.WINDOW_SET_BRAVERY_PANEL_DETAIL, braveryPanelDetail }) }, @@ -891,7 +891,7 @@ const windowActions = { */ setDownloadsToolbarVisible: function (isVisible) { dispatch({ - actionType: WindowConstants.WINDOW_SET_DOWNLOADS_TOOLBAR_VISIBLE, + actionType: windowConstants.WINDOW_SET_DOWNLOADS_TOOLBAR_VISIBLE, isVisible }) }, @@ -903,7 +903,7 @@ const windowActions = { */ setReleaseNotesVisible: function (isVisible) { dispatch({ - actionType: WindowConstants.WINDOW_SET_RELEASE_NOTES_VISIBLE, + actionType: windowConstants.WINDOW_SET_RELEASE_NOTES_VISIBLE, isVisible }) }, @@ -916,7 +916,7 @@ const windowActions = { */ setLinkHoverPreview: function (href, showOnRight) { dispatch({ - actionType: WindowConstants.WINDOW_SET_LINK_HOVER_PREVIEW, + actionType: windowConstants.WINDOW_SET_LINK_HOVER_PREVIEW, href, showOnRight }) @@ -931,7 +931,7 @@ const windowActions = { */ setBlockedBy: function (frameProps, blockType, location) { dispatch({ - actionType: WindowConstants.WINDOW_SET_BLOCKED_BY, + actionType: windowConstants.WINDOW_SET_BLOCKED_BY, frameProps, blockType, location @@ -946,7 +946,7 @@ const windowActions = { */ setRedirectedBy: function (frameProps, ruleset, location) { dispatch({ - actionType: WindowConstants.WINDOW_SET_REDIRECTED_BY, + actionType: windowConstants.WINDOW_SET_REDIRECTED_BY, frameProps, ruleset, location @@ -960,7 +960,7 @@ const windowActions = { */ setNoScript: function (frameProps, source) { dispatch({ - actionType: WindowConstants.WINDOW_SET_NOSCRIPT, + actionType: windowConstants.WINDOW_SET_NOSCRIPT, frameProps, source }) @@ -972,7 +972,7 @@ const windowActions = { */ setNoScriptVisible: function (isVisible) { dispatch({ - actionType: WindowConstants.WINDOW_SET_NOSCRIPT_VISIBLE, + actionType: windowConstants.WINDOW_SET_NOSCRIPT_VISIBLE, isVisible }) }, @@ -983,7 +983,7 @@ const windowActions = { */ addHistory: function (frameProps) { dispatch({ - actionType: WindowConstants.WINDOW_ADD_HISTORY, + actionType: windowConstants.WINDOW_ADD_HISTORY, frameProps }) }, @@ -993,7 +993,7 @@ const windowActions = { */ setClearBrowsingDataDetail: function (clearBrowsingDataDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL, + actionType: windowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL, clearBrowsingDataDetail }) }, @@ -1004,7 +1004,7 @@ const windowActions = { */ setImportBrowserDataDetail: function (importBrowserDataDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_DETAIL, + actionType: windowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_DETAIL, importBrowserDataDetail }) }, @@ -1015,14 +1015,14 @@ const windowActions = { */ setImportBrowserDataSelected: function (selected) { dispatch({ - actionType: WindowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_SELECTED, + actionType: windowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_SELECTED, selected }) }, widevineSiteAccessedWithoutInstall: function () { dispatch({ - actionType: WindowConstants.WINDOW_WIDEVINE_SITE_ACCESSED_WITHOUT_INSTALL + actionType: windowConstants.WINDOW_WIDEVINE_SITE_ACCESSED_WITHOUT_INSTALL }) }, @@ -1032,7 +1032,7 @@ const windowActions = { */ widevinePanelDetailChanged: function (widevinePanelDetail) { dispatch({ - actionType: WindowConstants.WINDOW_WIDEVINE_PANEL_DETAIL_CHANGED, + actionType: windowConstants.WINDOW_WIDEVINE_PANEL_DETAIL_CHANGED, widevinePanelDetail }) }, @@ -1044,7 +1044,7 @@ const windowActions = { */ setAutofillAddressDetail: function (currentDetail, originalDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL, + actionType: windowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL, currentDetail, originalDetail }) @@ -1057,7 +1057,7 @@ const windowActions = { */ setAutofillCreditCardDetail: function (currentDetail, originalDetail) { dispatch({ - actionType: WindowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL, + actionType: windowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL, currentDetail, originalDetail }) @@ -1071,7 +1071,7 @@ const windowActions = { */ setBlockedRunInsecureContent: function (frameProps, source) { dispatch({ - actionType: WindowConstants.WINDOW_SET_BLOCKED_RUN_INSECURE_CONTENT, + actionType: windowConstants.WINDOW_SET_BLOCKED_RUN_INSECURE_CONTENT, frameProps, source }) @@ -1084,7 +1084,7 @@ const windowActions = { */ toggleMenubarVisible: function (isVisible) { dispatch({ - actionType: WindowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE, + actionType: windowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE, isVisible }) }, @@ -1097,7 +1097,7 @@ const windowActions = { */ clickMenubarSubmenu: function (label) { dispatch({ - actionType: WindowConstants.WINDOW_CLICK_MENUBAR_SUBMENU, + actionType: windowConstants.WINDOW_CLICK_MENUBAR_SUBMENU, label }) }, @@ -1111,7 +1111,7 @@ const windowActions = { */ resetMenuState: function () { dispatch({ - actionType: WindowConstants.WINDOW_RESET_MENU_STATE + actionType: windowConstants.WINDOW_RESET_MENU_STATE }) }, @@ -1124,7 +1124,7 @@ const windowActions = { */ setSubmenuSelectedIndex: function (index) { dispatch({ - actionType: WindowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX, + actionType: windowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX, index }) }, @@ -1139,7 +1139,7 @@ const windowActions = { */ setLastFocusedSelector: function (selector) { dispatch({ - actionType: WindowConstants.WINDOW_SET_LAST_FOCUSED_SELECTOR, + actionType: windowConstants.WINDOW_SET_LAST_FOCUSED_SELECTOR, selector }) }, @@ -1152,7 +1152,7 @@ const windowActions = { */ gotResponseDetails: function (tabId, details) { dispatch({ - actionType: WindowConstants.WINDOW_GOT_RESPONSE_DETAILS, + actionType: windowConstants.WINDOW_GOT_RESPONSE_DETAILS, tabId, details }) @@ -1165,7 +1165,7 @@ const windowActions = { */ setBookmarksToolbarSelectedFolderId: function (folderId) { dispatch({ - actionType: WindowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID, + actionType: windowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID, folderId }) }, @@ -1176,7 +1176,7 @@ const windowActions = { */ onFocusChanged: function (hasFocus) { dispatch({ - actionType: WindowConstants.WINDOW_ON_FOCUS_CHANGED, + actionType: windowConstants.WINDOW_ON_FOCUS_CHANGED, hasFocus }) }, @@ -1188,7 +1188,7 @@ const windowActions = { */ setModalDialogDetail: function (className, props) { dispatch({ - actionType: WindowConstants.WINDOW_SET_MODAL_DIALOG_DETAIL, + actionType: windowConstants.WINDOW_SET_MODAL_DIALOG_DETAIL, className, props }) @@ -1196,7 +1196,7 @@ const windowActions = { autofillSelectionClicked: function (tabId, value, frontEndId, index) { dispatch({ - actionType: WindowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED, + actionType: windowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED, tabId, value, frontEndId, @@ -1206,7 +1206,7 @@ const windowActions = { autofillPopupHidden: function (tabId, notify = false) { dispatch({ - actionType: WindowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN, + actionType: windowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN, tabId, notify }) diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 60d3d2e10a0..1a3e0f0c5f3 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -5,7 +5,7 @@ const mapValuesByKeys = require('../lib/functional').mapValuesByKeys const _ = null -const AppConstants = { +const appConstants = { APP_NEW_WINDOW: _, APP_CLOSE_WINDOW: _, APP_WINDOW_CLOSED: _, @@ -83,4 +83,4 @@ const AppConstants = { APP_DOWNLOAD_REDOWNLOADED: _ } -module.exports = mapValuesByKeys(AppConstants) +module.exports = mapValuesByKeys(appConstants) diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index 9e7051b0119..91917aa9349 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -4,7 +4,7 @@ const AppDispatcher = require('../dispatcher/appDispatcher') const AppStore = require('../stores/appStore') -const AppConstants = require('../constants/appConstants') +const appConstants = require('../constants/appConstants') const appConfig = require('../constants/appConfig') const config = require('../constants/config') const settings = require('../constants/settings') @@ -192,7 +192,7 @@ const getContentSettingsFromSiteSettings = (appState, isPrivate = false) => { // Register callback to handle all updates const doAction = (action) => { switch (action.actionType) { - case AppConstants.APP_CHANGE_SITE_SETTING: + case appConstants.APP_CHANGE_SITE_SETTING: AppDispatcher.waitFor([AppStore.dispatchToken], () => { if (action.temporary) { setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState(), true).content_settings, true) @@ -201,7 +201,7 @@ const doAction = (action) => { } }) break - case AppConstants.APP_REMOVE_SITE_SETTING: + case appConstants.APP_REMOVE_SITE_SETTING: AppDispatcher.waitFor([AppStore.dispatchToken], () => { if (action.temporary) { setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState(), true).content_settings, true) @@ -210,12 +210,12 @@ const doAction = (action) => { } }) break - case AppConstants.APP_SET_RESOURCE_ENABLED: + case appConstants.APP_SET_RESOURCE_ENABLED: AppDispatcher.waitFor([AppStore.dispatchToken], () => { setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState()).content_settings) }) break - case AppConstants.APP_CHANGE_SETTING: + case appConstants.APP_CHANGE_SETTING: AppDispatcher.waitFor([AppStore.dispatchToken], () => { setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState()).content_settings) }) diff --git a/js/state/privacy.js b/js/state/privacy.js index 6f1a136b98f..be3596499b7 100644 --- a/js/state/privacy.js +++ b/js/state/privacy.js @@ -4,7 +4,7 @@ const AppDispatcher = require('../dispatcher/appDispatcher') const AppStore = require('../stores/appStore') -const AppConstants = require('../constants/appConstants') +const appConstants = require('../constants/appConstants') const settings = require('../constants/settings') const {registerUserPrefs} = require('./userPrefs') const getSetting = require('../settings').getSetting @@ -17,7 +17,7 @@ let updateTrigger // Register callback to handle all updates const doAction = (action) => { - if (action.actionType === AppConstants.APP_CHANGE_SETTING) { + if (action.actionType === appConstants.APP_CHANGE_SETTING) { AppDispatcher.waitFor([AppStore.dispatchToken], () => { updateTrigger() }) diff --git a/js/stores/appStore.js b/js/stores/appStore.js index eda76ff7d50..a903bfdd02a 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -3,8 +3,8 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict' -const AppConstants = require('../constants/appConstants') -const WindowConstants = require('../constants/windowConstants') +const appConstants = require('../constants/appConstants') +const windowConstants = require('../constants/windowConstants') const ExtensionConstants = require('../../app/common/constants/extensionConstants') const AppDispatcher = require('../dispatcher/appDispatcher') const appConfig = require('../constants/appConfig') @@ -364,7 +364,7 @@ const handleAppAction = (action) => { appState = downloadsReducer(appState, action) switch (action.actionType) { - case AppConstants.APP_SET_STATE: + case appConstants.APP_SET_STATE: appState = action.appState appState = Filtering.init(appState, action, appStore) appState = windows.init(appState, action, appStore) @@ -373,10 +373,10 @@ const handleAppAction = (action) => { appState = flash.init(appState, action, appStore) appState = webtorrent.init(appState, action, appStore) break - case AppConstants.APP_SHUTTING_DOWN: + case appConstants.APP_SHUTTING_DOWN: shuttingDown = true break - case AppConstants.APP_NEW_WINDOW: + case appConstants.APP_NEW_WINDOW: const frameOpts = action.frameOpts && action.frameOpts.toJS() const browserOpts = (action.browserOpts && action.browserOpts.toJS()) || {} const newWindowState = action.restoredState || {} @@ -431,19 +431,19 @@ const handleAppAction = (action) => { mainWindow.loadURL(appUrlUtil.getBraveExtIndexHTML()) mainWindow.show() break - case AppConstants.APP_CLOSE_WINDOW: + case appConstants.APP_CLOSE_WINDOW: appState = windows.closeWindow(appState, action) break - case AppConstants.APP_WINDOW_CLOSED: + case appConstants.APP_WINDOW_CLOSED: appState = windowState.removeWindow(appState, action) break - case AppConstants.APP_WINDOW_CREATED: + case appConstants.APP_WINDOW_CREATED: appState = windowState.maybeCreateWindow(appState, action) break - case AppConstants.APP_WINDOW_UPDATED: + case appConstants.APP_WINDOW_UPDATED: appState = windowState.maybeCreateWindow(appState, action) break - case AppConstants.APP_ADD_PASSWORD: + case appConstants.APP_ADD_PASSWORD: // If there is already an entry for this exact origin, action, and // username if it exists, update the password instead of creating a new entry let passwords = appState.get('passwords').filterNot((pw) => { @@ -453,27 +453,27 @@ const handleAppAction = (action) => { }) appState = appState.set('passwords', passwords.push(Immutable.fromJS(action.passwordDetail))) break - case AppConstants.APP_REMOVE_PASSWORD: + case appConstants.APP_REMOVE_PASSWORD: appState = appState.set('passwords', appState.get('passwords').filterNot((pw) => { return Immutable.is(pw, Immutable.fromJS(action.passwordDetail)) })) break - case AppConstants.APP_CLEAR_PASSWORDS: + case appConstants.APP_CLEAR_PASSWORDS: appState = appState.set('passwords', new Immutable.List()) break - case AppConstants.APP_CHANGE_NEW_TAB_DETAIL: + case appConstants.APP_CHANGE_NEW_TAB_DETAIL: appState = aboutNewTabState.mergeDetails(appState, action) if (action.refresh) { appState = aboutNewTabState.setSites(appState, action) } break - case AppConstants.APP_POPULATE_HISTORY: + case appConstants.APP_POPULATE_HISTORY: appState = aboutHistoryState.setHistory(appState, action) break - case AppConstants.APP_DATA_URL_COPIED: + case appConstants.APP_DATA_URL_COPIED: nativeImage.copyDataURL(action.dataURL, action.html, action.text) break - case AppConstants.APP_ADD_SITE: + case appConstants.APP_ADD_SITE: const oldSiteSize = appState.get('sites').size if (action.siteDetail.constructor === Immutable.List) { action.siteDetail.forEach((s) => { @@ -492,20 +492,20 @@ const handleAppAction = (action) => { appState = aboutNewTabState.setSites(appState, action) appState = aboutHistoryState.setHistory(appState, action) break - case AppConstants.APP_REMOVE_SITE: + case appConstants.APP_REMOVE_SITE: appState = appState.set('sites', siteUtil.removeSite(appState.get('sites'), action.siteDetail, action.tag)) appState = aboutNewTabState.setSites(appState, action) appState = aboutHistoryState.setHistory(appState, action) break - case AppConstants.APP_MOVE_SITE: + case appConstants.APP_MOVE_SITE: appState = appState.set('sites', siteUtil.moveSite(appState.get('sites'), action.sourceDetail, action.destinationDetail, action.prepend, action.destinationIsParent, false)) break - case AppConstants.APP_CLEAR_HISTORY: + case appConstants.APP_CLEAR_HISTORY: appState = appState.set('sites', siteUtil.clearHistory(appState.get('sites'))) appState = aboutNewTabState.setSites(appState, action) appState = aboutHistoryState.setHistory(appState, action) break - case AppConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED: + case appConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED: if (action.size && action.size.size === 2) { appState = appState.setIn(['defaultWindowParams', 'width'], action.size.get(0)) appState = appState.setIn(['defaultWindowParams', 'height'], action.size.get(1)) @@ -515,17 +515,17 @@ const handleAppAction = (action) => { appState = appState.setIn(['defaultWindowParams', 'y'], action.position.get(1)) } break - case AppConstants.APP_SET_DATA_FILE_ETAG: + case appConstants.APP_SET_DATA_FILE_ETAG: appState = appState.setIn([action.resourceName, 'etag'], action.etag) break - case AppConstants.APP_UPDATE_LAST_CHECK: + case appConstants.APP_UPDATE_LAST_CHECK: appState = appState.setIn(['updates', 'lastCheckTimestamp'], (new Date()).getTime()) appState = appState.setIn(['updates', 'lastCheckYMD'], dates.todayYMD()) appState = appState.setIn(['updates', 'lastCheckWOY'], dates.todayWOY()) appState = appState.setIn(['updates', 'lastCheckMonth'], dates.todayMonth()) appState = appState.setIn(['updates', 'firstCheckMade'], true) break - case AppConstants.APP_SET_UPDATE_STATUS: + case appConstants.APP_SET_UPDATE_STATUS: if (action.status !== undefined) { appState = appState.setIn(['updates', 'status'], action.status) } @@ -540,34 +540,34 @@ const handleAppAction = (action) => { app.quit() } break - case AppConstants.APP_SET_RESOURCE_ENABLED: + case appConstants.APP_SET_RESOURCE_ENABLED: appState = appState.setIn([action.resourceName, 'enabled'], action.enabled) break - case AppConstants.APP_RESOURCE_READY: + case appConstants.APP_RESOURCE_READY: appState = appState.setIn([action.resourceName, 'ready'], true) break - case AppConstants.APP_ADD_RESOURCE_COUNT: + case appConstants.APP_ADD_RESOURCE_COUNT: const oldCount = appState.getIn([action.resourceName, 'count']) || 0 appState = appState.setIn([action.resourceName, 'count'], oldCount + action.count) break - case AppConstants.APP_SET_DATA_FILE_LAST_CHECK: + case appConstants.APP_SET_DATA_FILE_LAST_CHECK: appState = appState.mergeIn([action.resourceName], { lastCheckVersion: action.lastCheckVersion, lastCheckDate: action.lastCheckDate }) break - case AppConstants.APP_CHANGE_SETTING: + case appConstants.APP_CHANGE_SETTING: appState = appState.setIn(['settings', action.key], action.value) handleChangeSettingAction(action.key, action.value) break - case AppConstants.APP_CHANGE_SITE_SETTING: + case appConstants.APP_CHANGE_SITE_SETTING: { let propertyName = action.temporary ? 'temporarySiteSettings' : 'siteSettings' appState = appState.set(propertyName, siteSettings.mergeSiteSetting(appState.get(propertyName), action.hostPattern, action.key, action.value)) break } - case AppConstants.APP_REMOVE_SITE_SETTING: + case appConstants.APP_REMOVE_SITE_SETTING: { let propertyName = action.temporary ? 'temporarySiteSettings' : 'siteSettings' let newSiteSettings = siteSettings.removeSiteSetting(appState.get(propertyName), @@ -575,7 +575,7 @@ const handleAppAction = (action) => { appState = appState.set(propertyName, newSiteSettings) break } - case AppConstants.APP_CLEAR_SITE_SETTINGS: + case appConstants.APP_CLEAR_SITE_SETTINGS: { let propertyName = action.temporary ? 'temporarySiteSettings' : 'siteSettings' let newSiteSettings = new Immutable.Map() @@ -585,13 +585,13 @@ const handleAppAction = (action) => { appState = appState.set(propertyName, newSiteSettings) break } - case AppConstants.APP_UPDATE_LEDGER_INFO: + case appConstants.APP_UPDATE_LEDGER_INFO: appState = appState.set('ledgerInfo', Immutable.fromJS(action.ledgerInfo)) break - case AppConstants.APP_UPDATE_PUBLISHER_INFO: + case appConstants.APP_UPDATE_PUBLISHER_INFO: appState = appState.set('publisherInfo', Immutable.fromJS(action.publisherInfo)) break - case AppConstants.APP_SHOW_MESSAGE_BOX: + case appConstants.APP_SHOW_MESSAGE_BOX: let notifications = appState.get('notifications') notifications = notifications.filterNot((notification) => { let message = notification.get('message') @@ -622,17 +622,17 @@ const handleAppAction = (action) => { notifications = notifications.insert(insertIndex, Immutable.fromJS(action.detail)) appState = appState.set('notifications', notifications) break - case AppConstants.APP_HIDE_MESSAGE_BOX: + case appConstants.APP_HIDE_MESSAGE_BOX: appState = appState.set('notifications', appState.get('notifications').filterNot((notification) => { return notification.get('message') === action.message })) break - case AppConstants.APP_CLEAR_MESSAGE_BOXES: + case appConstants.APP_CLEAR_MESSAGE_BOXES: appState = appState.set('notifications', appState.get('notifications').filterNot((notification) => { return notification.get('frameOrigin') === action.origin })) break - case AppConstants.APP_ADD_WORD: + case appConstants.APP_ADD_WORD: let listType = 'ignoredWords' if (action.learn) { listType = 'addedWords' @@ -643,31 +643,31 @@ const handleAppAction = (action) => { appState = appState.setIn(path, wordList.push(action.word)) } break - case AppConstants.APP_SET_DICTIONARY: + case appConstants.APP_SET_DICTIONARY: appState = appState.setIn(['dictionary', 'locale'], action.locale) break - case AppConstants.APP_BACKUP_KEYS: + case appConstants.APP_BACKUP_KEYS: appState = ledger.backupKeys(appState, action) break - case AppConstants.APP_RECOVER_WALLET: + case appConstants.APP_RECOVER_WALLET: appState = ledger.recoverKeys(appState, action) break - case AppConstants.APP_LEDGER_RECOVERY_SUCCEEDED: + case appConstants.APP_LEDGER_RECOVERY_SUCCEEDED: appState = appState.setIn(['ui', 'about', 'preferences', 'recoverySucceeded'], true) break - case AppConstants.APP_LEDGER_RECOVERY_FAILED: + case appConstants.APP_LEDGER_RECOVERY_FAILED: appState = appState.setIn(['ui', 'about', 'preferences', 'recoverySucceeded'], false) break - case AppConstants.APP_CLEAR_RECOVERY: + case appConstants.APP_CLEAR_RECOVERY: appState = appState.setIn(['ui', 'about', 'preferences', 'recoverySucceeded'], undefined) break - case AppConstants.APP_CLEAR_DATA: + case appConstants.APP_CLEAR_DATA: if (action.clearDataDetail.get('browserHistory')) { - handleAppAction({actionType: AppConstants.APP_CLEAR_HISTORY}) + handleAppAction({actionType: appConstants.APP_CLEAR_HISTORY}) BrowserWindow.getAllWindows().forEach((wnd) => wnd.webContents.send(messages.CLEAR_CLOSED_FRAMES)) } if (action.clearDataDetail.get('downloadHistory')) { - handleAppAction({actionType: AppConstants.APP_CLEAR_COMPLETED_DOWNLOADS}) + handleAppAction({actionType: appConstants.APP_CLEAR_COMPLETED_DOWNLOADS}) } // Site cookies clearing should also clear cache so that evercookies will be properly removed if (action.clearDataDetail.get('cachedImagesAndFiles') || action.clearDataDetail.get('allSiteCookies')) { @@ -675,7 +675,7 @@ const handleAppAction = (action) => { Filtering.clearCache() } if (action.clearDataDetail.get('savedPasswords')) { - handleAppAction({actionType: AppConstants.APP_CLEAR_PASSWORDS}) + handleAppAction({actionType: appConstants.APP_CLEAR_PASSWORDS}) } if (action.clearDataDetail.get('allSiteCookies')) { const Filtering = require('../../app/filtering') @@ -692,7 +692,7 @@ const handleAppAction = (action) => { appState = appState.set('temporarySiteSettings', Immutable.Map()) } break - case AppConstants.APP_IMPORT_BROWSER_DATA: + case appConstants.APP_IMPORT_BROWSER_DATA: { const importer = require('../../app/importer') if (action.selected.get('type') === 5) { @@ -704,34 +704,34 @@ const handleAppAction = (action) => { } break } - case AppConstants.APP_ADD_AUTOFILL_ADDRESS: + case appConstants.APP_ADD_AUTOFILL_ADDRESS: autofill.addAutofillAddress(action.detail.toJS(), action.originalDetail.get('guid') === undefined ? '-1' : action.originalDetail.get('guid')) break - case AppConstants.APP_REMOVE_AUTOFILL_ADDRESS: + case appConstants.APP_REMOVE_AUTOFILL_ADDRESS: autofill.removeAutofillAddress(action.detail.get('guid')) break - case AppConstants.APP_ADD_AUTOFILL_CREDIT_CARD: + case appConstants.APP_ADD_AUTOFILL_CREDIT_CARD: autofill.addAutofillCreditCard(action.detail.toJS(), action.originalDetail.get('guid') === undefined ? '-1' : action.originalDetail.get('guid')) break - case AppConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD: + case appConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD: autofill.removeAutofillCreditCard(action.detail.get('guid')) break - case AppConstants.APP_AUTOFILL_DATA_CHANGED: + case appConstants.APP_AUTOFILL_DATA_CHANGED: const date = new Date().getTime() appState = appState.setIn(['autofill', 'addresses', 'guid'], action.addressGuids) appState = appState.setIn(['autofill', 'addresses', 'timestamp'], date) appState = appState.setIn(['autofill', 'creditCards', 'guid'], action.creditCardGuids) appState = appState.setIn(['autofill', 'creditCards', 'timestamp'], date) break - case AppConstants.APP_SET_LOGIN_REQUIRED_DETAIL: + case appConstants.APP_SET_LOGIN_REQUIRED_DETAIL: appState = basicAuthState.setLoginRequiredDetail(appState, action) break - case AppConstants.APP_SET_LOGIN_RESPONSE_DETAIL: + case appConstants.APP_SET_LOGIN_RESPONSE_DETAIL: appState = basicAuth.setLoginResponseDetail(appState, action) break - case WindowConstants.WINDOW_CLOSE_FRAME: + case windowConstants.WINDOW_CLOSE_FRAME: appState = tabState.closeFrame(appState, action) break case ExtensionConstants.BROWSER_ACTION_REGISTERED: @@ -759,29 +759,29 @@ const handleAppAction = (action) => { process.emit('chrome-context-menus-clicked', action.extensionId, action.tabId, action.info.toJS()) break - case AppConstants.APP_SET_MENUBAR_TEMPLATE: + case appConstants.APP_SET_MENUBAR_TEMPLATE: appState = appState.setIn(['menu', 'template'], action.menubarTemplate) break - case AppConstants.APP_UPDATE_ADBLOCK_DATAFILES: + case appConstants.APP_UPDATE_ADBLOCK_DATAFILES: const adblock = require('../../app/adBlock') adblock.updateAdblockDataFiles(action.uuid, action.enable) handleAppAction({ - actionType: AppConstants.APP_CHANGE_SETTING, + actionType: appConstants.APP_CHANGE_SETTING, key: `adblock.${action.uuid}.enabled`, value: action.enable }) return - case AppConstants.APP_UPDATE_ADBLOCK_CUSTOM_RULES: { + case appConstants.APP_UPDATE_ADBLOCK_CUSTOM_RULES: { const adblock = require('../../app/adBlock') adblock.updateAdblockCustomRules(action.rules) handleAppAction({ - actionType: AppConstants.APP_CHANGE_SETTING, + actionType: appConstants.APP_CHANGE_SETTING, key: settings.ADBLOCK_CUSTOM_RULES, value: action.rules }) return } - case AppConstants.APP_DEFAULT_BROWSER_UPDATED: + case appConstants.APP_DEFAULT_BROWSER_UPDATED: if (action.useBrave) { for (const p of defaultProtocols) { app.setAsDefaultProtocolClient(p) @@ -790,26 +790,26 @@ const handleAppAction = (action) => { let isDefaultBrowser = defaultProtocols.every(p => app.isDefaultProtocolClient(p)) appState = appState.setIn(['settings', settings.IS_DEFAULT_BROWSER], isDefaultBrowser) break - case AppConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE: + case appConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE: appState = appState.set('defaultBrowserCheckComplete', {}) break - case WindowConstants.WINDOW_SET_FAVICON: - appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) - appState = aboutNewTabState.setSites(appState, action) - break - case AppConstants.APP_TAB_CREATED: + case appConstants.APP_TAB_CREATED: appState = tabState.maybeCreateTab(appState, action) break - case AppConstants.APP_TAB_UPDATED: + case appConstants.APP_TAB_UPDATED: appState = tabState.maybeCreateTab(appState, action) break - case AppConstants.APP_CLOSE_TAB: + case appConstants.APP_CLOSE_TAB: appState = tabs.removeTab(appState, action) break - case AppConstants.APP_TAB_CLOSED: + case appConstants.APP_TAB_CLOSED: appState = tabState.removeTab(appState, action) break - case WindowConstants.WINDOW_SET_AUDIO_MUTED: + case windowConstants.WINDOW_SET_FAVICON: + appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) + appState = aboutNewTabState.setSites(appState, action) + break + case windowConstants.WINDOW_SET_AUDIO_MUTED: appState = tabs.setAudioMuted(appState, action) break case AppConstants.APP_RENDER_URL_TO_PDF: diff --git a/js/stores/eventStore.js b/js/stores/eventStore.js index 98c5adfaed4..5b441281be8 100644 --- a/js/stores/eventStore.js +++ b/js/stores/eventStore.js @@ -2,12 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -const AppConstants = require('../constants/appConstants') +const appConstants = require('../constants/appConstants') const AppDispatcher = require('../dispatcher/appDispatcher') const AppStore = require('./appStore') const EventEmitter = require('events').EventEmitter const Immutable = require('immutable') -const WindowConstants = require('../constants/windowConstants') +const windowConstants = require('../constants/windowConstants') const debounce = require('../lib/debounce') const {isSourceAboutUrl} = require('../lib/appUrlUtil') const {responseHasContent} = require('../../app/common/lib/httpUtil') @@ -90,21 +90,21 @@ const windowClosed = (windowId) => { // Register callback to handle all updates const doAction = (action) => { switch (action.actionType) { - case WindowConstants.WINDOW_SET_FOCUSED_FRAME: + case windowConstants.WINDOW_SET_FOCUSED_FRAME: lastActiveTabId = action.frameProps.get('tabId') addPageView(action.frameProps.get('location'), lastActiveTabId) break - case AppConstants.APP_WINDOW_BLURRED: + case appConstants.APP_WINDOW_BLURRED: windowBlurred(action.windowId) break - case AppConstants.APP_IDLE_STATE_CHANGED: + case appConstants.APP_IDLE_STATE_CHANGED: if (action.idleState !== 'active') { addPageView(null, null) } else { addPageView(lastActivePageUrl, lastActiveTabId) } break - case AppConstants.APP_CLOSE_WINDOW: + case appConstants.APP_CLOSE_WINDOW: AppDispatcher.waitFor([AppStore.dispatchToken], () => { windowClosed(action.windowId) }) @@ -113,7 +113,7 @@ const doAction = (action) => { // retains all past pages, not really sure that's needed... [MTR] eventState = eventState.set('page_info', eventState.get('page_info').push(action.pageInfo)) break - case WindowConstants.WINDOW_GOT_RESPONSE_DETAILS: + case windowConstants.WINDOW_GOT_RESPONSE_DETAILS: // Only capture response for the page (not subresources, like images, JavaScript, etc) if (action.details && action.details.get('resourceType') === 'mainFrame') { const pageUrl = action.details.get('newURL') diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index dc857426662..68d77eafa0b 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -4,8 +4,8 @@ const AppDispatcher = require('../dispatcher/appDispatcher') const EventEmitter = require('events').EventEmitter -const AppConstants = require('../constants/appConstants') -const WindowConstants = require('../constants/windowConstants') +const appConstants = require('../constants/appConstants') +const windowConstants = require('../constants/windowConstants') const config = require('../constants/config') const settings = require('../constants/settings') const Immutable = require('immutable') @@ -246,7 +246,7 @@ const emitChanges = debounce(windowStore.emitChanges.bind(windowStore), 5) const doAction = (action) => { // console.log(action.actionType, action, windowState.toJS()) switch (action.actionType) { - case WindowConstants.WINDOW_SET_STATE: + case windowConstants.WINDOW_SET_STATE: windowState = action.windowState currentKey = windowState.get('frames').reduce((previousVal, frame) => Math.max(previousVal, frame.get('key')), 0) currentPartitionNumber = windowState.get('frames').reduce((previousVal, frame) => Math.max(previousVal, frame.get('partitionNumber')), 0) @@ -256,7 +256,7 @@ const doAction = (action) => { } // We should not emit here because the Window already know about the change on startup. return - case WindowConstants.WINDOW_SET_URL: + case windowConstants.WINDOW_SET_URL: const frame = FrameStateUtil.getFrameByKey(windowState, action.key) const currentLocation = frame.get('location') const parsedUrl = urlParse(action.location) @@ -304,7 +304,7 @@ const doAction = (action) => { updateNavBarInput(action.location, frameStatePath(action.key)) } break - case WindowConstants.WINDOW_SET_NAVIGATED: + case windowConstants.WINDOW_SET_NAVIGATED: action.location = action.location.trim() windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'shouldRender']), false) // For about: URLs, make sure we store the URL as about:something @@ -354,18 +354,18 @@ const doAction = (action) => { updateNavBarInput(action.location, frameStatePath(key)) } break - case WindowConstants.WINDOW_SET_NAVBAR_INPUT: + case windowConstants.WINDOW_SET_NAVBAR_INPUT: updateNavBarInput(action.location) updateUrlSuffix(windowState.getIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'suggestionList']), action.suggestionList)) // Since this value is bound we need to notify the control sync windowStore.emitChanges() return - case WindowConstants.WINDOW_SET_FRAME_TAB_ID: + case windowConstants.WINDOW_SET_FRAME_TAB_ID: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { tabId: action.tabId }) break - case WindowConstants.WINDOW_SET_FRAME_ERROR: + case windowConstants.WINDOW_SET_FRAME_ERROR: const frameKey = action.frameProps.get('key') // set the previous location to the most recent history item or the default url let previousLocation = action.frameProps.get('history').unshift(config.defaultUrl).findLast((url) => url !== action.errorDetails.url) @@ -379,7 +379,7 @@ const doAction = (action) => { }, action.errorDetails) }) break - case WindowConstants.WINDOW_SET_FRAME_TITLE: + case windowConstants.WINDOW_SET_FRAME_TITLE: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { title: action.title }) @@ -387,7 +387,7 @@ const doAction = (action) => { title: action.title }) break - case WindowConstants.WINDOW_SET_FINDBAR_SHOWN: + case windowConstants.WINDOW_SET_FINDBAR_SHOWN: if (action.shown) { windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'shouldRender']), false) } @@ -398,12 +398,12 @@ const doAction = (action) => { findbarSelected: action.shown }) break - case WindowConstants.WINDOW_SET_FINDBAR_SELECTED: + case windowConstants.WINDOW_SET_FINDBAR_SELECTED: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { findbarSelected: action.selected }) break - case WindowConstants.WINDOW_WEBVIEW_LOAD_START: + case windowConstants.WINDOW_WEBVIEW_LOAD_START: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { loading: true, provisionalLocation: action.location, @@ -415,7 +415,7 @@ const doAction = (action) => { provisionalLocation: action.location }) break - case WindowConstants.WINDOW_WEBVIEW_LOAD_END: + case windowConstants.WINDOW_WEBVIEW_LOAD_END: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { loading: false, endLoadTime: new Date().getTime(), @@ -425,13 +425,13 @@ const doAction = (action) => { loading: false }) break - case WindowConstants.WINDOW_SET_FULL_SCREEN: + case windowConstants.WINDOW_SET_FULL_SCREEN: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { isFullScreen: action.isFullScreen !== undefined ? action.isFullScreen : windowState.getIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)].concat('isFullScreen')), showFullScreenWarning: action.showFullScreenWarning }) break - case WindowConstants.WINDOW_SET_NAVBAR_FOCUSED: + case windowConstants.WINDOW_SET_NAVBAR_FOCUSED: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'focused']), action.focused) windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'focused']), action.focused) // selection should be cleared on blur @@ -439,13 +439,13 @@ const doAction = (action) => { windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'selected']), false) } break - case WindowConstants.WINDOW_NEW_FRAME: + case windowConstants.WINDOW_NEW_FRAME: newFrame(action.frameOpts, action.openInForeground) break - case WindowConstants.WINDOW_VIEW_KEY: + case windowConstants.WINDOW_VIEW_KEY: newFrame(action.frameOpts, action.openInForeground) break - case WindowConstants.WINDOW_CLONE_FRAME: + case windowConstants.WINDOW_CLONE_FRAME: { let insertionIndex = FrameStateUtil.findIndexForFrameKey(windowState.get('frames'), action.frameOpts.key) + 1 const nextKey = incrementNextKey() @@ -453,7 +453,7 @@ const doAction = (action) => { action.openInForeground, insertionIndex, nextKey) break } - case WindowConstants.WINDOW_CLOSE_FRAME: + case windowConstants.WINDOW_CLOSE_FRAME: // Use the frameProps we passed in, or default to the active frame const frameProps = action.frameProps || FrameStateUtil.getActiveFrame(windowState) const index = FrameStateUtil.getFramePropsIndex(windowState.get('frames'), frameProps) @@ -468,14 +468,14 @@ const doAction = (action) => { updateTabPageIndex(FrameStateUtil.getActiveFrame(windowState)) } break - case WindowConstants.WINDOW_UNDO_CLOSED_FRAME: + case windowConstants.WINDOW_UNDO_CLOSED_FRAME: windowState = windowState.merge(FrameStateUtil.undoCloseFrame(windowState, windowState.get('closedFrames'))) focusWebview(activeFrameStatePath()) break - case WindowConstants.WINDOW_CLEAR_CLOSED_FRAMES: + case windowConstants.WINDOW_CLEAR_CLOSED_FRAMES: windowState = windowState.set('closedFrames', new Immutable.List()) break - case WindowConstants.WINDOW_SET_ACTIVE_FRAME: + case windowConstants.WINDOW_SET_ACTIVE_FRAME: if (!action.frameProps) { break } @@ -486,20 +486,20 @@ const doAction = (action) => { windowState = windowState.deleteIn(['ui', 'tabs', 'previewTabPageIndex']) updateTabPageIndex(action.frameProps) break - case WindowConstants.WINDOW_SET_PREVIEW_FRAME: + case windowConstants.WINDOW_SET_PREVIEW_FRAME: windowState = windowState.merge({ previewFrameKey: action.frameProps && action.frameProps.get('key') !== windowState.get('activeFrameKey') ? action.frameProps.get('key') : null }) break - case WindowConstants.WINDOW_SET_PREVIEW_TAB_PAGE_INDEX: + case windowConstants.WINDOW_SET_PREVIEW_TAB_PAGE_INDEX: if (action.previewTabPageIndex !== windowState.getIn(['ui', 'tabs', 'tabPageIndex'])) { windowState = windowState.setIn(['ui', 'tabs', 'previewTabPageIndex'], action.previewTabPageIndex) } else { windowState = windowState.deleteIn(['ui', 'tabs', 'previewTabPageIndex']) } break - case WindowConstants.WINDOW_SET_TAB_PAGE_INDEX: + case windowConstants.WINDOW_SET_TAB_PAGE_INDEX: if (action.index !== undefined) { windowState = windowState.setIn(['ui', 'tabs', 'tabPageIndex'], action.index) windowState = windowState.deleteIn(['ui', 'tabs', 'previewTabPageIndex']) @@ -507,20 +507,20 @@ const doAction = (action) => { updateTabPageIndex(action.frameProps) } break - case WindowConstants.WINDOW_UPDATE_BACK_FORWARD: + case windowConstants.WINDOW_UPDATE_BACK_FORWARD: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { canGoBack: action.canGoBack, canGoForward: action.canGoForward }) break - case WindowConstants.WINDOW_SET_IS_BEING_DRAGGED_OVER_DETAIL: + case windowConstants.WINDOW_SET_IS_BEING_DRAGGED_OVER_DETAIL: if (!action.dragOverKey) { windowState = windowState.deleteIn(['ui', 'dragging']) } else { windowState = windowState.mergeIn(['ui', 'dragging', 'draggingOver'], Immutable.fromJS(Object.assign({}, action.dragDetail, { dragOverKey: action.dragOverKey, dragType: action.dragType }))) } break - case WindowConstants.WINDOW_TAB_MOVE: + case windowConstants.WINDOW_TAB_MOVE: const sourceFramePropsIndex = FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.sourceFrameProps) let newIndex = FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.destinationFrameProps) + (action.prepend ? 0 : 1) let frames = windowState.get('frames').splice(sourceFramePropsIndex, 1) @@ -535,13 +535,13 @@ const doAction = (action) => { // Since the tab could have changed pages, update the tab page as well updateTabPageIndex(FrameStateUtil.getActiveFrame(windowState)) break - case WindowConstants.WINDOW_SET_LINK_HOVER_PREVIEW: + case windowConstants.WINDOW_SET_LINK_HOVER_PREVIEW: windowState = windowState.mergeIn(activeFrameStatePath(), { hrefPreview: action.href, showOnRight: action.showOnRight }) break - case WindowConstants.WINDOW_SET_URL_BAR_SUGGESTIONS: + case windowConstants.WINDOW_SET_URL_BAR_SUGGESTIONS: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'selectedIndex']), action.selectedIndex) if (action.suggestionList !== undefined) { @@ -549,13 +549,13 @@ const doAction = (action) => { } updateUrlSuffix(action.suggestionList) break - case WindowConstants.WINDOW_SET_URL_BAR_PREVIEW: + case windowConstants.WINDOW_SET_URL_BAR_PREVIEW: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'urlPreview']), action.value) break - case WindowConstants.WINDOW_SET_URL_BAR_SUGGESTION_SEARCH_RESULTS: + case windowConstants.WINDOW_SET_URL_BAR_SUGGESTION_SEARCH_RESULTS: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'searchResults']), action.searchResults) break - case WindowConstants.WINDOW_SET_THEME_COLOR: + case windowConstants.WINDOW_SET_THEME_COLOR: if (action.themeColor !== undefined) { windowState = windowState.setIn(frameStatePathForFrame(action.frameProps).concat(['themeColor']), action.themeColor) windowState = windowState.setIn(tabStatePathForFrame(action.frameProps).concat(['themeColor']), action.themeColor) @@ -565,7 +565,7 @@ const doAction = (action) => { windowState = windowState.setIn(tabStatePathForFrame(action.frameProps).concat(['computedThemeColor']), action.computedThemeColor) } break - case WindowConstants.WINDOW_SET_URL_BAR_ACTIVE: + case windowConstants.WINDOW_SET_URL_BAR_ACTIVE: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'active']), action.isActive) if (!action.isActive) { windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'shouldRender']), false) @@ -575,7 +575,7 @@ const doAction = (action) => { }) } break - case WindowConstants.WINDOW_SET_RENDER_URL_BAR_SUGGESTIONS: + case windowConstants.WINDOW_SET_RENDER_URL_BAR_SUGGESTIONS: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'shouldRender']), action.enabled) if (!action.enabled) { windowState = windowState.mergeIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions']), { @@ -587,13 +587,13 @@ const doAction = (action) => { updateUrlSuffix(undefined) } break - case WindowConstants.WINDOW_SET_URL_BAR_AUTCOMPLETE_ENABLED: + case windowConstants.WINDOW_SET_URL_BAR_AUTCOMPLETE_ENABLED: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'suggestions', 'autocompleteEnabled']), action.enabled) break - case WindowConstants.WINDOW_SET_URL_BAR_FOCUSED: + case windowConstants.WINDOW_SET_URL_BAR_FOCUSED: windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'focused']), action.isFocused) break - case WindowConstants.WINDOW_SET_URL_BAR_SELECTED: + case windowConstants.WINDOW_SET_URL_BAR_SELECTED: const urlBarPath = activeFrameStatePath().concat(['navbar', 'urlbar']) windowState = windowState.mergeIn(urlBarPath, { selected: action.selected @@ -603,24 +603,24 @@ const doAction = (action) => { windowState = windowState.setIn(activeFrameStatePath().concat(['navbar', 'urlbar', 'focused']), true) } break - case WindowConstants.WINDOW_SET_ACTIVE_FRAME_SHORTCUT: + case windowConstants.WINDOW_SET_ACTIVE_FRAME_SHORTCUT: const framePath = action.frameProps ? ['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)] : activeFrameStatePath() windowState = windowState.mergeIn(framePath, { activeShortcut: action.activeShortcut, activeShortcutDetails: action.activeShortcutDetails }) break - case WindowConstants.WINDOW_SET_SEARCH_DETAIL: + case windowConstants.WINDOW_SET_SEARCH_DETAIL: windowState = windowState.merge({ searchDetail: action.searchDetail }) break - case WindowConstants.WINDOW_SET_FIND_DETAIL: + case windowConstants.WINDOW_SET_FIND_DETAIL: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'findDetail'], action.findDetail) // Since the input value is bound, we need to notify the control sync. windowStore.emitChanges() return - case WindowConstants.WINDOW_SET_BOOKMARK_DETAIL: + case windowConstants.WINDOW_SET_BOOKMARK_DETAIL: if (!action.currentDetail && !action.originalDetail) { windowState = windowState.delete('bookmarkDetail') } else { @@ -635,12 +635,12 @@ const doAction = (action) => { // Since the input values of bookmarks are bound, we need to notify the controls sync. windowStore.emitChanges() return - case WindowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED: + case windowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED: ipc.send('autofill-selection-clicked', action.tabId, action.value, action.frontEndId, action.index) windowState = windowState.delete('contextMenuDetail') break - case WindowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN: - case WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL: + case windowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN: + case windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL: if (!action.detail) { if (windowState.getIn('contextMenuDetail', 'type') === 'autofill' && windowState.getIn('contextMenuDetail', 'tabId') === action.tabId) { @@ -655,7 +655,7 @@ const doAction = (action) => { // Drag and drop bookmarks code expects this to be set sync windowStore.emitChanges() return - case WindowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL: + case windowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL: if (!action.detail) { windowState = windowState.delete('popupWindowDetail') } else { @@ -664,7 +664,7 @@ const doAction = (action) => { // Drag and drop bookmarks code expects this to be set sync windowStore.emitChanges() return - case WindowConstants.WINDOW_SET_PINNED: + case windowConstants.WINDOW_SET_PINNED: // Check if there's already a frame which is pinned. // If so we just want to set it as active. const location = action.frameProps.get('location') @@ -672,9 +672,9 @@ const doAction = (action) => { (frame) => frame.get('pinnedLocation') && frame.get('pinnedLocation') === location && (action.frameProps.get('partitionNumber') || 0) === (frame.get('partitionNumber') || 0)) if (alreadyPinnedFrameProps && action.isPinned) { - action.actionType = WindowConstants.WINDOW_CLOSE_FRAME + action.actionType = windowConstants.WINDOW_CLOSE_FRAME doAction(action) - action.actionType = WindowConstants.WINDOW_SET_ACTIVE_FRAME + action.actionType = windowConstants.WINDOW_SET_ACTIVE_FRAME action.frameProps = alreadyPinnedFrameProps doAction(action) } else { @@ -693,43 +693,43 @@ const doAction = (action) => { // change detection where it adds a second frame windowStore.emitChanges() return - case WindowConstants.WINDOW_SET_AUDIO_MUTED: + case windowConstants.WINDOW_SET_AUDIO_MUTED: windowState = windowState.setIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'audioMuted'], action.muted) windowState = windowState.setIn(['tabs', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'audioMuted'], action.muted) break - case WindowConstants.WINDOW_SET_AUDIO_PLAYBACK_ACTIVE: + case windowConstants.WINDOW_SET_AUDIO_PLAYBACK_ACTIVE: windowState = windowState.setIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'audioPlaybackActive'], action.audioPlaybackActive) windowState = windowState.setIn(['tabs', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'audioPlaybackActive'], action.audioPlaybackActive) break - case WindowConstants.WINDOW_SET_FAVICON: + case windowConstants.WINDOW_SET_FAVICON: windowState = windowState.setIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'icon'], action.favicon) windowState = windowState.setIn(['tabs', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'icon'], action.favicon) break - case WindowConstants.WINDOW_SET_LAST_ZOOM_PERCENTAGE: + case windowConstants.WINDOW_SET_LAST_ZOOM_PERCENTAGE: windowState = windowState.setIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'lastZoomPercentage'], action.percentage) break - case WindowConstants.WINDOW_SET_MAXIMIZE_STATE: + case windowConstants.WINDOW_SET_MAXIMIZE_STATE: windowState = windowState.setIn(['ui', 'isMaximized'], action.isMaximized) break - case WindowConstants.WINDOW_SAVE_POSITION: + case windowConstants.WINDOW_SAVE_POSITION: windowState = windowState.setIn(['ui', 'position'], action.position) break - case WindowConstants.WINDOW_SAVE_SIZE: + case windowConstants.WINDOW_SAVE_SIZE: windowState = windowState.setIn(['ui', 'size'], action.size) break - case WindowConstants.WINDOW_SET_FULLSCREEN_STATE: + case windowConstants.WINDOW_SET_FULLSCREEN_STATE: windowState = windowState.setIn(['ui', 'isFullScreen'], action.isFullScreen) break - case WindowConstants.WINDOW_SET_MOUSE_IN_TITLEBAR: + case windowConstants.WINDOW_SET_MOUSE_IN_TITLEBAR: windowState = windowState.setIn(['ui', 'mouseInTitlebar'], action.mouseInTitlebar) break - case WindowConstants.WINDOW_SET_NOSCRIPT_VISIBLE: + case windowConstants.WINDOW_SET_NOSCRIPT_VISIBLE: windowState = windowState.setIn(['ui', 'noScriptInfo', 'isVisible'], action.isVisible) break - case WindowConstants.WINDOW_SET_SITE_INFO_VISIBLE: + case windowConstants.WINDOW_SET_SITE_INFO_VISIBLE: windowState = windowState.setIn(['ui', 'siteInfo', 'isVisible'], action.isVisible) break - case WindowConstants.WINDOW_SET_BRAVERY_PANEL_DETAIL: + case windowConstants.WINDOW_SET_BRAVERY_PANEL_DETAIL: if (!action.braveryPanelDetail) { windowState = windowState.delete('braveryPanelDetail') } else { @@ -742,35 +742,35 @@ const doAction = (action) => { }) } break - case WindowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL: + case windowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL: if (!action.clearBrowsingDataDetail) { windowState = windowState.delete('clearBrowsingDataDetail') } else { windowState = windowState.set('clearBrowsingDataDetail', Immutable.fromJS(action.clearBrowsingDataDetail)) } break - case WindowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_DETAIL: + case windowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_DETAIL: if (!action.importBrowserDataDetail) { windowState = windowState.delete('importBrowserDataDetail') } else { windowState = windowState.set('importBrowserDataDetail', Immutable.fromJS(action.importBrowserDataDetail)) } break - case WindowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_SELECTED: + case windowConstants.WINDOW_SET_IMPORT_BROWSER_DATA_SELECTED: if (!action.selected) { windowState = windowState.delete('importBrowserDataSelected') } else { windowState = windowState.set('importBrowserDataSelected', Immutable.fromJS(action.selected)) } break - case WindowConstants.WINDOW_WIDEVINE_PANEL_DETAIL_CHANGED: + case windowConstants.WINDOW_WIDEVINE_PANEL_DETAIL_CHANGED: if (!action.widevinePanelDetail) { windowState = windowState.delete('widevinePanelDetail') } else { windowState = windowState.mergeIn(['widevinePanelDetail'], Immutable.fromJS(action.widevinePanelDetail)) } break - case WindowConstants.WINDOW_WIDEVINE_SITE_ACCESSED_WITHOUT_INSTALL: + case windowConstants.WINDOW_WIDEVINE_SITE_ACCESSED_WITHOUT_INSTALL: const activeLocation = windowState.getIn(activeFrameStatePath().concat(['location'])) windowState = windowState.set('widevinePanelDetail', Immutable.Map({ alsoAddRememberSiteSetting: true, @@ -778,7 +778,7 @@ const doAction = (action) => { shown: true })) break - case WindowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL: + case windowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL: if (!action.currentDetail && !action.originalDetail) { windowState = windowState.delete('autofillAddressDetail') } else { @@ -790,7 +790,7 @@ const doAction = (action) => { // Since the input values of address are bound, we need to notify the controls sync. windowStore.emitChanges() break - case WindowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL: + case windowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL: if (!action.currentDetail && !action.originalDetail) { windowState = windowState.delete('autofillCreditCardDetail') } else { @@ -802,13 +802,13 @@ const doAction = (action) => { // Since the input values of credit card are bound, we need to notify the controls sync. windowStore.emitChanges() break - case WindowConstants.WINDOW_SET_DOWNLOADS_TOOLBAR_VISIBLE: + case windowConstants.WINDOW_SET_DOWNLOADS_TOOLBAR_VISIBLE: windowState = windowState.setIn(['ui', 'downloadsToolbar', 'isVisible'], action.isVisible) break - case WindowConstants.WINDOW_SET_RELEASE_NOTES_VISIBLE: + case windowConstants.WINDOW_SET_RELEASE_NOTES_VISIBLE: windowState = windowState.setIn(['ui', 'releaseNotes', 'isVisible'], action.isVisible) break - case WindowConstants.WINDOW_SET_SECURITY_STATE: + case windowConstants.WINDOW_SET_SECURITY_STATE: let path = frameStatePathForFrame(action.frameProps) if (action.securityState.secure !== undefined) { windowState = windowState.setIn(path.concat(['security', 'isSecure']), @@ -823,23 +823,23 @@ const doAction = (action) => { action.securityState.certDetails) } break - case WindowConstants.WINDOW_SET_BLOCKED_BY: + case windowConstants.WINDOW_SET_BLOCKED_BY: const blockedByPath = ['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), action.blockType, 'blocked'] let blockedBy = windowState.getIn(blockedByPath) || new Immutable.List() blockedBy = blockedBy.toSet().add(action.location).toList() windowState = windowState.setIn(blockedByPath, blockedBy) break - case WindowConstants.WINDOW_SET_REDIRECTED_BY: + case windowConstants.WINDOW_SET_REDIRECTED_BY: const redirectedByPath = ['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps), 'httpsEverywhere', action.ruleset] let redirectedBy = windowState.getIn(redirectedByPath) || new Immutable.List() windowState = windowState.setIn(redirectedByPath, redirectedBy.push(action.location)) break - case WindowConstants.WINDOW_ADD_HISTORY: + case windowConstants.WINDOW_ADD_HISTORY: windowState = windowState.mergeIn(['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)], { history: addToHistory(action.frameProps) }) break - case WindowConstants.WINDOW_SET_BLOCKED_RUN_INSECURE_CONTENT: + case windowConstants.WINDOW_SET_BLOCKED_RUN_INSECURE_CONTENT: const blockedRunInsecureContentPath = ['frames', FrameStateUtil.getFramePropsIndex(windowState.get('frames'), action.frameProps)] if (action.source) { @@ -853,53 +853,53 @@ const doAction = (action) => { windowState.deleteIn(blockedRunInsecureContentPath.concat(['security', 'blockedRunInsecureContent'])) } break - case WindowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE: + case windowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE: if (getSetting(settings.AUTO_HIDE_MENU)) { - doAction({actionType: WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL}) + doAction({actionType: windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL}) // Use value if provided; if not, toggle to opposite. const newVisibleStatus = typeof action.isVisible === 'boolean' ? action.isVisible : !windowState.getIn(['ui', 'menubar', 'isVisible']) // Clear selection when menu is shown if (newVisibleStatus) { - doAction({ actionType: WindowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX, index: [0] }) + doAction({ actionType: windowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX, index: [0] }) } windowState = windowState.setIn(['ui', 'menubar', 'isVisible'], newVisibleStatus) } break - case WindowConstants.WINDOW_HIDE_BOOKMARK_HANGER: + case windowConstants.WINDOW_HIDE_BOOKMARK_HANGER: const hangerShowing = windowState.getIn(['bookmarkDetail', 'isBookmarkHanger']) if (hangerShowing) { windowState = windowState.delete('bookmarkDetail') } break - case WindowConstants.WINDOW_RESET_MENU_STATE: - doAction({actionType: WindowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL}) - doAction({actionType: WindowConstants.WINDOW_HIDE_BOOKMARK_HANGER}) + case windowConstants.WINDOW_RESET_MENU_STATE: + doAction({actionType: windowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL}) + doAction({actionType: windowConstants.WINDOW_HIDE_BOOKMARK_HANGER}) if (getSetting(settings.AUTO_HIDE_MENU)) { - doAction({actionType: WindowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE, isVisible: false}) + doAction({actionType: windowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE, isVisible: false}) } else { - doAction({actionType: WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL}) + doAction({actionType: windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL}) } - doAction({actionType: WindowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX}) - doAction({actionType: WindowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID}) + doAction({actionType: windowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX}) + doAction({actionType: windowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID}) break - case WindowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX: + case windowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX: windowState = windowState.setIn(['ui', 'menubar', 'selectedIndex'], Array.isArray(action.index) ? action.index : null) break - case WindowConstants.WINDOW_SET_LAST_FOCUSED_SELECTOR: + case windowConstants.WINDOW_SET_LAST_FOCUSED_SELECTOR: windowState = windowState.setIn(['ui', 'menubar', 'lastFocusedSelector'], action.selector) break - case WindowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID: + case windowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID: windowState = windowState.setIn(['ui', 'bookmarksToolbar', 'selectedFolderId'], action.folderId) break - case WindowConstants.WINDOW_ON_FOCUS_CHANGED: + case windowConstants.WINDOW_ON_FOCUS_CHANGED: windowState = windowState.setIn(['ui', 'hasFocus'], action.hasFocus) break - case WindowConstants.WINDOW_SET_MODAL_DIALOG_DETAIL: + case windowConstants.WINDOW_SET_MODAL_DIALOG_DETAIL: if (action.className && action.props === undefined) { windowState = windowState.deleteIn(['modalDialogDetail', action.className]) } else if (action.className) { @@ -908,7 +908,7 @@ const doAction = (action) => { // Since the input values of address are bound, we need to notify the controls sync. windowStore.emitChanges() break - case AppConstants.APP_NEW_TAB: + case appConstants.APP_NEW_TAB: newFrame(action.frameProps, action.frameProps.get('disposition') === 'foreground-tab') break default: @@ -931,7 +931,7 @@ ipc.on(messages.SHORTCUT_PREV_TAB, () => { ipc.on(messages.SHORTCUT_OPEN_CLEAR_BROWSING_DATA_PANEL, (e, clearBrowsingDataDetail) => { doAction({ - actionType: WindowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL, + actionType: windowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL, clearBrowsingDataDetail }) }) From 2a0c26ab2407077efab50b55ebade2712c40ecb3 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 8 Dec 2016 22:17:51 -0700 Subject: [PATCH 48/80] update for electron new window changes auditors @bbondy @darkdh --- app/browser/reducers/tabsReducer.js | 52 +++++++++++++++++++++++++++++ app/browser/tabs.js | 17 +++++----- app/browser/windows.js | 22 ------------ js/components/frame.js | 2 +- js/stores/appStore.js | 23 ++----------- 5 files changed, 63 insertions(+), 53 deletions(-) create mode 100644 app/browser/reducers/tabsReducer.js diff --git a/app/browser/reducers/tabsReducer.js b/app/browser/reducers/tabsReducer.js new file mode 100644 index 00000000000..9ddd360a1b4 --- /dev/null +++ b/app/browser/reducers/tabsReducer.js @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict' + +const appConfig = require('../../../js/constants/appConfig') +const appConstants = require('../../../js/constants/appConstants') +const tabs = require('../tabs') +const tabState = require('../../common/state/tabState') +const windowConstants = require('../../../js/constants/windowConstants') +const { makeImmutable } = require('../../common/state/immutableUtil') +const { getSiteSettingsForURL } = require('../../../js/state/siteSettings') + +const tabsReducer = (state, action) => { + action = makeImmutable(action) + switch (action.get('actionType')) { + case appConstants.APP_SET_STATE: + state = tabs.init(state, action) + break + case appConstants.APP_TAB_CREATED: + state = tabState.maybeCreateTab(state, action) + break + case appConstants.APP_TAB_UPDATED: + state = tabState.maybeCreateTab(state, action) + break + case appConstants.APP_CLOSE_TAB: + state = tabs.removeTab(state, action) + break + case appConstants.APP_TAB_CLOSED: + state = tabState.removeTab(state, action) + break + case appConstants.APP_ALLOW_FLASH_ONCE: + case appConstants.APP_ALLOW_FLASH_ALWAYS: + { + const webContents = tabs.getWebContents(action.get('tabId')) + if (webContents && !webContents.isDestroyed() && webContents.getURL() === action.get('url')) { + webContents.authorizePlugin(appConfig.flash.resourceId) + } + break + } + case windowConstants.WINDOW_SET_AUDIO_MUTED: + state = tabs.setAudioMuted(state, action) + break + case windowConstants.WINDOW_CLOSE_FRAME: + state = tabState.closeFrame(state, action) + break + } + return state +} + +module.exports = tabsReducer diff --git a/app/browser/tabs.js b/app/browser/tabs.js index 689b4866e03..ab82df90db1 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -15,7 +15,8 @@ const cleanupWebContents = (tabId) => { const getTabValue = function (tabId) { let tab = api.getWebContents(tabId) if (tab) { - return makeImmutable(extensions.tabValue(tab)) + const tabValue = makeImmutable(extensions.tabValue(tab)) + return tabValue.set('tabId', tabId) } } @@ -30,9 +31,13 @@ const updateTab = (tabId) => { const api = { init: (state, action) => { + process.on('add-new-contents', (e, openerTab, newTab, disposition, userGesture) => { + if (userGesture === false) { + e.preventDefault() + } + }) app.on('web-contents-created', function (event, tab) { - // TODO(bridiver) - also exclude extension action windows?? - if (extensions.isBackgroundPage(tab) || !tab.hostWebContents) { + if (extensions.isBackgroundPage(tab) || !tab.isGuest()) { return } let tabId = tab.getId() @@ -50,12 +55,6 @@ const api = { updateTab(tabId) } }) - tab.on('new-window', (e, url, frameName, disposition, options = {}) => { - let userGesture = options.userGesture - if (userGesture === false) { - e.preventDefault() - } - }) tab.on('unresponsive', () => { console.log('unresponsive') }) diff --git a/app/browser/windows.js b/app/browser/windows.js index cd61f18e5f0..76a40610426 100644 --- a/app/browser/windows.js +++ b/app/browser/windows.js @@ -72,28 +72,6 @@ const api = { win.once('closed', () => { cleanupWindow(windowId) }) - win.webContents.on('new-window', (e, url, frameName, disposition, options = {}) => { - let userGesture = options.userGesture - if (userGesture === false) { - e.preventDefault() - } else { - let frameProps = { - location: url, - delayedLoadUrl: options.delayedLoadUrl, - guestInstanceId: options.guestInstanceId, - windowId, - disposition - } - - let windowOpts = options.windowOptions || {} - windowOpts.disposition = disposition - if (disposition === 'new-window' || disposition === 'new-popup') { - appActions.newWindow(frameProps, windowOpts) - } else { - appActions.newTab(frameProps) - } - } - }) win.on('blur', () => { updateWindow(windowId) }) diff --git a/js/components/frame.js b/js/components/frame.js index ded53560759..e66f001a519 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -62,7 +62,7 @@ class Frame extends ImmutableComponent { } get frame () { - return windowStore.getFrame(this.props.frameKey) + return windowStore.getFrame(this.props.frameKey) || {} } get braveryDefaults () { diff --git a/js/stores/appStore.js b/js/stores/appStore.js index a903bfdd02a..bf093e37855 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -33,19 +33,18 @@ const autofill = require('../../app/autofill') const nativeImage = require('../../app/nativeImage') const Filtering = require('../../app/filtering') const basicAuth = require('../../app/browser/basicAuth') -const tabs = require('../../app/browser/tabs') const windows = require('../../app/browser/windows') const downloadsReducer = require('../../app/browser/reducers/downloadsReducer') // state helpers const basicAuthState = require('../../app/common/state/basicAuthState') const extensionState = require('../../app/common/state/extensionState') -const tabState = require('../../app/common/state/tabState') const aboutNewTabState = require('../../app/common/state/aboutNewTabState') const aboutHistoryState = require('../../app/common/state/aboutHistoryState') const windowState = require('../../app/common/state/windowState') const flash = require('../flash.js') +const tabsReducer = require('../../app/browser/reducers/tabsReducer') const webtorrent = require('../../app/browser/webtorrent') const isDarwin = process.platform === 'darwin' @@ -362,13 +361,13 @@ const handleAppAction = (action) => { const ledger = require('../../app/ledger') appState = downloadsReducer(appState, action) + appState = tabsReducer(appState, action) switch (action.actionType) { case appConstants.APP_SET_STATE: appState = action.appState appState = Filtering.init(appState, action, appStore) appState = windows.init(appState, action, appStore) - appState = tabs.init(appState, action, appStore) appState = basicAuth.init(appState, action, appStore) appState = flash.init(appState, action, appStore) appState = webtorrent.init(appState, action, appStore) @@ -731,9 +730,6 @@ const handleAppAction = (action) => { case appConstants.APP_SET_LOGIN_RESPONSE_DETAIL: appState = basicAuth.setLoginResponseDetail(appState, action) break - case windowConstants.WINDOW_CLOSE_FRAME: - appState = tabState.closeFrame(appState, action) - break case ExtensionConstants.BROWSER_ACTION_REGISTERED: appState = extensionState.browserActionRegistered(appState, action) break @@ -793,25 +789,10 @@ const handleAppAction = (action) => { case appConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE: appState = appState.set('defaultBrowserCheckComplete', {}) break - case appConstants.APP_TAB_CREATED: - appState = tabState.maybeCreateTab(appState, action) - break - case appConstants.APP_TAB_UPDATED: - appState = tabState.maybeCreateTab(appState, action) - break - case appConstants.APP_CLOSE_TAB: - appState = tabs.removeTab(appState, action) - break - case appConstants.APP_TAB_CLOSED: - appState = tabState.removeTab(appState, action) - break case windowConstants.WINDOW_SET_FAVICON: appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) appState = aboutNewTabState.setSites(appState, action) break - case windowConstants.WINDOW_SET_AUDIO_MUTED: - appState = tabs.setAudioMuted(appState, action) - break case AppConstants.APP_RENDER_URL_TO_PDF: const pdf = require('../../app/pdf') appState = pdf.renderUrlToPdf(appState, action) From 8f4dbb0236b9f3473e537202522c8c52f70a93ab Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 8 Dec 2016 22:18:41 -0700 Subject: [PATCH 49/80] fix certificate handling auditors @bbondy @diracdeltas --- app/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/index.js b/app/index.js index c9abcdece2a..1c4bf963ed1 100644 --- a/app/index.js +++ b/app/index.js @@ -78,6 +78,7 @@ const settings = require('../js/constants/settings') // temporary fix for #4517, #4518 and #4472 app.commandLine.appendSwitch('enable-use-zoom-for-dsf', 'false') +app.commandLine.appendSwitch('enable-features', 'BlockSmallPluginContent,PreferHtmlOverPlugins') // Used to collect the per window state when shutting down the application let perWindowState = [] @@ -280,12 +281,13 @@ app.on('ready', () => { let host = urlParse(url).host if (host && acceptCertDomains[host] === true) { // Ignore the cert error - cb(true) + cb('continue') return + } else { + cb('deny') } if (resourceType !== 'mainFrame') { - // Block subresources with certificate errors return } From 5ae6c1bcbc2c8ea540773a6c70cff4338972319d Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 8 Dec 2016 22:23:16 -0700 Subject: [PATCH 50/80] convert flash to host content settings auditors @bbondy @diracdeltas --- .../contentSettings/hostContentSettings.js | 33 ++ app/browser/reducers/flashReducer.js | 21 ++ app/browser/reducers/tabsReducer.js | 1 - .../locales/en-US/preferences.properties | 2 +- app/filtering.js | 20 +- app/sessionStore.js | 3 +- docs/state.md | 1 - js/about/aboutActions.js | 4 - js/about/preferences.js | 7 +- js/actions/appActions.js | 17 ++ js/components/frame.js | 5 + js/components/main.js | 1 - js/constants/appConfig.js | 1 + js/constants/appConstants.js | 6 +- js/constants/messages.js | 1 - js/contextMenus.js | 46 +-- js/flash.js | 234 +++----------- js/state/contentSettings.js | 286 ++++++++++-------- js/state/userPrefs.js | 9 +- js/stores/appStore.js | 21 +- 20 files changed, 363 insertions(+), 356 deletions(-) create mode 100644 app/browser/contentSettings/hostContentSettings.js create mode 100644 app/browser/reducers/flashReducer.js diff --git a/app/browser/contentSettings/hostContentSettings.js b/app/browser/contentSettings/hostContentSettings.js new file mode 100644 index 00000000000..7ad5d578867 --- /dev/null +++ b/app/browser/contentSettings/hostContentSettings.js @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { makeImmutable } = require('../../common/state/immutableUtil') + +let registeredSessions = {} + +module.exports.setContentSettings = (contentSettings) => { + contentSettings = makeImmutable(contentSettings) + contentSettings.forEach((settings, contentType) => { + for (let partition in registeredSessions) { + registeredSessions[partition].contentSettings.clearForOneType(contentType) + } + settings.forEach((setting) => { + module.exports.setContentSetting(setting.get('primaryPattern'), setting.get('secondaryPattern'), + contentType, setting.get('resourceId'), setting.get('setting')) + }) + for (let partition in registeredSessions) { + registeredSessions[partition].webRequest.handleBehaviorChanged() + } + }) +} + +module.exports.setContentSetting = (primaryUrl, secondaryUrl = '*', contentType, resourceId = '', setting) => { + for (var partition in registeredSessions) { + registeredSessions[partition].contentSettings.set(primaryUrl, secondaryUrl, contentType, resourceId, setting) + } +} + +module.exports.init = (ses, partition, isPrivate) => { + registeredSessions[partition] = ses +} diff --git a/app/browser/reducers/flashReducer.js b/app/browser/reducers/flashReducer.js new file mode 100644 index 00000000000..f7cea0cba6c --- /dev/null +++ b/app/browser/reducers/flashReducer.js @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict' + +const appConstants = require('../../../js/constants/appConstants') +const flash = require('../../../js/flash') +const {makeImmutable} = require('../../common/state/immutableUtil') + +const flashReducer = (state, action) => { + action = makeImmutable(action) + switch (action.get('actionType')) { + case appConstants.APP_SET_STATE: + flash.init() + break + } + return state +} + +module.exports = flashReducer diff --git a/app/browser/reducers/tabsReducer.js b/app/browser/reducers/tabsReducer.js index 9ddd360a1b4..f7248a548ca 100644 --- a/app/browser/reducers/tabsReducer.js +++ b/app/browser/reducers/tabsReducer.js @@ -10,7 +10,6 @@ const tabs = require('../tabs') const tabState = require('../../common/state/tabState') const windowConstants = require('../../../js/constants/windowConstants') const { makeImmutable } = require('../../common/state/immutableUtil') -const { getSiteSettingsForURL } = require('../../../js/state/siteSettings') const tabsReducer = (state, action) => { action = makeImmutable(action) diff --git a/app/extensions/brave/locales/en-US/preferences.properties b/app/extensions/brave/locales/en-US/preferences.properties index c832cfaf766..58e8dee1a3a 100644 --- a/app/extensions/brave/locales/en-US/preferences.properties +++ b/app/extensions/brave/locales/en-US/preferences.properties @@ -173,7 +173,7 @@ dashlane=Dashlane® (requires application) lastPass=LastPass® doNotManageMyPasswords=Don't manage my passwords usePDFJS=Enable HTML5 PDF reader (requires browser restart) -enableFlash=Enable Adobe Flash support (requires browser restart) +enableFlash=Enable Adobe Flash support widevineSection=Google Widevine Support enableWidevine=Enable Google Widevine support enableFlashSubtext=Brave uses a special version of Pepper Flash which must be installed from diff --git a/app/filtering.js b/app/filtering.js index 77054d25b1a..37faee328b0 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -11,6 +11,7 @@ const BrowserWindow = electron.BrowserWindow const webContents = electron.webContents const appActions = require('../js/actions/appActions') const appConfig = require('../js/constants/appConfig') +const hostContentSettings = require('./browser/contentSettings/hostContentSettings') const downloadStates = require('../js/constants/downloadStates') const urlParse = require('url').parse const getBaseDomain = require('../js/lib/baseDomain').getBaseDomain @@ -78,7 +79,7 @@ module.exports.registerHeadersReceivedFilteringCB = (filteringFn) => { * @param {object} session Session to add webRequest filtering on */ function registerForBeforeRequest (session, partition) { - const isPrivate = !partition.startsWith('persist:') + const isPrivate = module.exports.isPrivate(partition) session.webRequest.onBeforeRequest((details, cb) => { if (process.env.NODE_ENV === 'development') { let page = appUrlUtil.getGenDir(details.url) @@ -186,7 +187,7 @@ function registerForBeforeRequest (session, partition) { * @param {object} session Session to add webRequest filtering on */ function registerForBeforeRedirect (session, partition) { - const isPrivate = !partition.startsWith('persist:') + const isPrivate = module.exports.isPrivate(partition) // Note that onBeforeRedirect listener doesn't take a callback session.webRequest.onBeforeRedirect(function (details) { // Using an electron binary which isn't from Brave @@ -213,7 +214,7 @@ function registerForBeforeSendHeaders (session, partition) { const sendDNT = getSetting(settings.DO_NOT_TRACK) let spoofedUserAgent = getSetting(settings.USERAGENT) const braveRegex = new RegExp('brave/.+? ', 'gi') - const isPrivate = !partition.startsWith('persist:') + const isPrivate = module.exports.isPrivate(partition) session.webRequest.onBeforeSendHeaders(function (details, cb) { // Using an electron binary which isn't from Brave @@ -286,7 +287,7 @@ function registerForBeforeSendHeaders (session, partition) { * @param {object} session Session to add webRequest filtering on */ function registerForHeadersReceived (session, partition) { - const isPrivate = !partition.startsWith('persist:') + const isPrivate = module.exports.isPrivate(partition) // Note that onBeforeRedirect listener doesn't take a callback session.webRequest.onHeadersReceived(function (details, cb) { // Using an electron binary which isn't from Brave @@ -301,7 +302,7 @@ function registerForHeadersReceived (session, partition) { return } for (let i = 0; i < headersReceivedFilteringFns.length; i++) { - let results = headersReceivedFilteringFns[i](details) + let results = headersReceivedFilteringFns[i](details, isPrivate) if (!module.exports.isResourceEnabled(results.resourceName, firstPartyUrl, isPrivate)) { continue } @@ -320,7 +321,7 @@ function registerForHeadersReceived (session, partition) { * @param {string} partition name of the partition */ function registerPermissionHandler (session, partition) { - const isPrivate = !partition.startsWith('persist:') + const isPrivate = module.exports.isPrivate(partition) // Keep track of per-site permissions granted for this session. let permissions = null session.setPermissionRequestHandler((origin, mainFrameUrl, permission, cb) => { @@ -533,6 +534,7 @@ function initSession (ses, partition) { function initForPartition (partition) { let fns = [initSession, userPrefs.init, + hostContentSettings.init, registerForBeforeRequest, registerForBeforeRedirect, registerForBeforeSendHeaders, @@ -544,7 +546,7 @@ function initForPartition (partition) { options.parent_partition = '' } let ses = session.fromPartition(partition, options) - fns.forEach((fn) => { fn(ses, partition) }) + fns.forEach((fn) => { fn(ses, partition, module.exports.isPrivate(partition)) }) } const filterableProtocols = ['http:', 'https:'] @@ -577,6 +579,10 @@ function shouldIgnoreUrl (details) { return true } +module.exports.isPrivate = (partition) => { + return !partition.startsWith('persist:') +} + module.exports.init = (state, action, store) => { appStore = store diff --git a/app/sessionStore.js b/app/sessionStore.js index 7907bf91266..f14a2a54556 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -246,8 +246,7 @@ module.exports.cleanAppData = (data, isShutdown) => { data.notifications = [] // Delete temp site settings data.temporarySiteSettings = {} - // Delete Flash state since this is checked on startup - delete data.flashInitialized + if (data.settings[settings.CHECK_DEFAULT_ON_STARTUP] === true) { // Delete defaultBrowserCheckComplete state since this is checked on startup delete data.defaultBrowserCheckComplete diff --git a/docs/state.md b/docs/state.md index 485bb8b7523..82d3a8e6ae5 100644 --- a/docs/state.md +++ b/docs/state.md @@ -477,7 +477,6 @@ WindowStore maxHeight: number, // the maximum height of the popup window src: string, // the src for the popup window webview }, - flashInitialized: boolean, // Whether flash was initialized successfully. Cleared on shutdown. cleanedOnShutdown: boolean, // whether app data was successfully cleared on shutdown lastAppVersion: string, // Version of the last file that was saved ledgerInfo: { diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js index 9e871f0e1d9..77d4cc08234 100644 --- a/js/about/aboutActions.js +++ b/js/about/aboutActions.js @@ -198,10 +198,6 @@ const aboutActions = { }) }, - checkFlashInstalled: function () { - ipc.send(messages.CHECK_FLASH_INSTALLED) - }, - setResourceEnabled: function (resourceName, enabled) { aboutActions.dispatchAction({ actionType: appConstants.APP_SET_RESOURCE_ENABLED, diff --git a/js/about/preferences.js b/js/about/preferences.js index c9c2841a5d8..9af5e1e3195 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -1542,17 +1542,15 @@ class SecurityTab extends ImmutableComponent { } onToggleFlash (e) { aboutActions.setResourceEnabled(flash, e.target.value) - ipc.send(messages.PREFS_RESTART, flash, e.target.value) } onToggleWidevine (e) { aboutActions.setResourceEnabled(widevine, e.target.value) } render () { const lastPassPreferencesUrl = ('chrome-extension://' + extensionIds[passwordManagers.LAST_PASS] + '/tabDialog.html?dialog=preferences&cmd=open') - const isLinux = navigator.appVersion.indexOf('Linux') !== -1 - const flashInstalled = getSetting(settings.FLASH_INSTALLED, this.props.settings) + return
@@ -1791,7 +1789,6 @@ class AboutPreferences extends React.Component { firstRecoveryKey: '', secondRecoveryKey: '' } - aboutActions.checkFlashInstalled() ipc.on(messages.SETTINGS_UPDATED, (e, settings) => { this.setState({ settings: Immutable.fromJS(settings || {}) }) @@ -1918,7 +1915,7 @@ class AboutPreferences extends React.Component { hideOverlay={this.setOverlayVisible.bind(this, false)} /> break case preferenceTabs.SECURITY: - tab = + tab = break case preferenceTabs.ADVANCED: tab = diff --git a/js/actions/appActions.js b/js/actions/appActions.js index b1aa8df48c7..51d8baeb5a0 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -647,6 +647,23 @@ const appActions = { }) }, + allowFlashOnce: function (tabId, url, isPrivate) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_ALLOW_FLASH_ONCE, + tabId, + url, + isPrivate + }) + }, + + allowFlashAlways: function (tabId, url) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_ALLOW_FLASH_ALWAYS, + tabId, + url + }) + }, + /** * Dispatch a message to copy data URL to clipboard **/ diff --git a/js/components/frame.js b/js/components/frame.js index e66f001a519..81c92eecce7 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -637,6 +637,11 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('did-block-run-insecure-content', (e) => { windowActions.setBlockedRunInsecureContent(this.frame, e.details[0]) }) + this.webview.addEventListener('enable-pepper-menu', (e) => { + contextMenus.onFlashContextMenu(e.params, this.frame) + e.preventDefault() + e.stopPropagation() + }) this.webview.addEventListener('context-menu', (e) => { contextMenus.onMainContextMenu(e.params, this.frame) e.preventDefault() diff --git a/js/components/main.js b/js/components/main.js index c8fab0c55f8..7b496ac83c5 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -1257,7 +1257,6 @@ class Main extends ImmutableComponent { flash={this.props.appState.get('flash')} widevine={this.props.appState.get('widevine')} cookieblock={this.props.appState.get('cookieblock')} - flashInitialized={this.props.appState.get('flashInitialized')} allSiteSettings={allSiteSettings} ledgerInfo={this.props.appState.get('ledgerInfo') || new Immutable.Map()} publisherInfo={this.props.appState.get('publisherInfo') || new Immutable.Map()} diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js index 3670374eef5..414b1f89c6d 100644 --- a/js/constants/appConfig.js +++ b/js/constants/appConfig.js @@ -37,6 +37,7 @@ module.exports = { enabled: false, installUrl: 'https://get.adobe.com/flashplayer/', url: getTargetAboutUrl('about:flash'), + resourceId: 'PepperFlashPlayer.plugin', shields: false }, widevine: { diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 1a3e0f0c5f3..78b2ff2103f 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -73,14 +73,16 @@ const appConstants = { APP_POPULATE_HISTORY: _, APP_RENDER_URL_TO_PDF: _, APP_DATA_URL_COPIED: _, - APP_SHUTTING_DOWN: _, APP_DOWNLOAD_REVEALED: _, APP_DOWNLOAD_OPENED: _, APP_DOWNLOAD_ACTION_PERFORMED: _, APP_DOWNLOAD_COPIED_TO_CLIPBOARD: _, APP_DOWNLOAD_DELETED: _, APP_DOWNLOAD_CLEARED: _, - APP_DOWNLOAD_REDOWNLOADED: _ + APP_DOWNLOAD_REDOWNLOADED: _, + APP_ALLOW_FLASH_ONCE: _, + APP_ALLOW_FLASH_ALWAYS: _, + APP_SHUTTING_DOWN: _ } module.exports = mapValuesByKeys(appConstants) diff --git a/js/constants/messages.js b/js/constants/messages.js index e5265dc1a67..7e499f4fb60 100644 --- a/js/constants/messages.js +++ b/js/constants/messages.js @@ -114,7 +114,6 @@ const messages = { // About pages from contentScript RELOAD_URL: _, DISPATCH_ACTION: _, - CHECK_FLASH_INSTALLED: _, ABOUT_COMPONENT_INITIALIZED: _, CLEAR_BROWSING_DATA_NOW: _, IMPORT_BROWSER_DATA_NOW: _, diff --git a/js/contextMenus.js b/js/contextMenus.js index 318a0ea43a1..04e49db4273 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -462,6 +462,25 @@ function autofillTemplateInit (suggestions, frame) { return menuUtil.sanitizeTemplateItems(template) } +function flashTemplateInit (frameProps) { + const template = [] + template.push({ + label: locale.translation('allowFlashOnce'), + click: () => { + appActions.allowFlashOnce(frameProps.get('tabId'), frameProps.get('location'), frameProps.get('isPrivate')) + } + }) + if (!frameProps.get('isPrivate')) { + template.push({ + label: locale.translation('allowFlashAlways'), + click: () => { + appActions.allowFlashAlways(frameProps.get('tabId'), frameProps.get('location')) + } + }) + } + return template +} + function tabTemplateInit (frameProps) { const frameKey = frameProps.get('key') const template = [CommonMenu.newTabMenuItem(frameProps.get('key'))] @@ -872,26 +891,6 @@ const showDefinitionMenuItem = (selectionText) => { function mainTemplateInit (nodeProps, frame) { const template = [] - if (nodeProps.frameURL && nodeProps.frameURL.startsWith('chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/about-flash.html')) { - const pageOrigin = siteUtil.getOrigin(nodeProps.pageURL) - template.push({ - label: locale.translation('allowFlashOnce'), - click: () => { - appActions.changeSiteSetting(pageOrigin, 'flash', 1, frame.get('isPrivate')) - } - }) - if (!frame.get('isPrivate')) { - template.push({ - label: locale.translation('allowFlashAlways'), - click: () => { - const expirationTime = Date.now() + 7 * 24 * 3600 * 1000 - appActions.changeSiteSetting(pageOrigin, 'flash', expirationTime) - } - }) - } - return menuUtil.sanitizeTemplateItems(template) - } - const isLink = nodeProps.linkURL && nodeProps.linkURL !== '' const isImage = nodeProps.mediaType === 'image' const isVideo = nodeProps.mediaType === 'video' @@ -1234,6 +1233,12 @@ function onMainContextMenu (nodeProps, frame, contextMenuType) { } } +function onFlashContextMenu (nodeProps, frameProps) { + const flashMenu = Menu.buildFromTemplate(flashTemplateInit(frameProps)) + flashMenu.popup(currentWindow) + flashMenu.destroy() +} + function onTabContextMenu (frameProps, e) { e.stopPropagation() const tabMenu = Menu.buildFromTemplate(tabTemplateInit(frameProps)) @@ -1492,6 +1497,7 @@ function onReloadContextMenu (target) { module.exports = { onHamburgerMenu, + onFlashContextMenu, onMainContextMenu, onTabContextMenu, onNewTabContextMenu, diff --git a/js/flash.js b/js/flash.js index b2ed5ae0e27..ec12bd026fb 100644 --- a/js/flash.js +++ b/js/flash.js @@ -7,21 +7,17 @@ const fs = require('fs') const path = require('path') const electron = require('electron') const app = electron.app -const ipcMain = electron.ipcMain const webContents = electron.webContents const appActions = require('./actions/appActions') -const appConfig = require('./constants/appConfig') const Filtering = require('../app/filtering') -const locale = require('../app/locale') -const messages = require('./constants/messages') -const siteUtil = require('./state/siteUtil') -const urlParse = require('url').parse const settings = require('./constants/settings') -const {siteHacks} = require('./data/siteHacks') -const urlutil = require('./lib/urlutil') +// set to true if `init` has been called +let initialized = false +// set to true if the flash install check has succeeded let flashInstalled = false -const notificationCallbacks = {} +// set to true if a flash install url has been loaded +let flashMaybeInstalled = false const getPepperFlashPath = () => { if (['darwin', 'win32'].includes(process.platform)) { @@ -45,209 +41,79 @@ const getPepperFlashPath = () => { } /** - * Shows a Flash CtP notification if Flash is installed and enabled. - * If not enabled, alert user that Flash is installed. - * @param {string} origin - frame origin that is requesting to run flash. - * can either be main frame or subframe. - */ -const showFlashNotification = (origin, tabId, url, noFlashUrl) => { - // Generate a random string that is unlikely to collide. Not - // cryptographically random. - const nonce = Math.random().toString() - - if (flashInstalled) { - const message = locale.translation('allowFlashPlayer', { origin }) - // Show Flash notification bar - appActions.showMessageBox({ - buttons: [ - {text: locale.translation('deny')}, - {text: locale.translation('allow')} - ], - message, - frameOrigin: origin, - options: { - nonce, - persist: true - } - }) - notificationCallbacks[message] = (buttonIndex, persist) => { - let newUrl = null - if (buttonIndex === 1) { - if (persist) { - appActions.changeSiteSetting(origin, 'flash', Date.now() + 7 * 24 * 1000 * 3600) - } else { - appActions.changeSiteSetting(origin, 'flash', 1) - } - newUrl = url - } else { - if (persist) { - appActions.changeSiteSetting(origin, 'flash', false) - } - if (noFlashUrl) { - newUrl = noFlashUrl - } - } - - if (!newUrl) { - return - } - - let tab = webContents.fromTabID(tabId) - if (tab && !tab.isDestroyed()) { - tab.loadURL(newUrl) - } - } - } else { - module.exports.checkFlashInstalled((installed) => { - if (installed) { - let message = locale.translation('flashInstalled') - appActions.showMessageBox({ - buttons: [ - {text: locale.translation('goToPrefs')}, - {text: locale.translation('goToAdobe')} - ], - message: message, - options: {nonce} - }) - notificationCallbacks[message] = (buttonIndex, persist) => { - const location = buttonIndex === 0 ? 'about:preferences#security' : appConfig.flash.installUrl - appActions.newTab({ location }) - } - } else if (noFlashUrl) { - let tab = webContents.fromTabID(tabId) - if (tab && !tab.isDestroyed()) { - tab.loadURL(noFlashUrl) - } - } - }) - } - - ipcMain.once(messages.NOTIFICATION_RESPONSE + nonce, (e, msg, buttonIndex, persist) => { - try { - const cb = notificationCallbacks[msg] - delete notificationCallbacks[msg] - if (cb) { - cb(buttonIndex, persist) - } - } catch (e) { - console.error(e) - } - appActions.hideMessageBox(msg) - }) -} - -const flashSetting = (url, isPrivate) => { - let activeSiteSettings = Filtering.getSiteSettings(url, isPrivate) - return activeSiteSettings && activeSiteSettings.get('flash') -} - -const allowRunningFlash = (url, isPrivate) => { - return typeof flashSetting(url, isPrivate) === 'number' -} - -/** - * Checks whether the first-party page is one that should have Flash install - * URL interception. + * Checks whether a link is an Flash installer URL. * @param {string} url * @return {boolean} */ -const shouldInterceptFlash = (url, isPrivate) => { - if (!url) { - return false - } - - if (flashSetting(url, isPrivate) === false) { - return false - } - - return urlutil.shouldInterceptFlash(url) +const isFlashInstallUrl = (url) => { + const adobeRegex = new RegExp('//(get\\.adobe\\.com/([a-z_-]+/)*flashplayer|www\\.macromedia\\.com/go/getflash|www\\.adobe\\.com/go/getflash)', 'i') + return adobeRegex.test(url) } -function handleFlashCTP (details, isPrivate) { - // we never do anything with the result because this is after page load - const result = { - resourceName: module.exports.resourceName - } - - if (!flashInstalled || details.resourceType !== 'mainFrame' || !allowRunningFlash(details.url, isPrivate)) { - return result - } - - const mainFrameUrl = Filtering.getMainFrameUrl(details) - if (!mainFrameUrl) { - return result - } - - const origin = siteUtil.getOrigin(mainFrameUrl) - const parsed = urlParse(mainFrameUrl) - const hack = siteHacks[parsed.hostname] - - if (origin && hack && hack.enableFlashCTP) { - // Fix #3011 - showFlashNotification(origin, details.tabId, null, hack.redirectURL) - } - - return result -} - -function handleFlashInstallUrl (details, isPrivate) { +const handleFlashInstallUrl = (details, isPrivate) => { const result = { resourceName: module.exports.resourceName, redirectURL: null, cancel: false } - if (details.resourceType !== 'mainFrame') { + const url = details.url + if (!url || details.resourceType !== 'mainFrame') { return result } - const mainFrameUrl = Filtering.getMainFrameUrl(details) - if (!mainFrameUrl) { + if (!isFlashInstallUrl(url)) { return result } - const origin = siteUtil.getOrigin(mainFrameUrl) - if (origin && urlutil.isFlashInstallUrl(details.url) && - shouldInterceptFlash(mainFrameUrl, isPrivate)) { - result.cancel = true - showFlashNotification(origin, details.tabId, details.url) + if (!flashInstalled) { + if (flashMaybeInstalled) { + setImmediate(() => { + module.exports.checkFlashInstalled((installed) => { + flashMaybeInstalled = installed + let tab = webContents.fromTabID(details.tabId) + if (tab && !tab.isDestroyed()) { + tab.loadURL(url) + } + }) + }) + result.cancel = true + } else { + flashMaybeInstalled = true + } } return result } -module.exports.init = (state, action) => { - setImmediate(() => { - module.exports.checkFlashInstalled((result, path, manifest) => { - if (result) { - flashInstalled = true - Filtering.registerBeforeRequestFilteringCB(handleFlashInstallUrl) - Filtering.registerHeadersReceivedFilteringCB(handleFlashCTP) - app.commandLine.appendSwitch('ppapi-flash-path', path) +module.exports.checkFlashInstalled = (cb) => { + const pepperFlashSystemPluginPath = getPepperFlashPath() + const pepperFlashManifestPath = path.resolve(pepperFlashSystemPluginPath, '..', 'manifest.json') + fs.readFile(pepperFlashManifestPath, (err, data) => { + try { + if (err || !data) { + flashInstalled = false + } else { + const manifest = JSON.parse(data) + app.commandLine.appendSwitch('ppapi-flash-path', pepperFlashSystemPluginPath) app.commandLine.appendSwitch('ppapi-flash-version', manifest.version) + flashInstalled = true } - setImmediate(() => { - appActions.changeSetting(settings.FLASH_INSTALLED, result) - }) - }) + } finally { + appActions.changeSetting(settings.FLASH_INSTALLED, flashInstalled) + cb && cb(flashInstalled) + } }) - return state } -module.exports.checkFlashInstalled = (cb) => { - try { - const pepperFlashSystemPluginPath = getPepperFlashPath() - const pepperFlashManifestPath = path.resolve(pepperFlashSystemPluginPath, '..', 'manifest.json') - fs.readFile(pepperFlashManifestPath, (err, data) => { - if (err || !data) { - cb(false) - } else { - cb(true, pepperFlashSystemPluginPath, JSON.parse(data)) - } - }) - } catch (e) { - cb(false) +module.exports.init = () => { + if (initialized) { + return } + initialized = true + + Filtering.registerBeforeRequestFilteringCB(handleFlashInstallUrl) + module.exports.checkFlashInstalled() } module.exports.resourceName = 'flash' diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index 91917aa9349..01d65a8b2dc 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -7,13 +7,16 @@ const AppStore = require('../stores/appStore') const appConstants = require('../constants/appConstants') const appConfig = require('../constants/appConfig') const config = require('../constants/config') +const hostContentSettings = require('../../app/browser/contentSettings/hostContentSettings') +const {makeImmutable} = require('../../app/common/state/immutableUtil') +const Immutable = require('immutable') const settings = require('../constants/settings') const {cookieExceptions, localStorageExceptions} = require('../data/siteHacks') -const {passwordManagers, defaultPasswordManager} = require('../constants/passwordManagers') +const {defaultPasswordManager} = require('../constants/passwordManagers') const urlParse = require('url').parse const siteSettings = require('./siteSettings') -const {setUserPref} = require('./userPrefs') -const {getSetting} = require('../settings') +const { setUserPref } = require('./userPrefs') +const { getSetting } = require('../settings') // backward compatibility with appState siteSettings const parseSiteSettingsPattern = (pattern) => { @@ -22,27 +25,110 @@ const parseSiteSettingsPattern = (pattern) => { return '[*.]' + parsed.host } -const addContentSettings = (settingList, hostPattern, secondaryPattern = undefined, setting = 'block') => { - let contentSettingsPattern = parseSiteSettingsPattern(hostPattern) - settingList.push({ +const toContentSetting = (primaryPattern, secondaryPattern = undefined, setting = 'block', resourceId = undefined) => { + return Immutable.fromJS({ setting, + primaryPattern, secondaryPattern, - primaryPattern: contentSettingsPattern + resourceId }) } -const getPasswordManagerEnabled = (appState) => { - let appSettings = appState.get('settings') +const addContentSettings = (contentSettings, key, primaryPattern, secondaryPattern, setting, resourceId) => { + let contentSettingsForKey = contentSettings.get(key) + if (!contentSettingsForKey) { + return contentSettings + } else { + contentSettingsForKey = contentSettingsForKey.push(toContentSetting(primaryPattern, secondaryPattern, setting, resourceId)) + return contentSettings.set(key, contentSettingsForKey) + } +} + +// Content settings handled by HostContentSettingsMap in Muon +const getDefaultHostContentSettings = (braveryDefaults, appSettings, appConfig) => { + return Immutable.fromJS({ + plugins: getDefaultPluginSettings(braveryDefaults, appSettings, appConfig) + }) +} + +// Content settings currently handled by UserPrefs in Muon +// Usage of these settings is deprecated and we should be transitioning to HostContentSettings +// Check with @bridiver before adding additional user pref content settings +const getDefaultUserPrefContentSettings = (braveryDefaults, appSettings, appConfig) => { + return Immutable.fromJS({ + cookies: getDefault3rdPartyStorageSettings(braveryDefaults, appSettings, appConfig), + referer: [{ + setting: braveryDefaults.cookieControl === 'block3rdPartyCookie' ? 'block' : 'allow', + primaryPattern: '*' + }], + adInsertion: [{ + setting: braveryDefaults.adControl === 'showBraveAds' ? 'allow' : 'block', + primaryPattern: '*' + }], + passwordManager: getDefaultPasswordManagerSettings(braveryDefaults, appSettings, appConfig), + javascript: [{ + setting: braveryDefaults.noScript ? 'block' : 'allow', + primaryPattern: '*' + }, { + setting: 'allow', + secondaryPattern: '*', + primaryPattern: 'file:///*' + }, { + setting: 'allow', + secondaryPattern: '*', + primaryPattern: 'chrome-extension://*' + }], + canvasFingerprinting: [{ + setting: braveryDefaults.fingerprintingProtection ? 'block' : 'allow', + primaryPattern: '*' + }], + runInsecureContent: [{ + setting: 'block', + primaryPattern: '*' + }], + popups: [{ + setting: 'block', + primaryPattern: '*' + }] + }) +} + +const getDefaultPasswordManagerSettings = (braveryDefaults, appSettings, appConfig) => { + let bravePasswordManagerSetting = 'block' if (appSettings) { const passwordManager = getSetting(settings.ACTIVE_PASSWORD_MANAGER, appSettings) - if (typeof passwordManager === 'string') { - return passwordManager === passwordManagers.BUILT_IN - } + let useBuiltIn = passwordManager === defaultPasswordManager + bravePasswordManagerSetting = useBuiltIn ? 'allow' : 'block' } - return defaultPasswordManager === passwordManagers.BUILT_IN + + return [ + { + setting: bravePasswordManagerSetting, + primaryPattern: '*' + } + ] +} + +const getDefaultPluginSettings = (braveryDefaults, appSettings, appConfig) => { + return [ + { + setting: 'block', + primaryPattern: '*' + }, + { + setting: 'block', + resourceId: appConfig.flash.resourceId, + primaryPattern: '*' + }, + { + setting: 'block', + resourceId: appConfig.widevine.resourceId, + primaryPattern: '*' + } + ] } -const getBlock3rdPartyStorage = (braveryDefaults) => { +const getDefault3rdPartyStorageSettings = (braveryDefaults, appSettings, appConfig) => { if (braveryDefaults.cookieControl === 'block3rdPartyCookie') { const contentSettings = [ { @@ -79,145 +165,103 @@ const getBlock3rdPartyStorage = (braveryDefaults) => { } } -const hostSettingsToContentSettings = (hostSettings, contentSettingsSource) => { - let contentSettings = contentSettingsSource +const siteSettingsToContentSettings = (currentSiteSettings, defaultContentSettings, braveryDefaults, appConfig) => { + let contentSettings = makeImmutable(defaultContentSettings) + currentSiteSettings = makeImmutable(currentSiteSettings) + braveryDefaults = makeImmutable(braveryDefaults) + // We do 2 passes for setting content settings. On the first pass we consider all shield types. - for (let hostPattern in hostSettings) { - let hostSetting = hostSettings[hostPattern] - if (['number', 'boolean'].includes(typeof hostSetting.noScript)) { - addContentSettings(contentSettings.javascript, hostPattern, '*', - hostSetting.noScript === true ? 'block' : 'allow') + currentSiteSettings.forEach((siteSetting, hostPattern) => { + let primaryPattern = parseSiteSettingsPattern(hostPattern) + + if (['number', 'boolean'].includes(typeof siteSetting.get('noScript'))) { + contentSettings = addContentSettings(contentSettings, 'javascript', primaryPattern, '*', siteSetting.get('noScript') === true ? 'block' : 'allow') } - if (typeof hostSetting.runInsecureContent === 'boolean') { - addContentSettings(contentSettings.runInsecureContent, hostPattern, '*', - hostSetting.runInsecureContent ? 'allow' : 'block') + if (typeof siteSetting.get('runInsecureContent') === 'boolean') { + contentSettings = addContentSettings(contentSettings, 'runInsecureContent', primaryPattern, '*', + siteSetting.get('runInsecureContent') ? 'allow' : 'block') } - if (hostSetting.cookieControl) { - if (hostSetting.cookieControl === 'block3rdPartyCookie') { - addContentSettings(contentSettings.cookies, hostPattern, '*', 'block') - addContentSettings(contentSettings.cookies, hostPattern, parseSiteSettingsPattern(hostPattern), 'allow') - addContentSettings(contentSettings.referer, hostPattern, '*', 'block') - cookieExceptions.forEach((exceptionPair) => - addContentSettings(contentSettings.cookies, exceptionPair[0], exceptionPair[1], 'allow')) + if (siteSetting.get('cookieControl')) { + if (siteSetting.get('cookieControl') === 'block3rdPartyCookie') { + contentSettings = addContentSettings(contentSettings, 'cookies', primaryPattern, '*', 'block') + contentSettings = addContentSettings(contentSettings, 'cookies', primaryPattern, primaryPattern, 'allow') + contentSettings = addContentSettings(contentSettings, 'referer', primaryPattern, '*', 'block') + cookieExceptions.forEach((exceptionPair) => { + contentSettings = addContentSettings(contentSettings, 'cookies', exceptionPair[0], exceptionPair[1], 'allow') + }) } else { - addContentSettings(contentSettings.cookies, hostPattern, '*', 'allow') - addContentSettings(contentSettings.referer, hostPattern, '*', 'allow') + contentSettings = addContentSettings(contentSettings, 'cookies', primaryPattern, '*', 'allow') + contentSettings = addContentSettings(contentSettings, 'referer', primaryPattern, '*', 'allow') } } - if (typeof hostSetting.fingerprintingProtection === 'boolean') { - addContentSettings(contentSettings.canvasFingerprinting, hostPattern, '*', hostSetting.fingerprintingProtection ? 'block' : 'allow') + if (typeof siteSetting.get('fingerprintingProtection') === 'boolean') { + contentSettings = addContentSettings(contentSettings, 'canvasFingerprinting', primaryPattern, '*', siteSetting.get('fingerprintingProtection') ? 'block' : 'allow') } - if (hostSetting.adControl) { - addContentSettings(contentSettings.adInsertion, hostPattern, '*', hostSetting.adControl === 'showBraveAds' ? 'allow' : 'block') + if (siteSetting.get('adControl')) { + contentSettings = addContentSettings(contentSettings, 'adInsertion', primaryPattern, '*', siteSetting.get('adControl') === 'showBraveAds' ? 'allow' : 'block') } - if (typeof hostSetting.flash === 'number' && AppStore.getState().get('flashInitialized')) { - addContentSettings(contentSettings.flashActive, hostPattern, '*', 'allow') - addContentSettings(contentSettings.plugins, hostPattern, '*', 'allow') + if (typeof siteSetting.get('flash') === 'number') { // && braveryDefaults.flash) { + contentSettings = addContentSettings(contentSettings, 'plugins', primaryPattern, '*', 'allow', appConfig.flash.resourceId) } - if (typeof hostSetting.widevine === 'number' && AppStore.getState().getIn(['widevine', 'enabled'])) { - addContentSettings(contentSettings.plugins, hostPattern, '*', 'allow') + if (typeof siteSetting.get('widevine') === 'number' && braveryDefaults.widevine) { + contentSettings = addContentSettings(contentSettings, 'plugins', primaryPattern, '*', 'allow', appConfig.widevine.resourceId) } - } + }) // On the second pass we consider only shieldsUp === false settings since we want those to take precedence. - for (let hostPattern in hostSettings) { - let hostSetting = hostSettings[hostPattern] - if (hostSetting.shieldsUp === false) { - addContentSettings(contentSettings.cookies, hostPattern, '*', 'allow') - addContentSettings(contentSettings.canvasFingerprinting, hostPattern, '*', 'allow') - addContentSettings(contentSettings.adInsertion, hostPattern, '*', 'block') - addContentSettings(contentSettings.javascript, hostPattern, '*', 'allow') - addContentSettings(contentSettings.referer, hostPattern, '*', 'allow') + currentSiteSettings.forEach((siteSetting, hostPattern) => { + let primaryPattern = parseSiteSettingsPattern(hostPattern) + + if (siteSetting.get('shieldsUp') === false) { + contentSettings = addContentSettings(contentSettings, 'cookies', primaryPattern, '*', 'allow') + contentSettings = addContentSettings(contentSettings, 'canvasFingerprinting', primaryPattern, '*', 'allow') + contentSettings = addContentSettings(contentSettings, 'adInsertion', primaryPattern, '*', 'block') + contentSettings = addContentSettings(contentSettings, 'javascript', primaryPattern, '*', 'allow') + contentSettings = addContentSettings(contentSettings, 'referer', primaryPattern, '*', 'allow') } - } + }) return contentSettings } -const getContentSettingsFromSiteSettings = (appState, isPrivate = false) => { - let braveryDefaults = siteSettings.braveryDefaults(appState, appConfig) - - const contentSettings = { - cookies: getBlock3rdPartyStorage(braveryDefaults), - referer: [{ - setting: braveryDefaults.cookieControl === 'block3rdPartyCookie' ? 'block' : 'allow', - primaryPattern: '*' - }], - adInsertion: [{ - setting: braveryDefaults.adControl === 'showBraveAds' ? 'allow' : 'block', - primaryPattern: '*' - }], - passwordManager: [{ - setting: getPasswordManagerEnabled(appState) ? 'allow' : 'block', - primaryPattern: '*' - }], - javascript: [{ - setting: braveryDefaults.noScript ? 'block' : 'allow', - primaryPattern: '*' - }, { - setting: 'allow', - secondaryPattern: '*', - primaryPattern: 'chrome-extension://*' - }], - canvasFingerprinting: [{ - setting: braveryDefaults.fingerprintingProtection ? 'block' : 'allow', - primaryPattern: '*' - }], - flashEnabled: [{ - setting: braveryDefaults.flash ? 'allow' : 'block', - primaryPattern: '*' - }], - flashActive: [{ - setting: 'block', - primaryPattern: '*' - }], - runInsecureContent: [{ - setting: 'block', - primaryPattern: '*' - }], - plugins: [{ - setting: 'block', - primaryPattern: '*' - }] - } +const getSettingsFromSiteSettings = (defaultSettings, appState, appConfig, isPrivate = false) => { + let currentSiteSettings = appState.get('siteSettings') + const temporarySiteSettings = appState.get('temporarySiteSettings') + const braveryDefaults = siteSettings.braveryDefaults(appState, appConfig) - const regularSettings = hostSettingsToContentSettings(appState.get('siteSettings').toJS(), contentSettings) if (isPrivate) { - const privateSettings = - hostSettingsToContentSettings(appState.get('siteSettings').merge(appState.get('temporarySiteSettings')).toJS(), - contentSettings) - return { content_settings: privateSettings } + currentSiteSettings = currentSiteSettings.merge(temporarySiteSettings) } - return { content_settings: regularSettings } + + return siteSettingsToContentSettings(currentSiteSettings, defaultSettings, braveryDefaults, appConfig) +} + +const updateContentSettings = (appState, appConfig, isPrivate = false) => { + const braveryDefaults = siteSettings.braveryDefaults(appState, appConfig) + const defaultUserPrefs = getDefaultUserPrefContentSettings(braveryDefaults, appState, appConfig) + const defaultHostContentSettings = getDefaultHostContentSettings(braveryDefaults, appState, appConfig) + + setUserPref('content_settings', getSettingsFromSiteSettings(defaultUserPrefs, appState, appConfig, isPrivate), isPrivate) + hostContentSettings.setContentSettings(getSettingsFromSiteSettings(defaultHostContentSettings, appState, appConfig, isPrivate), isPrivate) } // Register callback to handle all updates const doAction = (action) => { switch (action.actionType) { - case appConstants.APP_CHANGE_SITE_SETTING: - AppDispatcher.waitFor([AppStore.dispatchToken], () => { - if (action.temporary) { - setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState(), true).content_settings, true) - } else { - setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState()).content_settings) - } - }) - break case appConstants.APP_REMOVE_SITE_SETTING: + case appConstants.APP_CHANGE_SITE_SETTING: AppDispatcher.waitFor([AppStore.dispatchToken], () => { - if (action.temporary) { - setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState(), true).content_settings, true) - } else { - setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState()).content_settings) - } + updateContentSettings(AppStore.getState(), appConfig, action.temporary) }) break + case appConstants.APP_CHANGE_SETTING: case appConstants.APP_SET_RESOURCE_ENABLED: AppDispatcher.waitFor([AppStore.dispatchToken], () => { - setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState()).content_settings) + updateContentSettings(AppStore.getState(), appConfig) }) break - case appConstants.APP_CHANGE_SETTING: + case appConstants.APP_ALLOW_FLASH_ONCE: + case appConstants.APP_ALLOW_FLASH_ALWAYS: AppDispatcher.waitFor([AppStore.dispatchToken], () => { - setUserPref('content_settings', getContentSettingsFromSiteSettings(AppStore.getState()).content_settings) + updateContentSettings(AppStore.getState(), appConfig, action.isPrivate) }) break default: diff --git a/js/state/userPrefs.js b/js/state/userPrefs.js index f25e93cfbc7..99cedd04090 100644 --- a/js/state/userPrefs.js +++ b/js/state/userPrefs.js @@ -6,8 +6,6 @@ let registeredCallbacks = [] let registeredSessions = [] let registeredPrivateSessions = [] -const isPrivate = (partition) => !partition.startsWith('persist:') && partition !== 'main-1' - // TODO(bridiver) move this to electron so we can call a simpler api const setUserPrefType = (ses, path, value) => { switch (typeof value) { @@ -58,14 +56,17 @@ const runCallback = (cb, name, incognito) => { } module.exports.setUserPref = (path, value, incognito = false) => { + value = value.toJS ? value.toJS() : value + let partitions = incognito ? Object.keys(registeredPrivateSessions) : Object.keys(registeredSessions) partitions.forEach((partition) => { setUserPrefType(registeredSessions[partition], path, value) + registeredSessions[partition].webRequest.handleBehaviorChanged() }) } -module.exports.init = (ses, partition) => { - if (isPrivate(partition)) { +module.exports.init = (ses, partition, isPrivate) => { + if (isPrivate) { registeredPrivateSessions[partition] = ses } registeredSessions[partition] = ses diff --git a/js/stores/appStore.js b/js/stores/appStore.js index bf093e37855..4fe04a0b2f9 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -43,7 +43,7 @@ const aboutNewTabState = require('../../app/common/state/aboutNewTabState') const aboutHistoryState = require('../../app/common/state/aboutHistoryState') const windowState = require('../../app/common/state/windowState') -const flash = require('../flash.js') +const flashReducer = require('../../app/browser/reducers/flashReducer') const tabsReducer = require('../../app/browser/reducers/tabsReducer') const webtorrent = require('../../app/browser/webtorrent') @@ -361,6 +361,7 @@ const handleAppAction = (action) => { const ledger = require('../../app/ledger') appState = downloadsReducer(appState, action) + appState = flashReducer(appState, action) appState = tabsReducer(appState, action) switch (action.actionType) { @@ -369,7 +370,6 @@ const handleAppAction = (action) => { appState = Filtering.init(appState, action, appStore) appState = windows.init(appState, action, appStore) appState = basicAuth.init(appState, action, appStore) - appState = flash.init(appState, action, appStore) appState = webtorrent.init(appState, action, appStore) break case appConstants.APP_SHUTTING_DOWN: @@ -559,6 +559,23 @@ const handleAppAction = (action) => { appState = appState.setIn(['settings', action.key], action.value) handleChangeSettingAction(action.key, action.value) break + case appConstants.APP_ALLOW_FLASH_ONCE: + { + const propertyName = action.isPrivate ? 'temporarySiteSettings' : 'siteSettings' + console.log(siteUtil.getOrigin(action.url)) + console.log(propertyName) + appState = appState.set(propertyName, + siteSettings.mergeSiteSetting(appState.get(propertyName), siteUtil.getOrigin(action.url), 'flash', 1)) + break + } + case appConstants.APP_ALLOW_FLASH_ALWAYS: + { + const propertyName = action.isPrivate ? 'temporarySiteSettings' : 'siteSettings' + const expirationTime = Date.now() + 7 * 24 * 3600 * 1000 + appState = appState.set(propertyName, + siteSettings.mergeSiteSetting(appState.get(propertyName), siteUtil.getOrigin(action.url), 'flash', expirationTime)) + break + } case appConstants.APP_CHANGE_SITE_SETTING: { let propertyName = action.temporary ? 'temporarySiteSettings' : 'siteSettings' From 215cc4962455ce1344678f0889f77738bf535c4c Mon Sep 17 00:00:00 2001 From: bridiver Date: Fri, 9 Dec 2016 12:21:23 -0700 Subject: [PATCH 51/80] rebase fixes auditors @bbondy --- app/browser/webtorrent.js | 6 +++++- app/renderer/components/downloadsBar.js | 3 +-- docs/directoryStructure.md | 2 +- js/about/preferences.js | 3 +-- js/components/tab.js | 2 +- js/state/contentSettings.js | 4 ---- js/stores/appStore.js | 2 +- 7 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/browser/webtorrent.js b/app/browser/webtorrent.js index 395e166865c..a47ebcc4160 100644 --- a/app/browser/webtorrent.js +++ b/app/browser/webtorrent.js @@ -33,7 +33,9 @@ function handleMangetUrl (details, isPrivate) { } // Receive messages via the window process, ultimately from the UI in a process -function init () { +function init (state, action) { + Filtering.registerBeforeRequestFilteringCB(handleMangetUrl) + if (DEBUG_IPC) console.log('WebTorrent IPC init') ipc.on(messages.TORRENT_MESSAGE, function (e, msg) { if (server === null) { @@ -44,6 +46,8 @@ function init () { channels[msg.clientKey] = e.sender server.receive(msg) }) + + return state } // Send messages from the browser process (here), thru the window process, to the diff --git a/app/renderer/components/downloadsBar.js b/app/renderer/components/downloadsBar.js index 2e520c6648e..c610e1f9037 100644 --- a/app/renderer/components/downloadsBar.js +++ b/app/renderer/components/downloadsBar.js @@ -39,8 +39,7 @@ class DownloadsBar extends ImmutableComponent { }
-
diff --git a/docs/directoryStructure.md b/docs/directoryStructure.md index 5080b143e50..7ddffeb80fe 100644 --- a/docs/directoryStructure.md +++ b/docs/directoryStructure.md @@ -3,7 +3,7 @@ - `app`: Container for all app runtime code - `browser`: Code that runs in the main process. This includes the top level menu, shortcut handling, and contains other resources which need to be accessed from the main process. Files in this directory can use `require('electron')` for most electron APIs and `ipcMain` for IPC calls. - `renderer`: Code that runs in the renderer processes. It should be primarily UI related code for the main browser windows. Files in this directory must use `global.require('electron').remote` and for most electron APIs and `ipcRenderer` for IPC calls. - - `common`: Code that is shared by the browser and renderer process. This includes things like utility functions, constants and actions. Stores can live in either the browser or the renderer process, but should not be shared becuase the renderer processes are short-lived compared to the browser process and therefore won't receive the same set of updates. Files in the common directory should avoid using electron APIs, but if it is necessary they must do a process type check and either `require('electron')` or `global.require('electron').remote` as appropriate. + - `common`: Code that is shared by the browser and renderer process. This includes things like utility functions, constants and actions. Stores can live in either the browser or the renderer process, but should not be shared becuase the renderer processes are short-lived compared to the browser process and therefore won't receive the same set of updates. Files in the common directory should avoid using electron APIs #Deprecated Directory Structure - `app`: Code that runs in the main process. This includes the top level menu, shortcut handling, and contains other resources which need to be accessed from the main process. diff --git a/js/about/preferences.js b/js/about/preferences.js index 9af5e1e3195..a2f1fdd4921 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -1608,8 +1608,7 @@ class SecurityTab extends ImmutableComponent {
- - +
{ isDarwin || isWindows ?
diff --git a/js/components/tab.js b/js/components/tab.js index 75399b19567..f3dc971a3e1 100644 --- a/js/components/tab.js +++ b/js/components/tab.js @@ -16,7 +16,7 @@ const {isIntermediateAboutPage} = require('../lib/appUrlUtil') const contextMenus = require('../contextMenus') const dnd = require('../dnd') const windowStore = require('../stores/windowStore') -const ipc = global.require('electron').ipcRenderer +const ipc = require('electron').ipcRenderer const {TabIcon, AudioTabIcon} = require('../../app/renderer/components/tabIcon') diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index 01d65a8b2dc..65ee3eda4b3 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -69,10 +69,6 @@ const getDefaultUserPrefContentSettings = (braveryDefaults, appSettings, appConf javascript: [{ setting: braveryDefaults.noScript ? 'block' : 'allow', primaryPattern: '*' - }, { - setting: 'allow', - secondaryPattern: '*', - primaryPattern: 'file:///*' }, { setting: 'allow', secondaryPattern: '*', diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 4fe04a0b2f9..6ea9e475598 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -810,7 +810,7 @@ const handleAppAction = (action) => { appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) appState = aboutNewTabState.setSites(appState, action) break - case AppConstants.APP_RENDER_URL_TO_PDF: + case appConstants.APP_RENDER_URL_TO_PDF: const pdf = require('../../app/pdf') appState = pdf.renderUrlToPdf(appState, action) break From 7b6a19badfc54570e740dbd74cdc6153a85a709a Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Fri, 9 Dec 2016 10:05:27 -0500 Subject: [PATCH 52/80] Fix pinned tab tests Auditors: @bsclifton --- js/devTools.js | 2 ++ test/components/pinnedTabTest.js | 11 +++-------- test/lib/brave.js | 3 +-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/js/devTools.js b/js/devTools.js index 83e61c7274a..5e4bba7fa7b 100644 --- a/js/devTools.js +++ b/js/devTools.js @@ -6,5 +6,7 @@ module.exports = function (name) { return electron } else if (name === 'appActions') { return appActions + } else if (name === 'immutable') { + return require('immutable') } } diff --git a/test/components/pinnedTabTest.js b/test/components/pinnedTabTest.js index 1ffd0ba28c0..ffefa93ee2f 100644 --- a/test/components/pinnedTabTest.js +++ b/test/components/pinnedTabTest.js @@ -173,10 +173,6 @@ describe('pinnedTabs', function () { .url(page2Url) .waitForUrl(page2Url) .windowByUrl(Brave.browserWindowUrl) - yield this.app.client - .waitUntil(function () { - return this.getAttribute('webview[data-frame-key="2"]', 'src').then((src) => src === page2Url) - }) .waitUntil(function () { return this.elements(pinnedTabsTabs).then((res) => res.value.length === 1) }) @@ -187,11 +183,10 @@ describe('pinnedTabs', function () { it('navigating to a different origin opens a new tab', function * () { const page2Url = Brave.server.url('page2.html').replace('localhost', '127.0.0.1') yield this.app.client - .tabByUrl(this.page1Url) - .url(page2Url) - .waitForUrl(page2Url) + .click(urlInput) + .setValue(urlInput, page2Url) + .keys(Brave.keys.ENTER) .windowByUrl(Brave.browserWindowUrl) - this.app.client.waitForExist('webview[data-frame-key="3"]') .waitUntil(function () { return this.elements(pinnedTabsTabs).then((res) => res.value.length === 1) }) diff --git a/test/lib/brave.js b/test/lib/brave.js index 48c29d67f98..d047fa17ec6 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -327,8 +327,7 @@ var exports = { this.app.client.addCommand('setPinned', function (location, isPinned, options = {}) { return this.execute(function (location, isPinned, options) { - var Immutable = require('immutable') - devTools('electron').testData.windowActions.setPinned(Immutable.fromJS(Object.assign({ + devTools('electron').testData.windowActions.setPinned(devTools('immutable').fromJS(Object.assign({ windowId: devTools('electron').remote.getCurrentWindow().id, location }, options)), isPinned) From a5e605348e4673d7557742ca4809f1942be8dacd Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Fri, 9 Dec 2016 09:35:00 -0500 Subject: [PATCH 53/80] Fix various test failures Auditors: @bsclifton --- test/components/findbarTest.js | 7 ------- test/components/navigationBarTest.js | 22 +++++----------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/test/components/findbarTest.js b/test/components/findbarTest.js index 5bbd06365d9..db11a4b1f6b 100644 --- a/test/components/findbarTest.js +++ b/test/components/findbarTest.js @@ -17,10 +17,6 @@ describe('findBar', function () { .url(url) .waitForUrl(url) .windowParentByUrl(url) - .waitUntil(function () { - return this.getAttribute('webview[data-frame-key="1"]', 'src').then((src) => src === url) - }) - .waitForElementFocus('webview[data-frame-key="1"]') }) it('should focus findbar on show', function * () { @@ -208,9 +204,6 @@ describe('findBar', function () { .url(url2) .waitForUrl(url2) .windowParentByUrl(url2) - .waitUntil(function () { - return this.getAttribute('webview[data-frame-key="1"]', 'src').then((src) => src === url2) - }) // No findbar .waitForVisible(findBarInput, 500, true) .showFindbar() diff --git a/test/components/navigationBarTest.js b/test/components/navigationBarTest.js index a05964778d2..d5a8161eab5 100644 --- a/test/components/navigationBarTest.js +++ b/test/components/navigationBarTest.js @@ -341,10 +341,6 @@ describe('navigationBar tests', function () { .waitUntil(function () { return this.getValue(urlInput).then((val) => val === page) }) - .waitUntil(function () { - return this.getAttribute(activeWebview, 'src').then((src) => src === page) - }) - yield this.app.client .tabByUrl(this.page) .waitForExist('#bottom_link') .leftClick('#bottom_link') @@ -894,22 +890,15 @@ describe('navigationBar tests', function () { yield setup(this.app.client) // wait for the urlInput to be fully initialized yield this.app.client.waitForExist(urlInput) - yield this.app.client.keys(this.page1) - // hit enter - yield this.app.client.keys(Brave.keys.ENTER) + .keys(this.page1) + // hit enter + .keys(Brave.keys.ENTER) }) it('webview has focus', function * () { yield this.app.client.waitForElementFocus(activeWebview) }) - it('webview loads url', function * () { - var page1 = this.page1 - yield this.app.client.waitUntil(function () { - return this.getAttribute(activeWebview, 'src').then((src) => src === page1) - }) - }) - it('urlbar shows webview url when focused', function * () { var page1 = this.page1 yield blur(this.app.client) @@ -1076,9 +1065,8 @@ describe('navigationBar tests', function () { }) it('focuses on the webview', function * () { - this.app.client.waitUntil(function () { - return this.getAttribute(':focus', 'src').then((src) => src === config.defaultUrl) - }) + this.app.client + .waitForUrl(config.defaultUrl) }) }) From 0423e539c3180e65f2dac2bde89157886a63f2ff Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Sat, 10 Dec 2016 20:02:13 +0800 Subject: [PATCH 54/80] Apply changes to https://github.com/brave/browser-laptop/commit/1fea05c7012c5d017cfc20ca68b1a380b12b6b12#diff-b95013a7d2996f174fdafb3bb3cfd7cbR65 Auditors: @bridiver, @bbondy --- js/components/frame.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 81c92eecce7..f547232aa58 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -9,6 +9,7 @@ const webviewActions = require('../actions/webviewActions') const appActions = require('../actions/appActions') const ImmutableComponent = require('./immutableComponent') const Immutable = require('immutable') +const immutableUtil = require('../../app/common/state/immutableUtil') const cx = require('../lib/classSet') const siteUtil = require('../state/siteUtil') const FrameStateUtil = require('../state/frameStateUtil') @@ -713,7 +714,7 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('page-favicon-updated', (e) => { // TODO(Anthony): more general solution on muon to prevent weview event // from emitting after tab closed - if (e.favicons && e.favicons.length > 0 && this.frame) { + if (e.favicons && e.favicons.length > 0 && immutableUtil.isImmutable(this.frame)) { imageUtil.getWorkingImageUrl(e.favicons[0], (imageFound) => { windowActions.setFavicon(this.frame, imageFound ? e.favicons[0] : null) }) @@ -722,7 +723,7 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('page-title-updated', ({title}) => { // TODO(Anthony): more general solution on muon to prevent weview event // from emitting after tab closed - if (this.frame) { + if (immutableUtil.isImmutable(this.frame)) { windowActions.setFrameTitle(this.frame, title) } }) @@ -735,7 +736,7 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('hide-autofill-popup', (e) => { // TODO(Anthony): more general solution on muon to prevent weview event // from emitting after tab closed - if (this.frame) { + if (immutableUtil.isImmutable(this.frame)) { let webContents = this.webview.getWebContents() if (webContents && webContents.isFocused()) { windowActions.autofillPopupHidden(this.props.tabId) @@ -1009,7 +1010,7 @@ class Frame extends ImmutableComponent { } }) this.webview.addEventListener('did-get-response-details', (details) => { - if (this.frame) { + if (immutableUtil.isImmutable(this.frame)) { windowActions.gotResponseDetails(this.frame.get('tabId'), details) } }) From 20aa99cb6bd970658c3d799bca02751202461a26 Mon Sep 17 00:00:00 2001 From: bridiver Date: Sat, 10 Dec 2016 21:16:01 -0700 Subject: [PATCH 55/80] update to muon 2.0.2 auditors @bbondy --- .npmrc | 4 ++-- tools/cibuild.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.npmrc b/.npmrc index 70fe2bd496c..0e6ccda8099 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,5 @@ runtime = electron -target = 2.0.1 +target = 2.0.2 target_arch = x64 -brave_electron_version = 2.0.1 +brave_electron_version = 2.0.2 disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist diff --git a/tools/cibuild.py b/tools/cibuild.py index d8a2d5d0085..5621820cedd 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -5,8 +5,8 @@ import sys import os.path -BRAVE_ELECTRON = '2.0.1' -UPSTREAM_ELECTRON = '2.0.1' +BRAVE_ELECTRON = '2.0.2' +UPSTREAM_ELECTRON = '2.0.2' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) TARGET_ARCH= os.environ['TARGET_ARCH'] if os.environ.has_key('TARGET_ARCH') else 'x64' os.environ['npm_config_arch'] = TARGET_ARCH From 83eef6099851d00e87e3bd8ec2febf4d9d61a2fc Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Sun, 11 Dec 2016 08:42:39 -0500 Subject: [PATCH 56/80] Update prebuilt to 2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ec5e1497937..6e9300d33fc 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "aphrodite": "^1.0.0", "async": "^2.0.1", "electron-localshortcut": "^0.6.0", - "electron-prebuilt": "brave/electron-prebuilt#2.0.1", + "electron-prebuilt": "brave/electron-prebuilt#2.0.2", "electron-squirrel-startup": "brave/electron-squirrel-startup", "file-loader": "^0.8.5", "font-awesome": "^4.5.0", From 4507f5e9ecc6df1500ef07c5740f2251ee4ae900 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 12 Dec 2016 00:42:45 -0500 Subject: [PATCH 57/80] Fix pressing esc not restoring location This fixes a bunch of failing automated tests too. Fix #6148 Auditors: @bsclifton --- js/components/navigationBar.js | 13 ++++++++++++- js/components/urlBar.js | 19 +------------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/js/components/navigationBar.js b/js/components/navigationBar.js index c0ee31b1cbb..f1d03b50b7a 100644 --- a/js/components/navigationBar.js +++ b/js/components/navigationBar.js @@ -68,7 +68,17 @@ class NavigationBar extends ImmutableComponent { } onStop () { - ipc.emit(messages.SHORTCUT_ACTIVE_FRAME_STOP) + if (this.props.navbar.getIn(['urlbar', 'focused'])) { + windowActions.setUrlBarActive(false) + const shouldRenderSuggestions = this.props.navbar.getIn(['urlbar', 'suggestions', 'shouldRender']) === true + const suggestionList = this.props.navbar.getIn(['urlbar', 'suggestions', 'suggestionList']) + if (!shouldRenderSuggestions || + // TODO: Once we take out suggestion generation from within URLBarSuggestions we can remove this check + // and put it in shouldRenderUrlBarSuggestions where it belongs. See https://github.com/brave/browser-laptop/issues/3151 + !suggestionList || suggestionList.size === 0) { + windowActions.setUrlBarSelected(true) + } + } } get bookmarked () { @@ -190,6 +200,7 @@ class NavigationBar extends ImmutableComponent { endLoadTime={this.props.endLoadTime} titleMode={this.titleMode} urlbar={this.props.navbar.get('urlbar')} + onStop={this.onStop} menubarVisible={this.props.menubarVisible} /> { diff --git a/js/components/urlBar.js b/js/components/urlBar.js index f309be1e656..5373016d398 100644 --- a/js/components/urlBar.js +++ b/js/components/urlBar.js @@ -31,7 +31,6 @@ const {isUrl, isIntermediateAboutPage} = require('../lib/appUrlUtil') class UrlBar extends ImmutableComponent { constructor () { super() - this.onActiveFrameStop = this.onActiveFrameStop.bind(this) this.onFocus = this.onFocus.bind(this) this.onBlur = this.onBlur.bind(this) this.onKeyDown = this.onKeyDown.bind(this) @@ -213,7 +212,7 @@ class UrlBar extends ImmutableComponent { break case KeyCodes.ESC: e.preventDefault() - ipc.emit(messages.SHORTCUT_ACTIVE_FRAME_STOP) + this.props.onStop() this.clearSearchEngine() this.restore() this.select() @@ -373,28 +372,12 @@ class UrlBar extends ImmutableComponent { this.detectSearchEngine() } - onActiveFrameStop () { - if (this.isFocused()) { - windowActions.setUrlBarActive(false) - if (!this.shouldRenderUrlBarSuggestions || - // TODO: Once we take out suggestion generation from within URLBarSuggestions we can remove this check - // and put it in shouldRenderUrlBarSuggestions where it belongs. See https://github.com/brave/browser-laptop/issues/3151 - !this.props.urlbar.getIn(['suggestions', 'suggestionList']) || - this.props.urlbar.getIn(['suggestions', 'suggestionList']).size === 0) { - this.restore() - windowActions.setUrlBarSelected(true) - } - } - } - componentWillMount () { ipc.on(messages.SHORTCUT_FOCUS_URL, (e) => { windowActions.setRenderUrlBarSuggestions(false) windowActions.setUrlBarSelected(true) windowActions.setUrlBarActive(true) }) - // escape key handling - ipc.on(messages.SHORTCUT_ACTIVE_FRAME_STOP, this.onActiveFrameStop) } componentDidMount () { From 4beccb87f824477487fb834cbee6de47a02a55b2 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 12 Dec 2016 01:24:21 -0500 Subject: [PATCH 58/80] Fix hide download toolbar button Probably a merge problem that you ran into Auditors: @bridiver Introduced here: https://github.com/brave/browser-laptop/commit/72803908c199c3e2fc497711d2d54ba0053de9da It was causing the close button to render wrongly and also failing automated unit tests on the downloads bar --- app/renderer/components/downloadsBar.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/renderer/components/downloadsBar.js b/app/renderer/components/downloadsBar.js index c610e1f9037..2e520c6648e 100644 --- a/app/renderer/components/downloadsBar.js +++ b/app/renderer/components/downloadsBar.js @@ -39,7 +39,8 @@ class DownloadsBar extends ImmutableComponent { }
-
From 79362d3ea8f93246a099105e9916cf1229bf660d Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 12 Dec 2016 08:56:08 -0500 Subject: [PATCH 59/80] Fix call to Tabs.create when printing backup recovery keys Fix #6150 Auditors: @bsclifton It was crashing because it was treating this api as a promise but really it uses callbacks. Note that the print operation won't actually work until #6159 is addressed. --- app/ledger.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/ledger.js b/app/ledger.js index a204f85b777..f7ec0d5fbfd 100644 --- a/app/ledger.js +++ b/app/ledger.js @@ -270,14 +270,12 @@ var backupKeys = (appState, action) => { if (err) { console.log(err) } else { - Tabs.create({url: fileUrl(filePath)}).then((webContents) => { + Tabs.create({url: fileUrl(filePath)}, (webContents) => { if (action.backupAction === 'print') { webContents.print({silent: false, printBackground: false}) } else { webContents.downloadURL(fileUrl(filePath)) } - }).catch((err) => { - console.error(err) }) } }) From 89559a35cb4041eb005211665f5435f809e897b4 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 12 Dec 2016 12:08:59 -0500 Subject: [PATCH 60/80] Fix tests that use electron.screen Auditors: @darkdh --- test/lib/brave.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/lib/brave.js b/test/lib/brave.js index d047fa17ec6..ba6f1c2850f 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -430,7 +430,7 @@ var exports = { this.app.client.addCommand('getDefaultWindowHeight', function () { return this.execute(function () { - let screen = devTools('electron').screen + let screen = devTools('electron').remote.screen let primaryDisplay = screen.getPrimaryDisplay() return primaryDisplay.workAreaSize.height }).then((response) => response.value) @@ -438,7 +438,7 @@ var exports = { this.app.client.addCommand('getDefaultWindowWidth', function () { return this.execute(function () { - let screen = devTools('electron').screen + let screen = devTools('electron').remote.screen let primaryDisplay = screen.getPrimaryDisplay() return primaryDisplay.workAreaSize.width }).then((response) => response.value) @@ -446,7 +446,7 @@ var exports = { this.app.client.addCommand('getPrimaryDisplayHeight', function () { return this.execute(function () { - let screen = devTools('electron').screen + let screen = devTools('electron').remote.screen return screen.getPrimaryDisplay().bounds.height }).then((response) => response.value) }) @@ -459,7 +459,7 @@ var exports = { this.app.client.addCommand('getPrimaryDisplayWidth', function () { return this.execute(function () { - let screen = devTools('electron').screen + let screen = devTools('electron').remote.screen return screen.getPrimaryDisplay().bounds.width }).then((response) => response.value) }) From e2c1d3cce09eac1f259b13200417739d944e3914 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 12 Dec 2016 15:10:07 -0500 Subject: [PATCH 61/80] Make it easier to start w/ logging Auditors: @bsclifton --- docs/debugging.md | 8 ++++---- package.json | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/debugging.md b/docs/debugging.md index 8681788fe2f..022db3840b4 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -82,11 +82,11 @@ See [tests.md](https://github.com/brave/browser-laptop/blob/master/docs/tests.md ### Logging -Enable Chrome logging (same as `—enable-logging`, but set at the right time) +Enable Chromium and electron logging using: -``` -export ELECTRON_ENABLE_LOGGING=stderr -``` +`npm run start-log` + +This will pass `--enable-logging=stderr` and set the log level to `--v=1` to `start.js`. https://www.chromium.org/for-testers/enable-logging [docs/api/chrome-command-line-switches.md](https://github.com/brave/electron/blob/master/docs/api/chrome-command-line-switches.md) from electron docs. diff --git a/package.json b/package.json index 6e9300d33fc..5e496660f62 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "lint": "standard", "postinstall": "webpack", "preload-httpse": "node ./preload-httpse.js", + "start-log": "node ./tools/start.js --user-data-dir=brave-development --debug=5858 --enable-logging=stderr --v=1 --enable-extension-activity-logging --enable-sandbox-logging --enable-dcheck", "start": "node ./tools/start.js --user-data-dir=brave-development --debug=5858 --enable-logging --v=0 --enable-extension-activity-logging --enable-sandbox-logging --enable-dcheck", "start-brk": "node ./tools/start.js --debug-brk=5858 -enable-logging --v=0 --enable-dcheck", "test": "NODE_ENV=test mocha --require babel-register --require babel-polyfill 'test/**/*Test.js'", From fa88eda9df7ac64ab5f0aaa7b9451439712b8652 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Tue, 13 Dec 2016 13:28:07 +0800 Subject: [PATCH 62/80] default settings should be last resort fix #6169 Auditors: @bsclifton, @bbondy --- js/settings.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/settings.js b/js/settings.js index dc21c987bde..7a05a2308f5 100644 --- a/js/settings.js +++ b/js/settings.js @@ -49,11 +49,12 @@ const resolveValue = (settingKey, settingsCollection) => { const appSettings = (process.type === 'browser' ? require('./stores/appStore').getState().get('settings') : require('./stores/appStoreRenderer').state.get('settings')) || Immutable.Map() - if (settingsCollection && settingsCollection.constructor === Immutable.Map) { - return settingsCollection.get(settingKey) !== undefined ? settingsCollection.get(settingKey) : appConfig.defaultSettings[settingKey] + if (settingsCollection && settingsCollection.constructor === Immutable.Map && + settingsCollection.get(settingKey) !== undefined) { + return settingsCollection.get(settingKey) } - if (settingsCollection) { - return settingsCollection[settingKey] !== undefined ? settingsCollection[settingKey] : appConfig.defaultSettings[settingKey] + if (settingsCollection && settingsCollection[settingKey] !== undefined) { + return settingsCollection[settingKey] } return appSettings.get(settingKey) !== undefined ? appSettings.get(settingKey) : appConfig.defaultSettings[settingKey] } From 868644d4c70091fa5085077ca18dbddbd3eec7d1 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Tue, 13 Dec 2016 16:49:58 +0800 Subject: [PATCH 63/80] Add test to getSetting --- test/unit/settingsTest.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/test/unit/settingsTest.js b/test/unit/settingsTest.js index 7eafcea9923..846322d9f41 100644 --- a/test/unit/settingsTest.js +++ b/test/unit/settingsTest.js @@ -1,4 +1,5 @@ -/* global describe, it, beforeEach */ +/* global describe, it, beforeEach, before, after */ +const mockery = require('mockery') const settings = require('../../js/settings') const settingsConst = require('../../js/constants/settings') const {passwordManagers, extensionIds, displayNames} = require('../../js/constants/passwordManagers') @@ -12,6 +13,18 @@ require('./braveUnit') describe('settings unit test', function () { let settingsCollection = null + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + }) + + after(function () { + mockery.disable() + }) + beforeEach(function () { settingsCollection = {} }) @@ -23,11 +36,26 @@ describe('settings unit test', function () { assert.equal(response, 'testValue') }) - it('returns default value from appConfig if not found', function () { + it('returns value from appConfig if both collection and appStore not found', function () { const response = settings.getSetting(settingsConst.TABS_PER_PAGE, settingsCollection) assert.equal(response, appConfig.defaultSettings[settingsConst.TABS_PER_PAGE]) }) + it('returns value from appStore if collection not found', function () { + const nonDefaultValue = appConfig.defaultSettings[settingsConst.TABS_PER_PAGE] + 10 + let settingsState = {} + settingsState[settingsConst.TABS_PER_PAGE] = nonDefaultValue + mockery.registerMock('./stores/appStoreRenderer', { + get state () { + return Immutable.fromJS({ + settings: settingsState + }) + } + }) + const response = settings.getSetting(settingsConst.TABS_PER_PAGE, settingsCollection) + assert.equal(response, nonDefaultValue) + }) + describe('when setting default value for new config entries (based on previous session data)', function () { describe('ACTIVE_PASSWORD_MANAGER', function () { it('returns `1Password` if ONE_PASSWORD_ENABLED was true', function () { From 5f7eac6e81b63e4cadf2fc47536edb886138401b Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Fri, 9 Dec 2016 18:13:18 +0800 Subject: [PATCH 64/80] Harden context menu icon handling and add getPathFromFileURI utility function fix https://github.com/brave/electron/issues/113 Auditors: @bbondy, @bsclifton Test Plan: 1. Enable the LastPass extension 2. Enable the Pocket extension 3. Navigate to "Profile folder"/Extensions/hdokiejnpimakedhajhdlcegeplioahd 4. Remove "16": "icon2.png", from manifest.json and save 5. Restart Brave 6. Right-click context menu should have lastpass with no icon and pocket with icon --- app/common/lib/platformUtil.js | 9 +++++++ app/common/state/extensionState.js | 26 ++++++++++++-------- test/unit/app/common/lib/platformUtilTest.js | 17 +++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/app/common/lib/platformUtil.js b/app/common/lib/platformUtil.js index ab29dc386ae..0388203e24f 100644 --- a/app/common/lib/platformUtil.js +++ b/app/common/lib/platformUtil.js @@ -24,6 +24,15 @@ module.exports.getPlatformStyles = () => { return styleList } +module.exports.getPathFromFileURI = (fileURI) => { + const path = decodeURI(fileURI) + if (process.platform === 'win32') { + return path.replace('file:///', '') + } else { + return path.replace('file://', '') + } +} + module.exports.isDarwin = () => { return process.platform === 'darwin' || navigator.platform === 'MacIntel' diff --git a/app/common/state/extensionState.js b/app/common/state/extensionState.js index 2ee9d1255f7..be56e7a4baa 100644 --- a/app/common/state/extensionState.js +++ b/app/common/state/extensionState.js @@ -5,6 +5,7 @@ const { makeImmutable } = require('./immutableUtil') const Immutable = require('immutable') const windowConstants = require('../../../js/constants/windowConstants') +const platformUtil = require('../lib/platformUtil') const browserActionDefaults = Immutable.fromJS({ tabs: {} @@ -148,20 +149,25 @@ const extensionState = { state = state.setIn(['extensions', action.get('extensionId'), 'contextMenus'], new Immutable.List()) } let contextMenus = state.getIn(['extensions', action.get('extensionId'), 'contextMenus']) - let basePath = state.getIn(['extensions', action.get('extensionId'), 'base_path']) - basePath = decodeURI(basePath) - if (process.platform === 'win32') { - basePath = basePath.replace('file:///', '') + const basePath = + platformUtil.getPathFromFileURI(state.getIn(['extensions', action.get('extensionId'), 'base_path'])) + const iconPath = action.get('icon') + if (!iconPath) { + contextMenus = contextMenus.push({ + extensionId: action.get('extensionId'), + menuItemId: action.get('menuItemId'), + properties: action.get('properties').toJS() + }) } else { - basePath = basePath.replace('file://', '') - } - return state.setIn(['extensions', action.get('extensionId'), 'contextMenus'], - contextMenus.push({ + contextMenus = contextMenus.push({ extensionId: action.get('extensionId'), menuItemId: action.get('menuItemId'), properties: action.get('properties').toJS(), - icon: basePath + '/' + action.get('icon') - })) + icon: basePath + '/' + iconPath + }) + } + return state.setIn(['extensions', action.get('extensionId'), 'contextMenus'], + contextMenus) } else { return state } diff --git a/test/unit/app/common/lib/platformUtilTest.js b/test/unit/app/common/lib/platformUtilTest.js index 1f88b7c931e..71af28522f0 100644 --- a/test/unit/app/common/lib/platformUtilTest.js +++ b/test/unit/app/common/lib/platformUtilTest.js @@ -77,6 +77,23 @@ describe('platformUtil', function () { }) }) + describe('getPathFromFileURI', function () { + const winFileURI = 'file:///C:/brave/brave%20is%20awesome' + const fileURI = 'file:///brave/brave%20is%20awesome' + const winExpectedResult = 'C:/brave/brave is awesome' + const expectedResult = '/brave/brave is awesome' + it('return path for window', function () { + loadMocks(mockWin10) + const result = platformUtil.getPathFromFileURI(winFileURI) + assert.equal(result, winExpectedResult) + }) + it('return path for non window', function () { + loadMocks(mockMacOS) + const result = platformUtil.getPathFromFileURI(fileURI) + assert.equal(result, expectedResult) + }) + }) + describe('isDarwin', function () { it('returns true if using macOS', function () { loadMocks(mockMacOS) From e030f39748126ac03d281ec57ffd7a84bd97fbca Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 14 Dec 2016 12:15:47 -0500 Subject: [PATCH 65/80] Fix ledger panel color test Auditors: @bsclifton --- test/components/ledgerPanelTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/ledgerPanelTest.js b/test/components/ledgerPanelTest.js index 50bf3178895..6a09d156406 100644 --- a/test/components/ledgerPanelTest.js +++ b/test/components/ledgerPanelTest.js @@ -29,7 +29,7 @@ describe('Payments Panel', function () { .click(paymentsTab) .waitForVisible(paymentsWelcomePage) let background = yield this.app.client.getCssProperty(walletSwitch, 'background-color') - assert.equal(background.value, 'rgba(211,211,211,1)') + assert.equal(background.value, 'rgba(204,204,204,1)') }) it('payments can be enabled', function * () { From 10b0853e80c399452d390efc64aec487a37bc071 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 14 Dec 2016 12:16:05 -0500 Subject: [PATCH 66/80] Fix window tests Auditors: @bsclifton --- test/components/windowTest.js | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/test/components/windowTest.js b/test/components/windowTest.js index 5e78a1f08fa..417a93085b0 100644 --- a/test/components/windowTest.js +++ b/test/components/windowTest.js @@ -304,7 +304,9 @@ describe('application window', function () { yield this.app.client .waitForVisible(selector) - .getAttribute(selector, 'src').should.become(page1) + .tabByIndex(1) + .waitForUrl(page1) + .windowByUrl(Brave.browserWindowUrl) .getWindowCount().should.become(1) .getTabCount().should.become(2) }) @@ -615,17 +617,15 @@ describe('application window', function () { yield this.app.client .windowByIndex(0) - .getAttribute('.frameWrapper:nth-child(1) webview', 'src').should.become(clickWithTargetPage) - yield this.app.client - .windowByIndex(0) - .getAttribute('.frameWrapper:nth-child(2) webview', 'src').should.become(page1) + .tabByIndex(0) + .waitForUrl(clickWithTargetPage) + .windowByIndex(1) + .waitForUrl(page1) }) // https://github.com/brave/browser-laptop/issues/143 it('loads in the tab with the target name', function * () { let clickWithTargetPage = this.clickWithTargetPage - let page2 = this.page2 - yield this.app.client .windowByIndex(0) .click('.tabArea:nth-child(1)') @@ -633,13 +633,10 @@ describe('application window', function () { .waitForVisible('#name2') .click('#name2') .windowByIndex(0) - - yield this.app.client - .waitForVisible('.frameWrapper:nth-child(1) webview') - .getAttribute('.frameWrapper:nth-child(1) webview', 'src').should.become(clickWithTargetPage) - yield this.app.client - .getAttribute('.frameWrapper:nth-child(2) webview', 'src').should.become(page2) - yield this.app.client + .tabByIndex(0) + .waitForUrl(clickWithTargetPage) + .tabByIndex(1) + .waitForUrl(this.page2) .isExisting('.frameWrapper:nth-child(3) webview').should.eventually.be.false // same tab }) }) From 37c3862a58d4d711820c357f9fa2180400821c34 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 14 Dec 2016 12:34:39 -0500 Subject: [PATCH 67/80] Fix error page tests Auditors: @bsclifton --- test/components/errorPageTest.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/components/errorPageTest.js b/test/components/errorPageTest.js index 3886f36f050..4c91146641f 100644 --- a/test/components/errorPageTest.js +++ b/test/components/errorPageTest.js @@ -26,18 +26,18 @@ describe('errorPage', function () { yield this.app.client .waitForVisible(errorContent) .waitForVisible('span[data-l10n-id=nameNotResolved]') - .waitForVisible('span[data-l10n-id=errorReload]') + .waitForVisible('button[data-l10n-id=errorReload]') .waitForVisible(errorUrl) .getText(errorUrl).should.eventually.be.equal(this.url) - .isVisible('span[data-l10n-id=errorReload]').should.eventually.be.true - .isVisible('span[data-l10n-id=back]').should.eventually.be.true + .isVisible('button[data-l10n-id=errorReload]').should.eventually.be.true + .isVisible('button[data-l10n-id=back]').should.eventually.be.true }) it('should go back to newtab when back is clicked', function * () { yield this.app.client .waitForUrl(getTargetAboutUrl('about:error')) - .waitForVisible('span[data-l10n-id=back]') - .leftClick('span[data-l10n-id=back]', 5, 5) + .waitForVisible('button[data-l10n-id=back]') + .leftClick('button[data-l10n-id=back]', 5, 5) .waitForUrl(Brave.newTabUrl) }) @@ -45,13 +45,13 @@ describe('errorPage', function () { it.skip('should attempt a reload when reload is clicked', function * () { yield this.app.client .waitForUrl(getTargetAboutUrl('about:error')) - .waitForVisible('span[data-l10n-id=errorReload]') - .leftClick('span[data-l10n-id=errorReload]') + .waitForVisible('button[data-l10n-id=errorReload]') + .leftClick('button[data-l10n-id=errorReload]') .waitForUrl(getTargetAboutUrl('about:error')) // still no back button for the url .waitForVisible(errorUrl) .getText(errorUrl).should.eventually.be.equal(this.url) - .isVisible('span[data-l10n-id=back]').should.eventually.be.false + .isVisible('button[data-l10n-id=back]').should.eventually.be.false }) }) }) From 2338d58372b12d3e3b7e633d65b2ec7ad7254148 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Wed, 14 Dec 2016 12:46:23 -0500 Subject: [PATCH 68/80] Fix urlbar tests Auditors: @bsclifton --- test/components/urlBarTest.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/components/urlBarTest.js b/test/components/urlBarTest.js index fcf1fc539a5..f31beab138b 100644 --- a/test/components/urlBarTest.js +++ b/test/components/urlBarTest.js @@ -1,7 +1,7 @@ /* global describe, it, before, beforeEach */ const Brave = require('../lib/brave') -const {urlInput, urlBarSuggestions, urlbarIcon, activeWebview, reloadButton} = require('../lib/selectors') +const {urlInput, urlBarSuggestions, urlbarIcon, reloadButton} = require('../lib/selectors') const searchProviders = require('../../js/data/searchProviders') const config = require('../../js/constants/config') const messages = require('../../js/constants/messages') @@ -311,11 +311,11 @@ describe('urlBar tests', function () { .keys(Brave.keys.ENTER) }) - it('changes the webview src', function * () { + it('changes the webview location', function * () { const url = Brave.server.url('page1.html') - yield this.app.client.waitUntil(function () { - return this.getAttribute(activeWebview, 'src').then((src) => src === url) - }) + yield this.app.client + .tabByIndex(0) + .waitForUrl(url) }) }) }) From 7fb2e4c30c98b592c00fc390648f99672a6caad7 Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 14 Dec 2016 11:00:19 -0700 Subject: [PATCH 69/80] support for tabs.create auditors @bbondy @darkdh --- app/browser/tabs.js | 28 ++++++++- js/components/frame.js | 106 ++++++++++----------------------- js/components/main.js | 2 +- js/dispatcher/appDispatcher.js | 12 +++- js/lib/appUrlUtil.js | 6 +- js/state/frameStateUtil.js | 8 +++ js/stores/windowStore.js | 25 ++++++-- 7 files changed, 96 insertions(+), 91 deletions(-) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index ab82df90db1..ddf44d2873f 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -1,7 +1,8 @@ -const {app, extensions, webContents} = require('electron') const appActions = require('../../js/actions/appActions') -const { makeImmutable } = require('../common/state/immutableUtil') +const messages = require('../..//js/constants/messages') const tabState = require('../common/state/tabState') +const {app, extensions, webContents} = require('electron') +const { makeImmutable } = require('../common/state/immutableUtil') let currentWebContents = {} @@ -31,9 +32,30 @@ const updateTab = (tabId) => { const api = { init: (state, action) => { - process.on('add-new-contents', (e, openerTab, newTab, disposition, userGesture) => { + process.on('add-new-contents', (e, source, newTab, disposition, size, userGesture) => { if (userGesture === false) { e.preventDefault() + return + } + + let location = newTab.getURL() + if (!location || location === '') { + location = 'about:blank' + } + + const frameOpts = { + location, + partition: newTab.session.partition, + guestInstanceId: newTab.guestInstanceId, + active: disposition !== 'background-tab' + } + + if (disposition === 'new-window' || disposition === 'new-popup') { + const windowOpts = makeImmutable(size) + appActions.newWindow(makeImmutable(frameOpts), windowOpts) + } else { + let hostWebContents = source.hostWebContents || source + hostWebContents.send(messages.SHORTCUT_NEW_FRAME, location, { frameOpts }) } }) app.on('web-contents-created', function (event, tab) { diff --git a/js/components/frame.js b/js/components/frame.js index f547232aa58..e87fc3ec6eb 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -9,7 +9,6 @@ const webviewActions = require('../actions/webviewActions') const appActions = require('../actions/appActions') const ImmutableComponent = require('./immutableComponent') const Immutable = require('immutable') -const immutableUtil = require('../../app/common/state/immutableUtil') const cx = require('../lib/classSet') const siteUtil = require('../state/siteUtil') const FrameStateUtil = require('../state/frameStateUtil') @@ -264,45 +263,49 @@ class Frame extends ImmutableComponent { let location = this.props.location newSrc = newSrc || this.props.src + if (isSourceAboutUrl(newSrc)) { + newSrc = getTargetAboutUrl(newSrc) + } else if (isTorrentViewerURL(newSrc)) { + newSrc = getTargetMagnetUrl(newSrc) + } + + let guestInstanceId = null + // Create the webview dynamically because React doesn't whitelist all // of the attributes we need let webviewAdded = false - let guestInstanceId = null if (this.shouldCreateWebview()) { - // only set the guestInstanceId if this is a new frame - if (this.webview == null) { - guestInstanceId = this.props.guestInstanceId - } - while (this.webviewContainer.firstChild) { - this.webviewContainer.removeChild(this.webviewContainer.firstChild) - } - // the webview tag is where the user's page is rendered (runs in its own process) - // @see http://electron.atom.io/docs/api/web-view-tag/ + guestInstanceId = this.props.guestInstanceId this.webview = document.createElement('webview') + if (guestInstanceId) { + if (!this.webview.setGuestInstanceId(guestInstanceId)) { + console.error('could not set guestInstanceId ' + guestInstanceId) + guestInstanceId = null + } + } else { + let partition = FrameStateUtil.getPartition(this.frame) + ipc.sendSync(messages.INITIALIZE_PARTITION, partition) + this.webview.setAttribute('partition', partition) + } + this.addEventListeners() if (cb) { this.runOnDomReady = cb let eventCallback = (e) => { this.webview.removeEventListener(e.type, eventCallback) - // handle deprectaed zoom level site settings - if (this.zoomLevel) { - this.webview.setZoomLevel(this.zoomLevel) - } this.runOnDomReady() delete this.runOnDomReady } this.webview.addEventListener('did-attach', eventCallback) } - let partition = FrameStateUtil.getPartition(this.frame) - ipc.sendSync(messages.INITIALIZE_PARTITION, partition) - this.webview.setAttribute('partition', partition) - if (guestInstanceId) { - if (!this.webview.setGuestInstanceId(guestInstanceId)) { - guestInstanceId = null - } - } + webviewAdded = true } + + if (!guestInstanceId || newSrc !== getTargetAboutUrl('about:blank')) { + this.webview.setAttribute('src', newSrc) + } + this.webview.setAttribute('data-frame-key', this.props.frameKey) const parsedUrl = urlParse(location) @@ -314,14 +317,6 @@ class Frame extends ImmutableComponent { this.webview.setUserAgentOverride(hack.userAgent) } - if (!guestInstanceId || newSrc !== 'about:blank') { - let webviewSrc - if (isSourceAboutUrl(newSrc)) webviewSrc = getTargetAboutUrl(newSrc) - else if (isTorrentViewerURL(newSrc)) webviewSrc = getTargetMagnetUrl(newSrc) - else webviewSrc = newSrc - this.webview.setAttribute('src', webviewSrc) - } - if (webviewAdded) { this.webviewContainer.appendChild(this.webview) } else { @@ -673,32 +668,6 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('mouseleave', (e) => { currentWindow.webContents.send(messages.DISABLE_SWIPE_GESTURE) }) - // @see new-window event - this.webview.addEventListener('new-window', (e) => { - let guestInstanceId = e.options && e.options.guestInstanceId - let windowOpts = e.options && e.options.windowOptions || {} - windowOpts.parentWindowKey = currentWindow.id - windowOpts.disposition = e.disposition - let delayedLoadUrl = e.options && e.options.delayedLoadUrl - - let frameOpts = { - location: e.url, - parentFrameKey: this.props.frameKey, - isPrivate: this.props.isPrivate, - partitionNumber: this.props.partitionNumber, - // use the delayed load url for the temporary title - delayedLoadUrl, - guestInstanceId - } - - if (e.disposition === 'new-window' || e.disposition === 'new-popup') { - appActions.newWindow(frameOpts, windowOpts) - } else { - let openInForeground = this.props.prefOpenInForeground === true || - e.disposition !== 'background-tab' - windowActions.newFrame(frameOpts, openInForeground) - } - }) this.webview.addEventListener('did-attach', (e) => { let tabId = this.webview.getWebContents().getId() if (this.props.tabId !== tabId) { @@ -712,20 +681,14 @@ class Frame extends ImmutableComponent { this.props.onCloseFrame(this.frame) }) this.webview.addEventListener('page-favicon-updated', (e) => { - // TODO(Anthony): more general solution on muon to prevent weview event - // from emitting after tab closed - if (e.favicons && e.favicons.length > 0 && immutableUtil.isImmutable(this.frame)) { + if (e.favicons && e.favicons.length > 0) { imageUtil.getWorkingImageUrl(e.favicons[0], (imageFound) => { windowActions.setFavicon(this.frame, imageFound ? e.favicons[0] : null) }) } }) this.webview.addEventListener('page-title-updated', ({title}) => { - // TODO(Anthony): more general solution on muon to prevent weview event - // from emitting after tab closed - if (immutableUtil.isImmutable(this.frame)) { - windowActions.setFrameTitle(this.frame, title) - } + windowActions.setFrameTitle(this.frame, title) }) this.webview.addEventListener('show-autofill-settings', (e) => { windowActions.newFrame({ location: 'about:autofill' }, true) @@ -734,14 +697,7 @@ class Frame extends ImmutableComponent { contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) }) this.webview.addEventListener('hide-autofill-popup', (e) => { - // TODO(Anthony): more general solution on muon to prevent weview event - // from emitting after tab closed - if (immutableUtil.isImmutable(this.frame)) { - let webContents = this.webview.getWebContents() - if (webContents && webContents.isFocused()) { - windowActions.autofillPopupHidden(this.props.tabId) - } - } + windowActions.autofillPopupHidden(this.props.tabId) }) this.webview.addEventListener('ipc-message', (e) => { let method = () => {} @@ -1010,9 +966,7 @@ class Frame extends ImmutableComponent { } }) this.webview.addEventListener('did-get-response-details', (details) => { - if (immutableUtil.isImmutable(this.frame)) { - windowActions.gotResponseDetails(this.frame.get('tabId'), details) - } + windowActions.gotResponseDetails(this.frame.get('tabId'), details) }) // Handle zoom using Ctrl/Cmd and the mouse wheel. // this.webview.addEventListener('mousewheel', this.onMouseWheel.bind(this)) diff --git a/js/components/main.js b/js/components/main.js index 7b496ac83c5..0774f9361de 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -344,7 +344,7 @@ class Main extends ImmutableComponent { } } let openInForeground = getSetting(settings.SWITCH_TO_NEW_TABS) === true || options.openInForeground - const frameOpts = { + const frameOpts = options.frameOpts || { location: url, isPrivate: !!options.isPrivate, isPartitioned: !!options.isPartitioned, diff --git a/js/dispatcher/appDispatcher.js b/js/dispatcher/appDispatcher.js index bc6c5238b2c..428690421f6 100644 --- a/js/dispatcher/appDispatcher.js +++ b/js/dispatcher/appDispatcher.js @@ -117,12 +117,18 @@ if (process.type === 'browser') { let queryInfo = payload.queryInfo || payload.frameProps || (payload.queryInfo = {}) queryInfo = queryInfo.toJS ? queryInfo.toJS() : queryInfo - if (event.sender.hostWebContents) { + if (!event.sender.isDestroyed() && event.sender.hostWebContents) { // received from an extension // only extension messages will have a hostWebContents - let win = require('electron').BrowserWindow.fromWebContents(event.sender.hostWebContents) + // default to the windowId of the hostWebContents - queryInfo.windowId = queryInfo.windowId || win.id + if (!queryInfo.windowId) { + let win = require('electron').BrowserWindow.fromWebContents(event.sender.hostWebContents) + if (!win) { + return + } + queryInfo.windowId = win.id + } // add queryInfo if we only had frameProps before payload.queryInfo = queryInfo diff --git a/js/lib/appUrlUtil.js b/js/lib/appUrlUtil.js index eb5a2a32d20..0ed73fd8821 100644 --- a/js/lib/appUrlUtil.js +++ b/js/lib/appUrlUtil.js @@ -66,13 +66,13 @@ module.exports.getGenDir = function (url) { module.exports.getBraveIndexPath = function (relateivePath = '') { return module.exports.fileUrl( - path.resolve(__dirname, '..', '..') + '/app/extensions/brave/' + relateivePath) + path.resolve(__dirname, '..', '..') + '/app/extensions/brave/' + relateivePath).replace('file://', 'chrome://brave') } module.exports.getBraveExtIndexHTML = function () { return process.env.NODE_ENV === 'development' - ? module.exports.getBraveIndexPath('index-dev.html').replace('file://', 'chrome://brave') - : module.exports.getBraveIndexPath('index.html').replace('file://', 'chrome://brave') + ? module.exports.getBraveIndexPath('index-dev.html') + : module.exports.getBraveIndexPath('index.html') } /** diff --git a/js/state/frameStateUtil.js b/js/state/frameStateUtil.js index c35defb7b0c..180a54fa0d9 100644 --- a/js/state/frameStateUtil.js +++ b/js/state/frameStateUtil.js @@ -207,6 +207,13 @@ function isAncestorFrameKey (frames, frame, parentFrameKey) { return isAncestorFrameKey(frames, parentFrame, parentFrameKey) } +function getPartitionNumber (partition) { + console.log(partition) + const regex = /partition-(\d+)/ + const matches = regex.exec(partition) + return matches && matches[0] +} + function isSessionPartition (partition) { return partition && partition.startsWith('persist:partition-') } @@ -511,6 +518,7 @@ module.exports = { getFrameByDisplayIndex, getFrameByKey, getFrameByTabId, + getPartitionNumber, getActiveFrame, setActiveFrameDisplayIndex, setActiveFrameIndex, diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index 68d77eafa0b..8aae1e1d209 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -169,10 +169,19 @@ const newFrame = (frameOpts, openInForeground, insertionIndex, nextKey) => { } frameOpts = frameOpts.toJS ? frameOpts.toJS() : frameOpts + // handle tabs.create properties + insertionIndex = frameOpts.index || insertionIndex + + if (frameOpts.active !== undefined) { + openInForeground = frameOpts.active + } + if (openInForeground === undefined) { openInForeground = true } + // TODO(bridiver) - handle pinned property + // evaluate the location frameOpts.location = frameOpts.location || newFrameUrl() if (frameOpts.location && UrlUtil.isURL(frameOpts.location)) { @@ -189,12 +198,14 @@ const newFrame = (frameOpts, openInForeground, insertionIndex, nextKey) => { } } - if (nextKey === undefined) { - nextKey = incrementNextKey() + let partitionNumber = frameOpts.partitionNumber + if (!partitionNumber && frameOpts.partition) { + partitionNumber = FrameStateUtil.getPartitionNumber(frameOpts.partition) } + let nextPartitionNumber = 0 - if (frameOpts.partitionNumber) { - nextPartitionNumber = frameOpts.partitionNumber + if (partitionNumber) { + nextPartitionNumber = partitionNumber if (currentPartitionNumber < nextPartitionNumber) { currentPartitionNumber = nextPartitionNumber } @@ -222,6 +233,10 @@ const newFrame = (frameOpts, openInForeground, insertionIndex, nextKey) => { insertionIndex = 0 } + if (nextKey === undefined) { + nextKey = incrementNextKey() + } + windowState = windowState.merge( FrameStateUtil.addFrame( frames, windowState.get('tabs'), frameOpts, @@ -644,11 +659,11 @@ const doAction = (action) => { if (!action.detail) { if (windowState.getIn('contextMenuDetail', 'type') === 'autofill' && windowState.getIn('contextMenuDetail', 'tabId') === action.tabId) { + windowState = windowState.delete('contextMenuDetail') if (action.notify) { ipc.send('autofill-popup-hidden', action.tabId) } } - windowState = windowState.delete('contextMenuDetail') } else { windowState = windowState.set('contextMenuDetail', action.detail) } From 6f14654949f9c69d0ce098a63c1f3712e08d4d97 Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 14 Dec 2016 12:30:39 -0700 Subject: [PATCH 70/80] more tabs stuff --- app/browser/tabs.js | 3 ++- js/state/frameStateUtil.js | 5 +++++ js/stores/windowStore.js | 17 +++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index ddf44d2873f..9d531ef813c 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -43,11 +43,12 @@ const api = { location = 'about:blank' } + // TODO(bridiver) - handle pinned property?? - probably through tabValue const frameOpts = { location, partition: newTab.session.partition, guestInstanceId: newTab.guestInstanceId, - active: disposition !== 'background-tab' + disposition } if (disposition === 'new-window' || disposition === 'new-popup') { diff --git a/js/state/frameStateUtil.js b/js/state/frameStateUtil.js index 180a54fa0d9..881399b5601 100644 --- a/js/state/frameStateUtil.js +++ b/js/state/frameStateUtil.js @@ -214,6 +214,10 @@ function getPartitionNumber (partition) { return matches && matches[0] } +function isPrivatePartition (partition) { + return partition && !partition.startsWith('persist:') +} + function isSessionPartition (partition) { return partition && partition.startsWith('persist:partition-') } @@ -509,6 +513,7 @@ module.exports = { isAncestorFrameKey, isFrameKeyActive, isFrameKeyPinned, + isPrivatePartition, isSessionPartition, getFrameIndex, getFrameDisplayIndex, diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index 8aae1e1d209..c7aef98806c 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -172,16 +172,21 @@ const newFrame = (frameOpts, openInForeground, insertionIndex, nextKey) => { // handle tabs.create properties insertionIndex = frameOpts.index || insertionIndex - if (frameOpts.active !== undefined) { - openInForeground = frameOpts.active + if (frameOpts.partition) { + frameOpts.isPrivate = FrameStateUtil.isPrivatePartition(frameOpts.partition) + if (FrameStateUtil.isSessionPartition(frameOpts.partition)) { + frameOpts.partitionNumber = FrameStateUtil.getPartitionNumber(frameOpts.partition) + } + } + + if (frameOpts.disposition) { + openInForeground = frameOpts.disposition !== 'background-tab' } if (openInForeground === undefined) { openInForeground = true } - // TODO(bridiver) - handle pinned property - // evaluate the location frameOpts.location = frameOpts.location || newFrameUrl() if (frameOpts.location && UrlUtil.isURL(frameOpts.location)) { @@ -199,10 +204,6 @@ const newFrame = (frameOpts, openInForeground, insertionIndex, nextKey) => { } let partitionNumber = frameOpts.partitionNumber - if (!partitionNumber && frameOpts.partition) { - partitionNumber = FrameStateUtil.getPartitionNumber(frameOpts.partition) - } - let nextPartitionNumber = 0 if (partitionNumber) { nextPartitionNumber = partitionNumber From 9756fe885f8d8dc74be51047dab17475f21224b0 Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 14 Dec 2016 12:31:36 -0700 Subject: [PATCH 71/80] catch errors in `getPepperFlashPath` fixes https://github.com/brave/electron/issues/118 --- js/flash.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/js/flash.js b/js/flash.js index ec12bd026fb..4a0ceb23de9 100644 --- a/js/flash.js +++ b/js/flash.js @@ -87,23 +87,27 @@ const handleFlashInstallUrl = (details, isPrivate) => { } module.exports.checkFlashInstalled = (cb) => { - const pepperFlashSystemPluginPath = getPepperFlashPath() - const pepperFlashManifestPath = path.resolve(pepperFlashSystemPluginPath, '..', 'manifest.json') - fs.readFile(pepperFlashManifestPath, (err, data) => { - try { - if (err || !data) { - flashInstalled = false - } else { - const manifest = JSON.parse(data) - app.commandLine.appendSwitch('ppapi-flash-path', pepperFlashSystemPluginPath) - app.commandLine.appendSwitch('ppapi-flash-version', manifest.version) - flashInstalled = true + try { + const pepperFlashSystemPluginPath = getPepperFlashPath() + const pepperFlashManifestPath = path.resolve(pepperFlashSystemPluginPath, '..', 'manifest.json') + fs.readFile(pepperFlashManifestPath, (err, data) => { + try { + if (err || !data) { + flashInstalled = false + } else { + const manifest = JSON.parse(data) + app.commandLine.appendSwitch('ppapi-flash-path', pepperFlashSystemPluginPath) + app.commandLine.appendSwitch('ppapi-flash-version', manifest.version) + flashInstalled = true + } + } finally { + appActions.changeSetting(settings.FLASH_INSTALLED, flashInstalled) + cb && cb(flashInstalled) } - } finally { - appActions.changeSetting(settings.FLASH_INSTALLED, flashInstalled) - cb && cb(flashInstalled) - } - }) + }) + } catch (e) { + cb && cb(flashInstalled) + } } module.exports.init = () => { From a77be92e1d760de2c318a10f2df0d34c57dbd505 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Mon, 12 Dec 2016 15:33:19 +0800 Subject: [PATCH 72/80] Print stack to trace where the warning comes from Auditors: @mrose17, @bbondy --- app/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/index.js b/app/index.js index 1c4bf963ed1..de533491c0b 100644 --- a/app/index.js +++ b/app/index.js @@ -36,6 +36,8 @@ process.on('unhandledRejection', function (error, promise) { handleUncaughtError(error) }) +process.on('warning', warning => console.warn(warning.stack)) + if (process.platform === 'win32') { require('./windowsInit') } From cd1c0d61920e79f44287ec22110b0788ab7720a6 Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 14 Dec 2016 20:32:35 -0700 Subject: [PATCH 73/80] fix webpack config for devtools --- webpack.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index 9d3b5696df5..836af9624de 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -151,12 +151,12 @@ module.exports = { ], production: [ merge(app, production()), - merge(devTools, development()), + merge(devTools, production()), merge(webtorrentPage, production()) ], test: [ merge(app, production()), - merge(devTools, development()), + merge(devTools, production()), merge(webtorrentPage, production()) ] }[env] From 4f115f0f3fb90ecec2dbc0e66143fd4657ab728a Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 14 Dec 2016 20:39:37 -0700 Subject: [PATCH 74/80] faviconUrl should only be available with `tabs` permission --- app/browser/tabs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index 9d531ef813c..6bff31ff808 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -72,10 +72,10 @@ const api = { }) tab.on('page-favicon-updated', function (e, favicons) { if (favicons && favicons.length > 0) { - tab.setTabValues({ - faviconUrl: favicons[0] - }) - updateTab(tabId) + // tab.setTabValues({ + // faviconUrl: favicons[0] + // }) + // updateTab(tabId) } }) tab.on('unresponsive', () => { From 52c12cbd666857b72ed086b448d01c9625b3132d Mon Sep 17 00:00:00 2001 From: bridiver Date: Wed, 14 Dec 2016 22:02:37 -0700 Subject: [PATCH 75/80] use extensions.createTab for tabs.create auditors: @bbondy --- app/browser/tabs.js | 12 ++++++------ js/components/frame.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index 6bff31ff808..f239916a4f3 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -1,7 +1,7 @@ const appActions = require('../../js/actions/appActions') const messages = require('../..//js/constants/messages') const tabState = require('../common/state/tabState') -const {app, extensions, webContents} = require('electron') +const {app, extensions} = require('electron') const { makeImmutable } = require('../common/state/immutableUtil') let currentWebContents = {} @@ -138,9 +138,9 @@ const api = { let frameProps = action.get('frameProps') let muted = action.get('muted') let tabId = frameProps.get('tabId') - let webContents = api.getWebContents(tabId) - if (webContents) { - webContents.setAudioMuted(muted) + let tab = api.getWebContents(tabId) + if (tab) { + tab.setAudioMuted(muted) let tabValue = getTabValue(tabId) return tabState.updateTab(state, { tabValue }) } @@ -162,8 +162,8 @@ const api = { create: (createProperties, cb = null) => { createProperties = makeImmutable(createProperties).toJS() - webContents.createTab(createProperties, (webContents) => { - cb && cb(webContents) + extensions.createTab(createProperties, (tab) => { + cb && cb(tab) }) } } diff --git a/js/components/frame.js b/js/components/frame.js index e87fc3ec6eb..5bc0e465d52 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -62,7 +62,7 @@ class Frame extends ImmutableComponent { } get frame () { - return windowStore.getFrame(this.props.frameKey) || {} + return windowStore.getFrame(this.props.frameKey) || Immutable.fromJS({}) } get braveryDefaults () { From b9ec9a500c63b5475b7cefd9f5fc933835394037 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 15 Dec 2016 00:42:13 -0700 Subject: [PATCH 76/80] use new api for "clone" auditors @bbondy --- js/components/frame.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 5bc0e465d52..140b8b43425 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -430,18 +430,9 @@ class Frame extends ImmutableComponent { } clone (args) { - const newGuest = this.webview.clone() - const newGuestInstanceId = newGuest.getWebPreferences().guestInstanceId - let cloneAction - if (args && args.get('back')) { - cloneAction = newGuest.goBack - } else if (args && args.get('forward')) { - cloneAction = () => newGuest.goForward - } - if (cloneAction) { - newGuest.once('did-attach', cloneAction.bind(newGuest)) - } - windowActions.cloneFrame(this.frame, newGuestInstanceId, args && args.get('openInForeground')) + this.webview.clone((tab) => { + console.log(tab) + }) } handleShortcut () { From 30049613c1cefaac77adaaf71f7a5b4350509fc2 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Thu, 15 Dec 2016 21:48:58 +0800 Subject: [PATCH 77/80] Fix immutable.getIn and autofillPopupHidden condition fix #6233 Auditors: @bridiver, @bbondy --- js/components/frame.js | 5 ++++- js/stores/windowStore.js | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 140b8b43425..5e72bee231f 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -688,7 +688,10 @@ class Frame extends ImmutableComponent { contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) }) this.webview.addEventListener('hide-autofill-popup', (e) => { - windowActions.autofillPopupHidden(this.props.tabId) + let webContents = this.webview.getWebContents() + if (webContents && webContents.isFocused()) { + windowActions.autofillPopupHidden(this.props.tabId) + } }) this.webview.addEventListener('ipc-message', (e) => { let method = () => {} diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index c7aef98806c..b4e199e2364 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -658,8 +658,8 @@ const doAction = (action) => { case windowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN: case windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL: if (!action.detail) { - if (windowState.getIn('contextMenuDetail', 'type') === 'autofill' && - windowState.getIn('contextMenuDetail', 'tabId') === action.tabId) { + if (windowState.getIn(['contextMenuDetail', 'type']) === 'autofill' && + windowState.getIn(['contextMenuDetail', 'tabId']) === action.tabId) { windowState = windowState.delete('contextMenuDetail') if (action.notify) { ipc.send('autofill-popup-hidden', action.tabId) From 0d9e7b13980274766af1c8f41f5882106adddf58 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 15 Dec 2016 11:06:50 -0700 Subject: [PATCH 78/80] remote `getWebContents` auditors @bbondy @darkdh --- js/components/frame.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/js/components/frame.js b/js/components/frame.js index 5e72bee231f..767d90e8407 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -660,7 +660,7 @@ class Frame extends ImmutableComponent { currentWindow.webContents.send(messages.DISABLE_SWIPE_GESTURE) }) this.webview.addEventListener('did-attach', (e) => { - let tabId = this.webview.getWebContents().getId() + let tabId = this.webview.getId() if (this.props.tabId !== tabId) { windowActions.setFrameTabId(this.frame, tabId) } @@ -688,8 +688,7 @@ class Frame extends ImmutableComponent { contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) }) this.webview.addEventListener('hide-autofill-popup', (e) => { - let webContents = this.webview.getWebContents() - if (webContents && webContents.isFocused()) { + if (this.webview.isFocused()) { windowActions.autofillPopupHidden(this.props.tabId) } }) @@ -884,9 +883,8 @@ class Frame extends ImmutableComponent { // After navigating to the URL via back/forward buttons, set correct frame title if (!e.isRendererInitiated) { - let webContents = this.webview.getWebContents() - let index = webContents.getCurrentEntryIndex() - let title = webContents.getTitleAtIndex(index) + let index = this.webview.getCurrentEntryIndex() + let title = this.webview.getTitleAtIndex(index) windowActions.setFrameTitle(this.frame, title) } }) @@ -970,9 +968,9 @@ class Frame extends ImmutableComponent { this.webview.goBack() } - getHistoryEntry (sites, webContent, index) { - const url = webContent.getURLAtIndex(index) - const title = webContent.getTitleAtIndex(index) + getHistoryEntry (sites, index) { + const url = this.webview.getURLAtIndex(index) + const title = this.webview.getTitleAtIndex(index) let entry = { index: index, @@ -996,18 +994,18 @@ class Frame extends ImmutableComponent { } getHistory (appState) { - const webContent = this.webview.getWebContents() - const historyCount = webContent.getEntryCount() + const historyCount = this.webview.getEntryCount() + const currentIndex = this.webview.getCurrentEntryIndex() const sites = appState ? appState.get('sites') : null let history = { count: historyCount, - currentIndex: webContent.getCurrentEntryIndex(), + currentIndex, entries: [] } for (let index = 0; index < historyCount; index++) { - history.entries.push(this.getHistoryEntry(sites, webContent, index)) + history.entries.push(this.getHistoryEntry(sites, index)) } return history From 4e2473536a8b8abaa3c29d6374d4635ceb830795 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 15 Dec 2016 16:45:49 -0700 Subject: [PATCH 79/80] handle OpenURLFromTab auditors @bbondy --- app/browser/tabs.js | 7 +++++++ js/components/frame.js | 6 ++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index f239916a4f3..de86c87cefb 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -32,6 +32,13 @@ const updateTab = (tabId) => { const api = { init: (state, action) => { + process.on('open-url-from-tab', (e, source, targetUrl) => { + api.create({ + url: targetUrl, + openerTabId: source.getId() + }) + }) + process.on('add-new-contents', (e, source, newTab, disposition, size, userGesture) => { if (userGesture === false) { e.preventDefault() diff --git a/js/components/frame.js b/js/components/frame.js index 767d90e8407..19d1e2f8b55 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -430,9 +430,7 @@ class Frame extends ImmutableComponent { } clone (args) { - this.webview.clone((tab) => { - console.log(tab) - }) + this.webview.clone() } handleShortcut () { @@ -462,7 +460,7 @@ class Frame extends ImmutableComponent { this.webview.reloadIgnoringCache() break case 'clone': - this.clone(this.props.activeShortcutDetails) + this.clone() break case 'explicitLoadURL': this.webview.loadURL(this.props.location) From b0e85ebb17e1753b52f6d082d9fe4118a674fdd5 Mon Sep 17 00:00:00 2001 From: bridiver Date: Thu, 15 Dec 2016 21:41:04 -0700 Subject: [PATCH 80/80] bump to muon 2.0.4 auditors @bbondy --- .npmrc | 4 ++-- tools/cibuild.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.npmrc b/.npmrc index 0e6ccda8099..6adc4e62390 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,5 @@ runtime = electron -target = 2.0.2 +target = 2.0.4 target_arch = x64 -brave_electron_version = 2.0.2 +brave_electron_version = 2.0.4 disturl = http://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist diff --git a/tools/cibuild.py b/tools/cibuild.py index 5621820cedd..72eacbe7115 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -5,8 +5,8 @@ import sys import os.path -BRAVE_ELECTRON = '2.0.2' -UPSTREAM_ELECTRON = '2.0.2' +BRAVE_ELECTRON = '2.0.4' +UPSTREAM_ELECTRON = '2.0.4' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) TARGET_ARCH= os.environ['TARGET_ARCH'] if os.environ.has_key('TARGET_ARCH') else 'x64' os.environ['npm_config_arch'] = TARGET_ARCH