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 = { vAPI.messaging = {
ports: new Map(), ports: new Map(),
listeners: {}, listeners: new Map(),
defaultHandler: null, defaultHandler: null,
PRIVILEGED_URL: vAPI.getURL(''),
NOOPFUNC: noopFunc, NOOPFUNC: noopFunc,
UNHANDLED: 'vAPI.messaging.notHandled' UNHANDLED: 'vAPI.messaging.notHandled',
};
/******************************************************************************/ listen: function(details) {
this.listeners.set(details.name, {
vAPI.messaging.listen = function(listenerName, callback) { fn: details.listener,
this.listeners[listenerName] = callback; privileged: details.privileged === true
}; });
/******************************************************************************/
vAPI.messaging.onPortMessage = (function() {
var messaging = vAPI.messaging;
// 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);
};
CallbackWrapper.prototype = {
init: function(port, request) {
this.port = port;
this.request = request;
return this;
}, },
proxy: function(response) {
// https://github.com/chrisaljoudi/uBlock/issues/383 onPortDisconnect: function(port) {
if ( messaging.ports.has(this.port.name) ) { this.ports.delete(port.name);
this.port.postMessage({ },
auxProcessId: this.request.auxProcessId,
channelName: this.request.channelName, onPortConnect: function(port) {
msg: response !== undefined ? response : null 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)
});
},
setup: function(defaultHandler) {
if ( this.defaultHandler !== null ) { return; }
if ( typeof defaultHandler !== 'function' ) {
defaultHandler = function() {
return this.UNHANDLED;
};
}
this.defaultHandler = defaultHandler;
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);
}
}
}); });
} }
// Mark for reuse },
this.port = this.request = null;
callbackWrapperJunkyard.push(this); 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);
} }
};
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) { onFrameworkMessage: function(request, port, callback) {
var sender = port && port.sender; const sender = port && port.sender;
if ( !sender ) { return; } if ( !sender ) { return; }
var tabId = sender.tab && sender.tab.id || undefined; const tabId = sender.tab && sender.tab.id || undefined;
var msg = request.msg, const msg = request.msg;
toPort;
switch ( msg.what ) { switch ( msg.what ) {
case 'connectionAccepted': case 'connectionAccepted':
case 'connectionRefused': case 'connectionRefused': {
toPort = messaging.ports.get(msg.fromToken); const { port: toPort } = this.ports.get(msg.fromToken);
if ( toPort !== undefined ) { if ( toPort !== undefined ) {
msg.tabId = tabId; msg.tabId = tabId;
toPort.postMessage(request); toPort.postMessage(request);
@ -880,16 +904,17 @@ vAPI.messaging.onPortMessage = (function() {
port.postMessage(request); port.postMessage(request);
} }
break; break;
}
case 'connectionRequested': case 'connectionRequested':
msg.tabId = tabId; msg.tabId = tabId;
for ( toPort of messaging.ports.values() ) { for ( const { port: toPort } of this.ports.values() ) {
toPort.postMessage(request); toPort.postMessage(request);
} }
break; break;
case 'connectionBroken': case 'connectionBroken':
case 'connectionCheck': case 'connectionCheck':
case 'connectionMessage': case 'connectionMessage': {
toPort = messaging.ports.get( const { port: toPort } = this.ports.get(
port.name === msg.fromToken ? msg.toToken : msg.fromToken port.name === msg.fromToken ? msg.toToken : msg.fromToken
); );
if ( toPort !== undefined ) { if ( toPort !== undefined ) {
@ -900,9 +925,10 @@ vAPI.messaging.onPortMessage = (function() {
port.postMessage(request); port.postMessage(request);
} }
break; break;
}
case 'userCSS': case 'userCSS':
if ( tabId === undefined ) { break; } if ( tabId === undefined ) { break; }
var details = { const details = {
code: undefined, code: undefined,
frameId: sender.frameId, frameId: sender.frameId,
matchAboutBlank: true matchAboutBlank: true
@ -913,25 +939,24 @@ vAPI.messaging.onPortMessage = (function() {
if ( msg.add ) { if ( msg.add ) {
details.runAt = 'document_start'; details.runAt = 'document_start';
} }
var cssText; let countdown = 0;
var countdown = 0; const countdownHandler = function() {
var countdownHandler = function() {
void chrome.runtime.lastError; void chrome.runtime.lastError;
countdown -= 1; countdown -= 1;
if ( countdown === 0 && typeof callback === 'function' ) { if ( countdown === 0 && typeof callback === 'function' ) {
callback(); callback();
} }
}; };
for ( cssText of msg.add ) { for ( const cssText of msg.add ) {
countdown += 1; countdown += 1;
details.code = cssText; details.code = cssText;
chrome.tabs.insertCSS(tabId, details, countdownHandler); browser.tabs.insertCSS(tabId, details, countdownHandler);
} }
if ( typeof chrome.tabs.removeCSS === 'function' ) { if ( typeof chrome.tabs.removeCSS === 'function' ) {
for ( cssText of msg.remove ) { for ( const cssText of msg.remove ) {
countdown += 1; countdown += 1;
details.code = cssText; details.code = cssText;
chrome.tabs.removeCSS(tabId, details, countdownHandler); browser.tabs.removeCSS(tabId, details, countdownHandler);
} }
} }
if ( countdown === 0 && typeof callback === 'function' ) { if ( countdown === 0 && typeof callback === 'function' ) {
@ -939,100 +964,87 @@ vAPI.messaging.onPortMessage = (function() {
} }
break; break;
} }
}; },
// https://bugzilla.mozilla.org/show_bug.cgi?id=1392067 // Use a wrapper to avoid closure and to allow reuse.
// Workaround: manually remove ports matching removed tab. CallbackWrapper: class {
chrome.tabs.onRemoved.addListener(function(tabId) { constructor(messaging, port, request) {
for ( var port of messaging.ports.values() ) { this.messaging = messaging;
var tab = port.sender && port.sender.tab; this.callback = this.proxy.bind(this); // bind once
if ( !tab ) { continue; } this.init(port, request);
if ( tab.id === tabId ) {
vAPI.messaging.onPortDisconnect(port);
} }
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 // prepare response
var callback = this.NOOPFUNC; let callback = this.NOOPFUNC;
if ( request.auxProcessId !== undefined ) { if ( request.auxProcessId !== undefined ) {
callback = callbackWrapperFactory(port, request).callback; callback = this.callbackWrapperFactory(port, request).callback;
} }
// Content process to main process: framework handler. // Content process to main process: framework handler.
if ( request.channelName === 'vapi' ) { if ( request.channelName === 'vapi' ) {
toFramework(request, port, callback); this.onFrameworkMessage(request, port, callback);
return; return;
} }
// Auxiliary process to main process: specific handler // Auxiliary process to main process: specific handler
var r = this.UNHANDLED, const fromDetails = this.ports.get(port.name);
listener = this.listeners[request.channelName]; if ( fromDetails === undefined ) { return; }
if ( typeof listener === 'function' ) {
r = listener(request.msg, port.sender, callback); 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; } if ( r !== this.UNHANDLED ) { return; }
// Auxiliary process to main process: default handler // Auxiliary process to main process: default handler
if ( fromDetails.privileged ) {
r = this.defaultHandler(request.msg, port.sender, callback); r = this.defaultHandler(request.msg, port.sender, callback);
if ( r !== this.UNHANDLED ) { return; } if ( r !== this.UNHANDLED ) { return; }
}
// Auxiliary process to main process: no handler // Auxiliary process to main process: no handler
console.error( log.info(
'vAPI.messaging.onPortMessage > unhandled request: %o', `vAPI.messaging.onPortMessage > unhandled request: ${JSON.stringify(request.msg)}`,
request request
); );
// Need to callback anyways in case caller expected an answer, or // Need to callback anyways in case caller expected an answer, or
// else there is a memory leak on caller's side // else there is a memory leak on caller's side
callback(); 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 = (( ) => { vAPI.warSecret = (( ) => {
const generateSecret = ( ) => { const generateSecret = ( ) => {
return Math.floor(Math.random() * 982451653 + 982451653).toString(36) + return Math.floor(Math.random() * 982451653 + 982451653).toString(36);
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
}; };
const root = vAPI.getURL('/'); const root = vAPI.getURL('/');

View File

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

View File

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

View File

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

View File

@ -422,8 +422,6 @@
return this.assets.get(this.userFiltersPath, callback); return this.assets.get(this.userFiltersPath, callback);
}; };
/******************************************************************************/
µBlock.appendUserFilters = function(filters, options) { µBlock.appendUserFilters = function(filters, options) {
filters = filters.trim(); filters = filters.trim();
if ( filters.length === 0 ) { return; } if ( filters.length === 0 ) { return; }
@ -500,6 +498,12 @@
this.loadUserFilters(onLoaded); 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) { µBlock.autoSelectRegionalFilterLists = function(lists) {