Distinguish between priviledge and unprivileged messages

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/710

Messages from unprivileged ports (i.e. from content scripts)
are no longer relayed to message handlers which are to be
strictly used to execute privileged code.

The last remaining case of unprivileged messages which
should be converted into a privileged ones will be taken
care of when the following issue is fixed:
- https://github.com/gorhill/uBlock/issues/3497
This commit is contained in:
Raymond Hill 2019-09-01 12:43:12 -04:00
parent ac56aabd7c
commit ca9b29c7ec
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
6 changed files with 365 additions and 327 deletions

View File

@ -806,72 +806,96 @@ chrome.browserAction.onClicked.addListener(function(tab) {
/******************************************************************************/
/******************************************************************************/
// https://github.com/uBlockOrigin/uBlock-issues/issues/710
// uBO uses only ports to communicate with its auxiliary pages and
// content scripts. Whether a message can trigger a privileged operation is
// decided based on whether the port from which a message is received is
// privileged, which is a status evaluated once, at port connection time.
vAPI.messaging = {
ports: new Map(),
listeners: {},
listeners: new Map(),
defaultHandler: null,
PRIVILEGED_URL: vAPI.getURL(''),
NOOPFUNC: noopFunc,
UNHANDLED: 'vAPI.messaging.notHandled'
};
UNHANDLED: 'vAPI.messaging.notHandled',
/******************************************************************************/
listen: function(details) {
this.listeners.set(details.name, {
fn: details.listener,
privileged: details.privileged === true
});
},
vAPI.messaging.listen = function(listenerName, callback) {
this.listeners[listenerName] = callback;
};
onPortDisconnect: function(port) {
this.ports.delete(port.name);
},
/******************************************************************************/
onPortConnect: function(port) {
port.onDisconnect.addListener(
port => this.onPortDisconnect(port)
);
port.onMessage.addListener(
(request, port) => this.onPortMessage(request, port)
);
this.ports.set(port.name, {
port,
privileged: port.sender.url.startsWith(this.PRIVILEGED_URL)
});
},
vAPI.messaging.onPortMessage = (function() {
var messaging = vAPI.messaging;
setup: function(defaultHandler) {
if ( this.defaultHandler !== null ) { return; }
// Use a wrapper to avoid closure and to allow reuse.
var CallbackWrapper = function(port, request) {
this.callback = this.proxy.bind(this); // bind once
this.init(port, request);
};
if ( typeof defaultHandler !== 'function' ) {
defaultHandler = function() {
return this.UNHANDLED;
};
}
this.defaultHandler = defaultHandler;
CallbackWrapper.prototype = {
init: function(port, request) {
this.port = port;
this.request = request;
return this;
},
proxy: function(response) {
// https://github.com/chrisaljoudi/uBlock/issues/383
if ( messaging.ports.has(this.port.name) ) {
this.port.postMessage({
auxProcessId: this.request.auxProcessId,
channelName: this.request.channelName,
msg: response !== undefined ? response : null
});
browser.runtime.onConnect.addListener(
port => this.onPortConnect(port)
);
// https://bugzilla.mozilla.org/show_bug.cgi?id=1392067
// Workaround: manually remove ports matching removed tab.
if (
vAPI.webextFlavor.soup.has('firefox') &&
vAPI.webextFlavor.major < 61
) {
browser.tabs.onRemoved.addListener(tabId => {
for ( const { port } of this.ports.values() ) {
const tab = port.sender && port.sender.tab;
if ( !tab ) { continue; }
if ( tab.id === tabId ) {
this.onPortDisconnect(port);
}
}
});
}
},
broadcast: function(message) {
const messageWrapper = { broadcast: true, msg: message };
for ( const { port } of this.ports.values() ) {
try {
port.postMessage(messageWrapper);
} catch(ex) {
this.ports.delete(port.name);
}
// Mark for reuse
this.port = this.request = null;
callbackWrapperJunkyard.push(this);
}
};
},
var callbackWrapperJunkyard = [];
var callbackWrapperFactory = function(port, request) {
var wrapper = callbackWrapperJunkyard.pop();
if ( wrapper ) {
return wrapper.init(port, request);
}
return new CallbackWrapper(port, request);
};
var toFramework = function(request, port, callback) {
var sender = port && port.sender;
onFrameworkMessage: function(request, port, callback) {
const sender = port && port.sender;
if ( !sender ) { return; }
var tabId = sender.tab && sender.tab.id || undefined;
var msg = request.msg,
toPort;
const tabId = sender.tab && sender.tab.id || undefined;
const msg = request.msg;
switch ( msg.what ) {
case 'connectionAccepted':
case 'connectionRefused':
toPort = messaging.ports.get(msg.fromToken);
case 'connectionRefused': {
const { port: toPort } = this.ports.get(msg.fromToken);
if ( toPort !== undefined ) {
msg.tabId = tabId;
toPort.postMessage(request);
@ -880,16 +904,17 @@ vAPI.messaging.onPortMessage = (function() {
port.postMessage(request);
}
break;
}
case 'connectionRequested':
msg.tabId = tabId;
for ( toPort of messaging.ports.values() ) {
for ( const { port: toPort } of this.ports.values() ) {
toPort.postMessage(request);
}
break;
case 'connectionBroken':
case 'connectionCheck':
case 'connectionMessage':
toPort = messaging.ports.get(
case 'connectionMessage': {
const { port: toPort } = this.ports.get(
port.name === msg.fromToken ? msg.toToken : msg.fromToken
);
if ( toPort !== undefined ) {
@ -900,9 +925,10 @@ vAPI.messaging.onPortMessage = (function() {
port.postMessage(request);
}
break;
}
case 'userCSS':
if ( tabId === undefined ) { break; }
var details = {
const details = {
code: undefined,
frameId: sender.frameId,
matchAboutBlank: true
@ -913,25 +939,24 @@ vAPI.messaging.onPortMessage = (function() {
if ( msg.add ) {
details.runAt = 'document_start';
}
var cssText;
var countdown = 0;
var countdownHandler = function() {
let countdown = 0;
const countdownHandler = function() {
void chrome.runtime.lastError;
countdown -= 1;
if ( countdown === 0 && typeof callback === 'function' ) {
callback();
}
};
for ( cssText of msg.add ) {
for ( const cssText of msg.add ) {
countdown += 1;
details.code = cssText;
chrome.tabs.insertCSS(tabId, details, countdownHandler);
browser.tabs.insertCSS(tabId, details, countdownHandler);
}
if ( typeof chrome.tabs.removeCSS === 'function' ) {
for ( cssText of msg.remove ) {
for ( const cssText of msg.remove ) {
countdown += 1;
details.code = cssText;
chrome.tabs.removeCSS(tabId, details, countdownHandler);
browser.tabs.removeCSS(tabId, details, countdownHandler);
}
}
if ( countdown === 0 && typeof callback === 'function' ) {
@ -939,100 +964,87 @@ vAPI.messaging.onPortMessage = (function() {
}
break;
}
};
},
// https://bugzilla.mozilla.org/show_bug.cgi?id=1392067
// Workaround: manually remove ports matching removed tab.
chrome.tabs.onRemoved.addListener(function(tabId) {
for ( var port of messaging.ports.values() ) {
var tab = port.sender && port.sender.tab;
if ( !tab ) { continue; }
if ( tab.id === tabId ) {
vAPI.messaging.onPortDisconnect(port);
}
// Use a wrapper to avoid closure and to allow reuse.
CallbackWrapper: class {
constructor(messaging, port, request) {
this.messaging = messaging;
this.callback = this.proxy.bind(this); // bind once
this.init(port, request);
}
});
init(port, request) {
this.port = port;
this.request = request;
return this;
}
proxy(response) {
// https://github.com/chrisaljoudi/uBlock/issues/383
if ( this.messaging.ports.has(this.port.name) ) {
this.port.postMessage({
auxProcessId: this.request.auxProcessId,
channelName: this.request.channelName,
msg: response !== undefined ? response : null
});
}
// Store for reuse
this.port = this.request = null;
this.messaging.callbackWrapperJunkyard.push(this);
}
},
return function(request, port) {
callbackWrapperJunkyard: [],
callbackWrapperFactory: function(port, request) {
return this.callbackWrapperJunkyard.length !== 0
? this.callbackWrapperJunkyard.pop().init(port, request)
: new this.CallbackWrapper(this, port, request);
},
onPortMessage: function(request, port) {
// prepare response
var callback = this.NOOPFUNC;
let callback = this.NOOPFUNC;
if ( request.auxProcessId !== undefined ) {
callback = callbackWrapperFactory(port, request).callback;
callback = this.callbackWrapperFactory(port, request).callback;
}
// Content process to main process: framework handler.
if ( request.channelName === 'vapi' ) {
toFramework(request, port, callback);
this.onFrameworkMessage(request, port, callback);
return;
}
// Auxiliary process to main process: specific handler
var r = this.UNHANDLED,
listener = this.listeners[request.channelName];
if ( typeof listener === 'function' ) {
r = listener(request.msg, port.sender, callback);
const fromDetails = this.ports.get(port.name);
if ( fromDetails === undefined ) { return; }
const listenerDetails = this.listeners.get(request.channelName);
let r = this.UNHANDLED;
if (
(listenerDetails !== undefined) &&
(listenerDetails.privileged === false || fromDetails.privileged)
) {
r = listenerDetails.fn(request.msg, port.sender, callback);
}
if ( r !== this.UNHANDLED ) { return; }
// Auxiliary process to main process: default handler
r = this.defaultHandler(request.msg, port.sender, callback);
if ( r !== this.UNHANDLED ) { return; }
if ( fromDetails.privileged ) {
r = this.defaultHandler(request.msg, port.sender, callback);
if ( r !== this.UNHANDLED ) { return; }
}
// Auxiliary process to main process: no handler
console.error(
'vAPI.messaging.onPortMessage > unhandled request: %o',
log.info(
`vAPI.messaging.onPortMessage > unhandled request: ${JSON.stringify(request.msg)}`,
request
);
// Need to callback anyways in case caller expected an answer, or
// else there is a memory leak on caller's side
callback();
}.bind(vAPI.messaging);
})();
/******************************************************************************/
vAPI.messaging.onPortDisconnect = function(port) {
port.onDisconnect.removeListener(this.onPortDisconnect);
port.onMessage.removeListener(this.onPortMessage);
this.ports.delete(port.name);
}.bind(vAPI.messaging);
/******************************************************************************/
vAPI.messaging.onPortConnect = function(port) {
port.onDisconnect.addListener(this.onPortDisconnect);
port.onMessage.addListener(this.onPortMessage);
this.ports.set(port.name, port);
}.bind(vAPI.messaging);
/******************************************************************************/
vAPI.messaging.setup = function(defaultHandler) {
// Already setup?
if ( this.defaultHandler !== null ) {
return;
}
if ( typeof defaultHandler !== 'function' ) {
defaultHandler = function(){ return vAPI.messaging.UNHANDLED; };
}
this.defaultHandler = defaultHandler;
chrome.runtime.onConnect.addListener(this.onPortConnect);
};
/******************************************************************************/
vAPI.messaging.broadcast = function(message) {
const messageWrapper = { broadcast: true, msg: message };
for ( const port of this.ports.values() ) {
try {
port.postMessage(messageWrapper);
} catch(ex) {
this.ports.delete(port.name);
}
}
},
};
/******************************************************************************/
@ -1049,8 +1061,7 @@ vAPI.messaging.broadcast = function(message) {
vAPI.warSecret = (( ) => {
const generateSecret = ( ) => {
return Math.floor(Math.random() * 982451653 + 982451653).toString(36) +
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
return Math.floor(Math.random() * 982451653 + 982451653).toString(36);
};
const root = vAPI.getURL('/');

View File

@ -43,7 +43,7 @@ vAPI.webextFlavor = {
soup: new Set()
};
(function() {
(( ) => {
const ua = navigator.userAgent;
const flavor = vAPI.webextFlavor;
const soup = flavor.soup;

View File

@ -750,8 +750,8 @@ FilterContainer.prototype.addToSelectorCache = function(details) {
/******************************************************************************/
FilterContainer.prototype.removeFromSelectorCache = function(
targetHostname,
type
targetHostname = '*',
type = undefined
) {
let targetHostnameLength = targetHostname.length;
for ( let entry of this.selectorCache ) {

View File

@ -24,16 +24,23 @@
'use strict';
// Default handler
(function() {
// https://github.com/uBlockOrigin/uBlock-issues/issues/710
// Listeners have a name and a "privileged" status.
// The nameless default handler is always deemed "privileged".
// Messages from privileged ports must never relayed to listeners
// which are not privileged.
/******************************************************************************/
/******************************************************************************/
// Default handler
// priviledged
{
// >>>>> start of local scope
const µb = µBlock;
/******************************************************************************/
const getDomainNames = function(targets) {
const µburi = µb.URI;
return targets.map(target => {
@ -44,8 +51,6 @@ const getDomainNames = function(targets) {
});
};
/******************************************************************************/
const onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
@ -82,8 +87,6 @@ const onMessage = function(request, sender, callback) {
break;
}
const tabId = sender && sender.tab ? sender.tab.id : 0;
// Sync
var response;
@ -93,17 +96,13 @@ const onMessage = function(request, sender, callback) {
break;
case 'compileCosmeticFilterSelector':
response = µb.staticExtFilteringEngine.compileSelector(request.selector);
break;
case 'cosmeticFiltersInjected':
µb.cosmeticFilteringEngine.addToSelectorCache(request);
response = µb.staticExtFilteringEngine.compileSelector(
request.selector
);
break;
case 'createUserFilter':
µb.appendUserFilters(request.filters, request);
// https://github.com/gorhill/uBlock/issues/1786
µb.cosmeticFilteringEngine.removeFromSelectorCache(request.pageDomain);
µb.createUserFilters(request);
break;
case 'forceUpdateAssets':
@ -143,13 +142,6 @@ const onMessage = function(request, sender, callback) {
µb.openNewTab(request.details);
break;
case 'mouseClick':
µb.mouseEventRegister.tabId = tabId;
µb.mouseEventRegister.x = request.x;
µb.mouseEventRegister.y = request.y;
µb.mouseEventRegister.url = request.url;
break;
case 'reloadTab':
if ( vAPI.isBehindTheSceneTabId(request.tabId) === false ) {
vAPI.tabs.reload(request.tabId, request.bypassCache === true);
@ -159,10 +151,6 @@ const onMessage = function(request, sender, callback) {
}
break;
case 'scriptletResponse':
µb.scriptlets.report(tabId, request.scriptlet, request.response);
break;
case 'setWhitelist':
µb.netWhitelist = µb.whitelistFromString(request.whitelist);
µb.saveWhitelist();
@ -185,51 +173,43 @@ const onMessage = function(request, sender, callback) {
vAPI.messaging.setup(onMessage);
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: popupPanel
// Channel:
// popupPanel
// privileged
(function() {
{
// >>>>> start of local scope
/******************************************************************************/
const µb = µBlock;
var µb = µBlock;
/******************************************************************************/
var getHostnameDict = function(hostnameToCountMap) {
var r = Object.create(null),
domainEntry,
domainFromHostname = µb.URI.domainFromHostname,
domain, blockCount, allowCount,
hostname, counts;
const getHostnameDict = function(hostnameToCountMap) {
const r = Object.create(null);
const domainFromHostname = µb.URI.domainFromHostname;
// Note: destructuring assignment not supported before Chromium 49.
for ( var entry of hostnameToCountMap ) {
hostname = entry[0];
for ( const [ hostname, hnCounts ] of hostnameToCountMap ) {
if ( r[hostname] !== undefined ) { continue; }
domain = domainFromHostname(hostname) || hostname;
counts = hostnameToCountMap.get(domain) || 0;
blockCount = counts & 0xFFFF;
allowCount = counts >>> 16 & 0xFFFF;
const domain = domainFromHostname(hostname) || hostname;
const dnCounts = hostnameToCountMap.get(domain) || 0;
let blockCount = dnCounts & 0xFFFF;
let allowCount = dnCounts >>> 16 & 0xFFFF;
if ( r[domain] === undefined ) {
domainEntry = r[domain] = {
r[domain] = {
domain: domain,
blockCount: blockCount,
allowCount: allowCount,
totalBlockCount: blockCount,
totalAllowCount: allowCount
};
} else {
domainEntry = r[domain];
}
counts = entry[1];
blockCount = counts & 0xFFFF;
allowCount = counts >>> 16 & 0xFFFF;
const domainEntry = r[domain];
blockCount = hnCounts & 0xFFFF;
allowCount = hnCounts >>> 16 & 0xFFFF;
domainEntry.totalBlockCount += blockCount;
domainEntry.totalAllowCount += allowCount;
if ( hostname === domain ) { continue; }
@ -244,9 +224,7 @@ var getHostnameDict = function(hostnameToCountMap) {
return r;
};
/******************************************************************************/
var getFirewallRules = function(srcHostname, desHostnames) {
const getFirewallRules = function(srcHostname, desHostnames) {
var r = {};
var df = µb.sessionFirewall;
r['/ * *'] = df.lookupRuleData('*', '*', '*');
@ -256,32 +234,38 @@ var getFirewallRules = function(srcHostname, desHostnames) {
r['/ * 1p-script'] = df.lookupRuleData('*', '*', '1p-script');
r['/ * 3p-script'] = df.lookupRuleData('*', '*', '3p-script');
r['/ * 3p-frame'] = df.lookupRuleData('*', '*', '3p-frame');
if ( typeof srcHostname !== 'string' ) {
return r;
}
if ( typeof srcHostname !== 'string' ) { return r; }
r['. * *'] = df.lookupRuleData(srcHostname, '*', '*');
r['. * image'] = df.lookupRuleData(srcHostname, '*', 'image');
r['. * 3p'] = df.lookupRuleData(srcHostname, '*', '3p');
r['. * inline-script'] = df.lookupRuleData(srcHostname, '*', 'inline-script');
r['. * inline-script'] = df.lookupRuleData(srcHostname,
'*',
'inline-script'
);
r['. * 1p-script'] = df.lookupRuleData(srcHostname, '*', '1p-script');
r['. * 3p-script'] = df.lookupRuleData(srcHostname, '*', '3p-script');
r['. * 3p-frame'] = df.lookupRuleData(srcHostname, '*', '3p-frame');
for ( var desHostname in desHostnames ) {
r['/ ' + desHostname + ' *'] = df.lookupRuleData('*', desHostname, '*');
r['. ' + desHostname + ' *'] = df.lookupRuleData(srcHostname, desHostname, '*');
for ( const desHostname in desHostnames ) {
r[`/ ${desHostname} *`] = df.lookupRuleData(
'*',
desHostname,
'*'
);
r[`. ${desHostname} *`] = df.lookupRuleData(
srcHostname,
desHostname,
'*'
);
}
return r;
};
/******************************************************************************/
var popupDataFromTabId = function(tabId, tabTitle) {
let tabContext = µb.tabContextManager.mustLookup(tabId),
rootHostname = tabContext.rootHostname;
let r = {
const popupDataFromTabId = function(tabId, tabTitle) {
const tabContext = µb.tabContextManager.mustLookup(tabId);
const rootHostname = tabContext.rootHostname;
const r = {
advancedUserEnabled: µb.userSettings.advancedUserEnabled,
appName: vAPI.app.name,
appVersion: vAPI.app.version,
@ -305,13 +289,13 @@ var popupDataFromTabId = function(tabId, tabTitle) {
tooltipsDisabled: µb.userSettings.tooltipsDisabled
};
let pageStore = µb.pageStoreFromTabId(tabId);
const pageStore = µb.pageStoreFromTabId(tabId);
if ( pageStore ) {
// https://github.com/gorhill/uBlock/issues/2105
// Be sure to always include the current page's hostname -- it might
// not be present when the page itself is pulled from the browser's
// short-term memory cache. This needs to be done before calling
// getHostnameDict().
// Be sure to always include the current page's hostname -- it
// might not be present when the page itself is pulled from the
// browser's short-term memory cache. This needs to be done
// before calling getHostnameDict().
if (
pageStore.hostnameToCountMap.has(rootHostname) === false &&
µb.URI.isNetworkURI(tabContext.rawURL)
@ -325,14 +309,29 @@ var popupDataFromTabId = function(tabId, tabTitle) {
r.contentLastModified = pageStore.contentLastModified;
r.firewallRules = getFirewallRules(rootHostname, r.hostnameDict);
r.canElementPicker = µb.URI.isNetworkURI(r.rawURL);
r.noPopups = µb.sessionSwitches.evaluateZ('no-popups', rootHostname);
r.noPopups = µb.sessionSwitches.evaluateZ(
'no-popups',
rootHostname
);
r.popupBlockedCount = pageStore.popupBlockedCount;
r.noCosmeticFiltering = µb.sessionSwitches.evaluateZ('no-cosmetic-filtering', rootHostname);
r.noLargeMedia = µb.sessionSwitches.evaluateZ('no-large-media', rootHostname);
r.noCosmeticFiltering = µb.sessionSwitches.evaluateZ(
'no-cosmetic-filtering',
rootHostname
);
r.noLargeMedia = µb.sessionSwitches.evaluateZ(
'no-large-media',
rootHostname
);
r.largeMediaCount = pageStore.largeMediaCount;
r.noRemoteFonts = µb.sessionSwitches.evaluateZ('no-remote-fonts', rootHostname);
r.noRemoteFonts = µb.sessionSwitches.evaluateZ(
'no-remote-fonts',
rootHostname
);
r.remoteFontCount = pageStore.remoteFontCount;
r.noScripting = µb.sessionSwitches.evaluateZ('no-scripting', rootHostname);
r.noScripting = µb.sessionSwitches.evaluateZ(
'no-scripting',
rootHostname
);
} else {
r.hostnameDict = {};
r.firewallRules = getFirewallRules();
@ -352,9 +351,7 @@ var popupDataFromTabId = function(tabId, tabTitle) {
return r;
};
/******************************************************************************/
var popupDataFromRequest = function(request, callback) {
const popupDataFromRequest = function(request, callback) {
if ( request.tabId ) {
callback(popupDataFromTabId(request.tabId, ''));
return;
@ -372,10 +369,8 @@ var popupDataFromRequest = function(request, callback) {
});
};
/******************************************************************************/
var onMessage = function(request, sender, callback) {
var pageStore;
const onMessage = function(request, sender, callback) {
let pageStore;
// Async
switch ( request.what ) {
@ -388,7 +383,7 @@ var onMessage = function(request, sender, callback) {
}
// Sync
var response;
let response;
switch ( request.what ) {
case 'getPopupLazyData':
@ -462,7 +457,11 @@ var onMessage = function(request, sender, callback) {
case 'toggleNetFiltering':
pageStore = µb.pageStoreFromTabId(request.tabId);
if ( pageStore ) {
pageStore.toggleNetFilteringSwitch(request.url, request.scope, request.state);
pageStore.toggleNetFilteringSwitch(
request.url,
request.scope,
request.state
);
µb.updateToolbarIcon(request.tabId, 0b111);
}
break;
@ -474,22 +473,28 @@ var onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('popupPanel', onMessage);
vAPI.messaging.listen({
name: 'popupPanel',
listener: onMessage,
privileged: true,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: contentscript
// Channel:
// contentscript
// unprivileged
(function() {
{
// >>>>> start of local scope
/******************************************************************************/
const µb = µBlock;
var onMessage = function(request, sender, callback) {
const onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
default:
@ -497,7 +502,6 @@ var onMessage = function(request, sender, callback) {
}
// Sync
const µb = µBlock;
let response,
tabId, frameId,
pageStore = null;
@ -509,6 +513,10 @@ var onMessage = function(request, sender, callback) {
}
switch ( request.what ) {
case 'cosmeticFiltersInjected':
µb.cosmeticFilteringEngine.addToSelectorCache(request);
break;
case 'getCollapsibleBlockedRequests':
response = {
id: request.id,
@ -525,6 +533,13 @@ var onMessage = function(request, sender, callback) {
}
break;
case 'mouseClick':
µb.mouseEventRegister.tabId = tabId;
µb.mouseEventRegister.x = request.x;
µb.mouseEventRegister.y = request.y;
µb.mouseEventRegister.url = request.url;
break;
case 'shouldRenderNoscriptTags':
if ( pageStore === null ) { break; }
const fctxt = µb.filteringContext.fromTabId(tabId);
@ -604,20 +619,23 @@ var onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('contentscript', onMessage);
vAPI.messaging.listen({
name: 'contentscript',
listener: onMessage,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: elementPicker
// Channel:
// elementPicker
// unprivileged
(function() {
/******************************************************************************/
{
// >>>>> start of local scope
const onMessage = function(request, sender, callback) {
const µb = µBlock;
@ -669,6 +687,12 @@ const onMessage = function(request, sender, callback) {
let response;
switch ( request.what ) {
// https://github.com/gorhill/uBlock/issues/3497
// This needs to be removed once issue is fixed.
case 'createUserFilter':
µb.createUserFilters(request);
break;
case 'elementPickerEprom':
µb.epickerEprom = request;
break;
@ -680,22 +704,25 @@ const onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('elementPicker', onMessage);
vAPI.messaging.listen({
name: 'elementPicker',
listener: onMessage,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: cloudWidget
// Channel:
// cloudWidget
// privileged
(function() {
{
// >>>>> start of local scope
/******************************************************************************/
var onMessage = function(request, sender, callback) {
const onMessage = function(request, sender, callback) {
// Cloud storage support is optional.
if ( µBlock.cloudStorageSupported !== true ) {
callback();
@ -726,7 +753,7 @@ var onMessage = function(request, sender, callback) {
}
// Sync
var response;
let response;
switch ( request.what ) {
// For when cloud storage is disabled.
@ -742,27 +769,28 @@ var onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('cloudWidget', onMessage);
vAPI.messaging.listen({
name: 'cloudWidget',
listener: onMessage,
privileged: true,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: dashboard
// Channel:
// dashboard
// privileged
(function() {
/******************************************************************************/
{
// >>>>> start of local scope
const µb = µBlock;
/******************************************************************************/
// Settings
const getLocalData = function(callback) {
const onStorageInfoReady = function(bytesInUse) {
const o = µb.restoreBackupSettings;
@ -874,7 +902,6 @@ const restoreUserData = function(request) {
// Remove all stored data but keep global counts, people can become
// quite attached to numbers
const resetUserData = function() {
let count = 3;
const countdown = ( ) => {
@ -889,10 +916,7 @@ const resetUserData = function() {
vAPI.localStorage.removeItem('immediateHiddenSettings');
};
/******************************************************************************/
// 3rd-party filters
const prepListEntries = function(entries) {
const µburi = µb.URI;
for ( const k in entries ) {
@ -935,10 +959,7 @@ const getLists = function(callback) {
µb.getAvailableLists(onLists);
};
/******************************************************************************/
// My rules
const getRules = function() {
return {
permanentRules:
@ -1001,10 +1022,7 @@ const modifyRuleset = function(details) {
}
};
/******************************************************************************/
// Shortcuts pane
const getShortcuts = function(callback) {
if ( µb.canUseShortcuts === false ) {
return callback([]);
@ -1038,8 +1056,6 @@ const setShortcut = function(details) {
vAPI.storage.set({ commandShortcuts: Array.from(µb.commandShortcuts) });
};
/******************************************************************************/
const onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
@ -1124,26 +1140,28 @@ const onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('dashboard', onMessage);
vAPI.messaging.listen({
name: 'dashboard',
listener: onMessage,
privileged: true,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: loggerUI
// Channel:
// loggerUI
// privileged
(function() {
/******************************************************************************/
{
// >>>>> start of local scope
const µb = µBlock;
const extensionOriginURL = vAPI.getURL('');
/******************************************************************************/
const getLoggerData = function(details, activeTabId, callback) {
const response = {
colorBlind: µb.userSettings.colorBlindFriendly,
@ -1195,8 +1213,6 @@ const getLoggerData = function(details, activeTabId, callback) {
callback(response);
};
/******************************************************************************/
const getURLFilteringData = function(details) {
const colors = {};
const response = {
@ -1229,8 +1245,6 @@ const getURLFilteringData = function(details) {
return response;
};
/******************************************************************************/
const onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
@ -1288,20 +1302,24 @@ const onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('loggerUI', onMessage);
vAPI.messaging.listen({
name: 'loggerUI',
listener: onMessage,
privileged: true,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: documentBlocked
// Channel:
// documentBlocked
// privileged
(( ) => {
/******************************************************************************/
{
// >>>>> start of local scope
const onMessage = function(request, sender, callback) {
const tabId = sender && sender.tab ? sender.tab.id : 0;
@ -1331,26 +1349,28 @@ const onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('documentBlocked', onMessage);
vAPI.messaging.listen({
name: 'documentBlocked',
listener: onMessage,
privileged: true,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/
/******************************************************************************/
// channel: scriptlets
// Channel:
// scriptlets
// unprivileged
(function() {
/******************************************************************************/
{
// >>>>> start of local scope
const µb = µBlock;
const broadcastTimers = new Map();
/******************************************************************************/
const domSurveyFinalReport = function(tabId) {
broadcastTimers.delete(tabId + '-domSurveyReport');
@ -1365,8 +1385,6 @@ const domSurveyFinalReport = function(tabId) {
});
};
/******************************************************************************/
const logCosmeticFilters = function(tabId, details) {
if ( µb.logger.enabled === false ) { return; }
@ -1384,8 +1402,6 @@ const logCosmeticFilters = function(tabId, details) {
}
};
/******************************************************************************/
const logCSPViolations = function(pageStore, request) {
if ( µb.logger.enabled === false || pageStore === null ) {
return false;
@ -1475,8 +1491,6 @@ logCSPViolations.policyDirectiveToTypeMap = new Map([
[ 'style-src-elem', 'stylesheet' ],
]);
/******************************************************************************/
const onMessage = function(request, sender, callback) {
const tabId = sender && sender.tab ? sender.tab.id : 0;
const pageStore = µb.pageStoreFromTabId(tabId);
@ -1491,6 +1505,10 @@ const onMessage = function(request, sender, callback) {
let response;
switch ( request.what ) {
case 'applyFilterListSelection':
response = µb.applyFilterListSelection(request);
break;
case 'domSurveyTransientReport':
if ( pageStore !== null ) {
if ( request.filteredElementCount ) {
@ -1499,11 +1517,11 @@ const onMessage = function(request, sender, callback) {
if ( request.scriptCount ) {
pageStore.scriptCount += request.scriptCount;
}
let broadcastKey = tabId + '-domSurveyReport';
const broadcastKey = `${tabId}-domSurveyReport`;
if ( broadcastTimers.has(broadcastKey) === false ) {
broadcastTimers.set(broadcastKey, vAPI.setTimeout(
( ) => { domSurveyFinalReport(tabId); },
53
103
));
}
}
@ -1526,6 +1544,10 @@ const onMessage = function(request, sender, callback) {
logCosmeticFilters(tabId, request);
break;
case 'reloadAllFilters':
µb.loadFilterLists();
return;
case 'securityPolicyViolation':
response = logCSPViolations(pageStore, request);
break;
@ -1549,11 +1571,13 @@ const onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('scriptlets', onMessage);
vAPI.messaging.listen({
name: 'scriptlets',
listener: onMessage,
});
/******************************************************************************/
})();
// <<<<< end of local scope
}
/******************************************************************************/

View File

@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2015-2018 Raymond Hill
Copyright (C) 2015-present Raymond Hill
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,7 +23,7 @@
/******************************************************************************/
(function() {
(( ) => {
if ( typeof vAPI !== 'object' ) { return; }
// https://github.com/gorhill/httpswitchboard/issues/25
@ -47,7 +47,7 @@
inlineScriptCount = 1;
}
let scriptTags = document.querySelectorAll('script[src]');
const scriptTags = document.querySelectorAll('script[src]');
let filteredElementCount = 0;
if ( vAPI.domFilterer ) {
@ -58,7 +58,6 @@
'scriptlets',
{
what: 'domSurveyTransientReport',
pageURL: window.location.href,
filteredElementCount: filteredElementCount,
scriptCount: inlineScriptCount + scriptTags.length,
}

View File

@ -422,8 +422,6 @@
return this.assets.get(this.userFiltersPath, callback);
};
/******************************************************************************/
µBlock.appendUserFilters = function(filters, options) {
filters = filters.trim();
if ( filters.length === 0 ) { return; }
@ -500,6 +498,12 @@
this.loadUserFilters(onLoaded);
};
µBlock.createUserFilters = function(details) {
this.appendUserFilters(details.filters, details);
// https://github.com/gorhill/uBlock/issues/1786
this.cosmeticFilteringEngine.removeFromSelectorCache(details.pageDomain);
};
/******************************************************************************/
µBlock.autoSelectRegionalFilterLists = function(lists) {