1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-07-08 12:57:57 +02:00

changes required to use chromium platform code for webext platform code

This commit is contained in:
gorhill 2016-10-19 10:20:26 -04:00
parent a4ce5ec6af
commit e01a130bc5
7 changed files with 199 additions and 350 deletions

View File

@ -76,159 +76,166 @@ vAPI.storage = chrome.storage.local;
// Do not mess up with existing settings if not assigning them stricter
// values.
vAPI.browserSettings = {
webRTCSupported: undefined,
// https://github.com/gorhill/uBlock/issues/875
// Must not leave `lastError` unchecked.
noopCallback: function() {
void chrome.runtime.lastError;
},
// Calling with `true` means IP address leak is not prevented.
// https://github.com/gorhill/uBlock/issues/533
// We must first check wether this Chromium-based browser was compiled
// with WebRTC support. To do this, we use an iframe, this way the
// empty RTCPeerConnection object we create to test for support will
// be properly garbage collected. This prevents issues such as
// a computer unable to enter into sleep mode, as reported in the
// Chrome store:
// https://github.com/gorhill/uBlock/issues/533#issuecomment-167931681
setWebrtcIPAddress: function(setting) {
// We don't know yet whether this browser supports WebRTC: find out.
if ( this.webRTCSupported === undefined ) {
this.webRTCSupported = { setting: setting };
var iframe = document.createElement('iframe');
var me = this;
var messageHandler = function(ev) {
if ( ev.origin !== self.location.origin ) {
return;
}
window.removeEventListener('message', messageHandler);
var setting = me.webRTCSupported.setting;
me.webRTCSupported = ev.data === 'webRTCSupported';
me.setWebrtcIPAddress(setting);
iframe.parentNode.removeChild(iframe);
iframe = null;
};
window.addEventListener('message', messageHandler);
iframe.src = 'is-webrtc-supported.html';
document.body.appendChild(iframe);
return;
}
// We are waiting for a response from our iframe. This makes the code
// safe to re-entrancy.
if ( typeof this.webRTCSupported === 'object' ) {
this.webRTCSupported.setting = setting;
return;
}
// https://github.com/gorhill/uBlock/issues/533
// WebRTC not supported: `webRTCMultipleRoutesEnabled` can NOT be
// safely accessed. Accessing the property will cause full browser
// crash.
if ( this.webRTCSupported !== true ) {
return;
}
var cp = chrome.privacy,
cpn = cp.network;
// Older version of Chromium do not support this setting, and is
// marked as "deprecated" since Chromium 48.
if ( typeof cpn.webRTCMultipleRoutesEnabled === 'object' ) {
try {
if ( setting ) {
cpn.webRTCMultipleRoutesEnabled.clear({
scope: 'regular'
}, this.noopCallback);
} else {
cpn.webRTCMultipleRoutesEnabled.set({
value: false,
scope: 'regular'
}, this.noopCallback);
}
} catch(ex) {
console.error(ex);
}
}
// This setting became available in Chromium 48.
if ( typeof cpn.webRTCIPHandlingPolicy === 'object' ) {
try {
if ( setting ) {
cpn.webRTCIPHandlingPolicy.clear({
scope: 'regular'
}, this.noopCallback);
} else {
// Respect current stricter setting if any.
cpn.webRTCIPHandlingPolicy.get({}, function(details) {
var value = details.value === 'disable_non_proxied_udp' ?
'disable_non_proxied_udp' :
'default_public_interface_only';
cpn.webRTCIPHandlingPolicy.set({
value: value,
scope: 'regular'
}, this.noopCallback);
}.bind(this));
}
} catch(ex) {
console.error(ex);
}
}
},
set: function(details) {
for ( var setting in details ) {
if ( details.hasOwnProperty(setting) === false ) {
continue;
}
switch ( setting ) {
case 'prefetching':
try {
if ( !!details[setting] ) {
chrome.privacy.network.networkPredictionEnabled.clear({
scope: 'regular'
}, this.noopCallback);
} else {
chrome.privacy.network.networkPredictionEnabled.set({
value: false,
scope: 'regular'
}, this.noopCallback);
}
} catch(ex) {
console.error(ex);
}
break;
case 'hyperlinkAuditing':
try {
if ( !!details[setting] ) {
chrome.privacy.websites.hyperlinkAuditingEnabled.clear({
scope: 'regular'
}, this.noopCallback);
} else {
chrome.privacy.websites.hyperlinkAuditingEnabled.set({
value: false,
scope: 'regular'
}, this.noopCallback);
}
} catch(ex) {
console.error(ex);
}
break;
case 'webrtcIPAddress':
this.setWebrtcIPAddress(!!details[setting]);
break;
default:
break;
}
}
vAPI.browserSettings = (function() {
// Not all platforms support `chrome.privacy`.
if ( chrome.privacy instanceof Object === false ) {
return;
}
};
return {
webRTCSupported: undefined,
// https://github.com/gorhill/uBlock/issues/875
// Must not leave `lastError` unchecked.
noopCallback: function() {
void chrome.runtime.lastError;
},
// Calling with `true` means IP address leak is not prevented.
// https://github.com/gorhill/uBlock/issues/533
// We must first check wether this Chromium-based browser was compiled
// with WebRTC support. To do this, we use an iframe, this way the
// empty RTCPeerConnection object we create to test for support will
// be properly garbage collected. This prevents issues such as
// a computer unable to enter into sleep mode, as reported in the
// Chrome store:
// https://github.com/gorhill/uBlock/issues/533#issuecomment-167931681
setWebrtcIPAddress: function(setting) {
// We don't know yet whether this browser supports WebRTC: find out.
if ( this.webRTCSupported === undefined ) {
this.webRTCSupported = { setting: setting };
var iframe = document.createElement('iframe');
var me = this;
var messageHandler = function(ev) {
if ( ev.origin !== self.location.origin ) {
return;
}
window.removeEventListener('message', messageHandler);
var setting = me.webRTCSupported.setting;
me.webRTCSupported = ev.data === 'webRTCSupported';
me.setWebrtcIPAddress(setting);
iframe.parentNode.removeChild(iframe);
iframe = null;
};
window.addEventListener('message', messageHandler);
iframe.src = 'is-webrtc-supported.html';
document.body.appendChild(iframe);
return;
}
// We are waiting for a response from our iframe. This makes the code
// safe to re-entrancy.
if ( typeof this.webRTCSupported === 'object' ) {
this.webRTCSupported.setting = setting;
return;
}
// https://github.com/gorhill/uBlock/issues/533
// WebRTC not supported: `webRTCMultipleRoutesEnabled` can NOT be
// safely accessed. Accessing the property will cause full browser
// crash.
if ( this.webRTCSupported !== true ) {
return;
}
var cp = chrome.privacy,
cpn = cp.network;
// Older version of Chromium do not support this setting, and is
// marked as "deprecated" since Chromium 48.
if ( typeof cpn.webRTCMultipleRoutesEnabled === 'object' ) {
try {
if ( setting ) {
cpn.webRTCMultipleRoutesEnabled.clear({
scope: 'regular'
}, this.noopCallback);
} else {
cpn.webRTCMultipleRoutesEnabled.set({
value: false,
scope: 'regular'
}, this.noopCallback);
}
} catch(ex) {
console.error(ex);
}
}
// This setting became available in Chromium 48.
if ( typeof cpn.webRTCIPHandlingPolicy === 'object' ) {
try {
if ( setting ) {
cpn.webRTCIPHandlingPolicy.clear({
scope: 'regular'
}, this.noopCallback);
} else {
// Respect current stricter setting if any.
cpn.webRTCIPHandlingPolicy.get({}, function(details) {
var value = details.value === 'disable_non_proxied_udp' ?
'disable_non_proxied_udp' :
'default_public_interface_only';
cpn.webRTCIPHandlingPolicy.set({
value: value,
scope: 'regular'
}, this.noopCallback);
}.bind(this));
}
} catch(ex) {
console.error(ex);
}
}
},
set: function(details) {
for ( var setting in details ) {
if ( details.hasOwnProperty(setting) === false ) {
continue;
}
switch ( setting ) {
case 'prefetching':
try {
if ( !!details[setting] ) {
chrome.privacy.network.networkPredictionEnabled.clear({
scope: 'regular'
}, this.noopCallback);
} else {
chrome.privacy.network.networkPredictionEnabled.set({
value: false,
scope: 'regular'
}, this.noopCallback);
}
} catch(ex) {
console.error(ex);
}
break;
case 'hyperlinkAuditing':
try {
if ( !!details[setting] ) {
chrome.privacy.websites.hyperlinkAuditingEnabled.clear({
scope: 'regular'
}, this.noopCallback);
} else {
chrome.privacy.websites.hyperlinkAuditingEnabled.set({
value: false,
scope: 'regular'
}, this.noopCallback);
}
} catch(ex) {
console.error(ex);
}
break;
case 'webrtcIPAddress':
this.setWebrtcIPAddress(!!details[setting]);
break;
default:
break;
}
}
}
};
})();
/******************************************************************************/
/******************************************************************************/
@ -329,7 +336,10 @@ vAPI.tabs.registerListeners = function() {
chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigate);
chrome.webNavigation.onCommitted.addListener(onCommitted);
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
// Not supported on Firefox WebExtensions yet.
if ( chrome.webNavigation.onCreatedNavigationTarget instanceof Object ) {
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
}
chrome.tabs.onActivated.addListener(onActivated);
chrome.tabs.onUpdated.addListener(onUpdated);
@ -1243,6 +1253,11 @@ vAPI.adminStorage = {
/******************************************************************************/
vAPI.cloud = (function() {
// Not all platforms support `chrome.storage.sync`.
if ( chrome.storage.sync instanceof Object === false ) {
return;
}
var chunkCountPerFetch = 16; // Must be a power of 2
// Mind chrome.storage.sync.MAX_ITEMS (512 at time of writing)

View File

@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2014-2016 The uBlock Origin authors
Copyright (C) 2016 The uBlock Origin authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -23,192 +23,8 @@
'use strict';
/******************************************************************************/
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1067
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
// Firefox 17/Chromium 41 supports `startsWith`.
if ( String.prototype.startsWith instanceof Function === false ) {
String.prototype.startsWith = function(needle, pos) {
if ( typeof pos !== 'number' ) {
pos = 0;
}
return this.lastIndexOf(needle, pos) === pos;
};
}
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1067
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
// Firefox 17/Chromium 41 supports `endsWith`.
if ( String.prototype.endsWith instanceof Function === false ) {
String.prototype.endsWith = function(needle, pos) {
if ( typeof pos !== 'number' ) {
pos = this.length;
}
pos -= needle.length;
return this.indexOf(needle, pos) === pos;
};
}
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1070
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility
// This polyfill is designed to fulfill *only* what uBlock Origin needs -- this
// is not an accurate API of the real Set() type.
if ( self.Set instanceof Function === false ) {
self.Set = function(iter) {
this.clear();
if ( Array.isArray(iter) ) {
for ( var i = 0, n = iter.length; i < n; i++ ) {
this.add(iter[i]);
}
return;
}
};
self.Set.polyfill = true;
self.Set.prototype.clear = function() {
this._set = Object.create(null);
this.size = 0;
// Iterator stuff
this._values = undefined;
this._i = undefined;
this.value = undefined;
this.done = true;
};
self.Set.prototype.add = function(k) {
if ( this._set[k] === undefined ) {
this._set[k] = true;
this.size += 1;
}
return this;
};
self.Set.prototype.delete = function(k) {
if ( this._set[k] !== undefined ) {
delete this._set[k];
this.size -= 1;
return true;
}
return false;
};
self.Set.prototype.has = function(k) {
return this._set[k] !== undefined;
};
self.Set.prototype.next = function() {
if ( this._i < this.size ) {
this.value = this._values[this._i++];
} else {
this._values = undefined;
this.value = undefined;
this.done = true;
}
return this;
};
self.Set.prototype.values = function() {
this._values = Object.keys(this._set);
this._i = 0;
this.value = undefined;
this.done = false;
return this;
};
}
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1070
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility
// This polyfill is designed to fulfill *only* what uBlock Origin needs -- this
// is not an accurate API of the real Map() type.
if ( self.Map instanceof Function === false ) {
self.Map = function(iter) {
this.clear();
if ( Array.isArray(iter) ) {
for ( var i = 0, n = iter.length, entry; i < n; i++ ) {
entry = iter[i];
this.set(entry[0], entry[1]);
}
return;
}
};
self.Map.polyfill = true;
self.Map.prototype.clear = function() {
this._map = Object.create(null);
this.size = 0;
// Iterator stuff
this._keys = undefined;
this._i = undefined;
this.value = undefined;
this.done = true;
};
self.Map.prototype.delete = function(k) {
if ( this._map[k] !== undefined ) {
delete this._map[k];
this.size -= 1;
return true;
}
return false;
};
self.Map.prototype.entries = function() {
this._keys = Object.keys(this._map);
this._i = 0;
this.value = [ undefined, undefined ];
this.done = false;
return this;
};
self.Map.prototype.get = function(k) {
return this._map[k];
};
self.Map.prototype.has = function(k) {
return this._map[k] !== undefined;
};
self.Map.prototype.next = function() {
if ( this._i < this.size ) {
var key = this._keys[this._i++];
this.value[0] = key;
this.value[1] = this._map[key];
} else {
this._keys = undefined;
this.value = undefined;
this.done = true;
}
return this;
};
self.Map.prototype.set = function(k, v) {
if ( v !== undefined ) {
if ( this._map[k] === undefined ) {
this.size += 1;
}
this._map[k] = v;
} else {
if ( this._map[k] !== undefined ) {
this.size -= 1;
}
delete this._map[k];
}
return this;
};
}
// Nothing to polyfill so far for Firefox's WebExtensions.
/******************************************************************************/

View File

@ -70,6 +70,10 @@ return {
webrtcIPAddressHidden: false
},
// Features detection.
privacySettingsSupported: vAPI.browserSettings instanceof Object,
cloudStorageSupported: vAPI.cloud instanceof Object,
// https://github.com/chrisaljoudi/uBlock/issues/180
// Whitelist directives need to be loaded once the PSL is available
netWhitelist: {},

View File

@ -650,7 +650,7 @@ vAPI.messaging.listen('elementPicker', onMessage);
var onMessage = function(request, sender, callback) {
// Cloud storage support is optional.
if ( vAPI.cloud instanceof Object === false ) {
if ( µBlock.cloudStorageSupported !== true ) {
callback();
return;
}
@ -725,7 +725,8 @@ var getLocalData = function(callback) {
lastRestoreTime: o.lastRestoreTime,
lastBackupFile: o.lastBackupFile,
lastBackupTime: o.lastBackupTime,
cloudStorageSupported: vAPI.cloud instanceof Object
cloudStorageSupported: µb.cloudStorageSupported,
privacySettingsSupported: µb.privacySettingsSupported
});
};

View File

@ -142,6 +142,11 @@ var onLocalDataReceived = function(details) {
if ( details.cloudStorageSupported === false ) {
uDom('#cloud-storage-enabled').attr('disabled', '');
}
if ( details.privacySettingsSupported === false ) {
uDom('#prefetching-disabled').attr('disabled', '');
uDom('#hyperlink-auditing-disabled').attr('disabled', '');
uDom('#webrtc-ipaddress-hidden').attr('disabled', '');
}
};
/******************************************************************************/

View File

@ -68,7 +68,7 @@ var onAllReady = function() {
µb.assets.remoteFetchBarrier -= 1;
// vAPI.cloud is optional.
if ( vAPI.cloud instanceof Object ) {
if ( µb.cloudStorageSupported ) {
vAPI.cloud.start([
'tpFiltersPane',
'myFiltersPane',
@ -169,11 +169,13 @@ var onUserSettingsReady = function(fetched) {
µb.assets.autoUpdate = userSettings.autoUpdate;
µb.assets.autoUpdateDelay = µb.updateAssetsEvery;
vAPI.browserSettings.set({
'hyperlinkAuditing': !userSettings.hyperlinkAuditingDisabled,
'prefetching': !userSettings.prefetchingDisabled,
'webrtcIPAddress': !userSettings.webrtcIPAddressHidden
});
if ( µb.privacySettingsSupported ) {
vAPI.browserSettings.set({
'hyperlinkAuditing': !userSettings.hyperlinkAuditingDisabled,
'prefetching': !userSettings.prefetchingDisabled,
'webrtcIPAddress': !userSettings.webrtcIPAddressHidden
});
}
µb.permanentFirewall.fromString(fetched.dynamicFilteringString);
µb.sessionFirewall.assign(µb.permanentFirewall);

View File

@ -283,7 +283,9 @@ var matchWhitelistDirective = function(url, hostname, directive) {
this.contextMenu.update(null);
break;
case 'hyperlinkAuditingDisabled':
vAPI.browserSettings.set({ 'hyperlinkAuditing': !value });
if ( this.privacySettingsSupported ) {
vAPI.browserSettings.set({ 'hyperlinkAuditing': !value });
}
break;
case 'noCosmeticFiltering':
if ( this.hnSwitches.toggle('no-cosmetic-filtering', '*', value ? 1 : 0) ) {
@ -301,10 +303,14 @@ var matchWhitelistDirective = function(url, hostname, directive) {
}
break;
case 'prefetchingDisabled':
vAPI.browserSettings.set({ 'prefetching': !value });
if ( this.privacySettingsSupported ) {
vAPI.browserSettings.set({ 'prefetching': !value });
}
break;
case 'webrtcIPAddressHidden':
vAPI.browserSettings.set({ 'webrtcIPAddress': !value });
if ( this.privacySettingsSupported ) {
vAPI.browserSettings.set({ 'webrtcIPAddress': !value });
}
break;
default:
break;