diff --git a/app/extensions/brave/brave-default.js b/app/extensions/brave/brave-default.js index 7a86629d26c..dbf44e68893 100644 --- a/app/extensions/brave/brave-default.js +++ b/app/extensions/brave/brave-default.js @@ -812,7 +812,7 @@ if (typeof KeyEvent === 'undefined') { /** * @return {string} */ - function getPageScript () { + function getBlockFpPageScript () { return '(' + Function.prototype.toString.call(function (ERROR) { ERROR.stackTraceLimit = Infinity // collect all frames var event_id = document.currentScript ? document.currentScript.getAttribute('data-event-id') : '' @@ -1054,8 +1054,8 @@ if (typeof KeyEvent === 'undefined') { /** * Executes a script in the page DOM context * - * @param text The content of the script to insert - * @param data attributes to set in the inserted script tag + * @param {string} text The content of the script to insert + * @param {Object=} data attributes to set in the inserted script tag */ function insertScript (text, data) { var parent = document.documentElement @@ -1064,8 +1064,10 @@ if (typeof KeyEvent === 'undefined') { script.text = text script.async = false - for (var key in data) { - script.setAttribute('data-' + key.replace('_', '-'), data[key]) + if (data) { + for (var key in data) { + script.setAttribute('data-' + key.replace('_', '-'), data[key]) + } } parent.insertBefore(script, parent.firstChild) @@ -1084,9 +1086,73 @@ if (typeof KeyEvent === 'undefined') { ipcRenderer.send('got-canvas-fingerprinting', e.detail) }) - insertScript(getPageScript(), { + insertScript(getBlockFpPageScript(), { event_id: event_id }) }) /* End canvas fingerprinting detection */ + + /* Begin block of third-party client-side storage */ + + /** + * Whether this is running in a third-party document. + */ + function is3rdPartyDoc () { + try { + // Try accessing an element that cross-origin frames aren't supposed to + window.top.document + } catch (e) { + if (e.name === 'SecurityError') { + return true + } else { + console.log('got unexpected error accessing window.top.document', e) + // Err on the safe side and assume this is a third-party frame + return true + } + } + return false + } + + function blockStorage () { + console.log('blocking 3rd party storage mechanisms', window.location.href) + // Block js cookie storage + Document.prototype.__defineGetter__('cookie', () => {return ""}) + Document.prototype.__defineSetter__('cookie', () => {}) + // Block websql + window.openDatabase = () => { return {} } + // Block FileSystem API + window.webkitRequestFileSystem = () => { return {} } + // Block indexeddb + window.indexedDB.open = () => { return {} } + } + + function getBlockStoragePageScript () { + return '(' + Function.prototype.toString.call(blockStorage) + '());' + } + + function clearStorage () { + // Clears HTML5 storage when the page is loaded/unloaded. + console.log('clearing 3rd party storage', window.location.href) + window.localStorage.clear() + window.sessionStorage.clear() + // Clear IndexedDB + var indexedDB = window.indexedDB + indexedDB.webkitGetDatabaseNames().onsuccess = (sender) => { + var dbs = sender.target.result + for (var i = 0; i < dbs.length; i++) { + // Delete each DB + indexedDB.deleteDatabase(dbs[i]) + } + } + } + + // TODO: This should only run if ipcRenderer sends + // block-third-party-storage. Blocked by #2041. + if (is3rdPartyDoc()) { + insertScript(getBlockStoragePageScript()) + clearStorage() + window.addEventListener('unload', clearStorage) + } + + /* End block of 3rd party storage */ }).apply(this) diff --git a/js/components/frame.js b/js/components/frame.js index 59442860ff4..74384ebb0e6 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -444,6 +444,9 @@ class Frame extends ImmutableComponent { if (this.props.enableFingerprintingProtection) { this.webview.send(messages.BLOCK_CANVAS_FINGERPRINTING) } + if (this.props.block3rdPartyStorage) { + this.webview.send(messages.BLOCK_THIRD_PARTY_STORAGE) + } windowActions.updateBackForwardState( this.props.frame, this.webview.canGoBack(), @@ -507,9 +510,6 @@ class Frame extends ImmutableComponent { }) this.webview.addEventListener('load-start', (e) => { loadStart(e) - if (this.props.enableFingerprintingProtection) { - this.webview.send(messages.BLOCK_CANVAS_FINGERPRINTING) - } }) this.webview.addEventListener('did-navigate', (e) => { // only give focus focus is this is not the initial default page load diff --git a/js/components/main.js b/js/components/main.js index 68c4841de98..573df1ba975 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -472,6 +472,25 @@ class Main extends ImmutableComponent { return getSetting(settings.BLOCK_CANVAS_FINGERPRINTING) || false } + get block3rdPartyStorage () { + if (this.activeSiteSettings) { + if (this.activeSiteSettings.get('shieldsUp') === false) { + return false + } + + if (typeof this.activeSiteSettings.get('cookieControl') === 'string') { + return this.activeSiteSettings.get('cookieControl') === 'block3rdPartyCookie' + } + } + + let enabled = this.props.appState.getIn(['cookieblock', 'enabled']) + if (typeof enabled !== 'boolean') { + enabled = appConfig.cookieblock.enabled + } + + return enabled + } + onCloseFrame (activeFrameProps) { windowActions.closeFrame(this.props.windowState.get('frames'), activeFrameProps) } @@ -809,6 +828,7 @@ class Main extends ImmutableComponent { enableAds={this.enableAds} enableNoScript={this.enableNoScript} enableFingerprintingProtection={this.enableFingerprintingProtection} + block3rdPartyStorage={this.block3rdPartyStorage} isPreview={frame.get('key') === this.props.windowState.get('previewFrameKey')} isActive={FrameStateUtil.isFrameKeyActive(this.props.windowState, frame.get('key'))} />) diff --git a/js/constants/messages.js b/js/constants/messages.js index 2f36e90a35e..5f91a782d6e 100644 --- a/js/constants/messages.js +++ b/js/constants/messages.js @@ -71,6 +71,7 @@ const messages = { AUTOFILL_PASSWORD: _, BLOCK_CANVAS_FINGERPRINTING: _, GOT_CANVAS_FINGERPRINTING: _, + BLOCK_THIRD_PARTY_STORAGE: _, SHOW_NOTIFICATION: _, /** @arg {string} l10n id of desktop notification message */ SET_RESOURCE_ENABLED: _, GO_BACK: _,