Add keyboard support for toggling down blocking profile

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

By default, no specific keyboard shortcut is predefined,
this will have to be assigned by the user. The command
name in English is "Toggle blocking profile".

The default behavior is to toggle down according to one
of the following scenarios.

a) If script execution is disabled through the no-scripting
switch, the no-scripting switch will be locally toggled
so as to allow script execution. The page will be
automatically reloaded.

b) If script execution is not blocked but the 3rd-party
script and/or frame cells are blocked, local no-op rules
will be set so as to no longer block 3rd-party scripts
and/or frames. The page will be automatically reloaded.

Given this, it may take more than one toggle down command
to reach the lowest blocking profile, which is one where
JavaScript execution is not blocked and 3rd-party scripts
and frames resources block rules, if any, are bypassed
with local no-op rules.

TODO: At this point, I haven't yet decided whether
toggling from the lowest profile should restore the
original highest blocking profile.
This commit is contained in:
Raymond Hill 2019-06-26 07:47:14 -04:00
parent d1df2b5e73
commit 693687fd74
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
6 changed files with 190 additions and 40 deletions

View File

@ -20,6 +20,9 @@
},
"launch-logger": {
"description": "__MSG_popupTipLog__"
},
"toggle-blocking-profile": {
"description": "__MSG_toggleBlockingProfile__"
}
},
"content_scripts": [

View File

@ -607,7 +607,7 @@ vAPI.tabs.remove = function(tabId) {
/******************************************************************************/
vAPI.tabs.reload = function(tabId, bypassCache) {
vAPI.tabs.reload = function(tabId, bypassCache = false) {
tabId = toChromiumTabId(tabId);
if ( tabId === 0 ) { return; }

View File

@ -963,6 +963,10 @@
"message":"Copy to clipboard",
"description":"Label for buttons used to copy something to the clipboard"
},
"toggleBlockingProfile":{
"message":"Toggle blocking profile",
"description":"Label for keyboard shortcut used to toggle blocking profile"
},
"dummy":{
"message":"This entry must be the last one",
"description":"so we dont need to deal with comma for last entry"

View File

@ -42,6 +42,7 @@ const µBlock = (function() { // jshint ignore:line
autoUpdateAssetFetchPeriod: 120,
autoUpdateDelayAfterLaunch: 180,
autoUpdatePeriod: 7,
blockingProfiles: '11111 11101 00001',
cacheStorageAPI: 'unset',
cacheStorageCompression: true,
cacheControlForFirefox1376932: 'no-cache, no-store, must-revalidate',

View File

@ -26,43 +26,160 @@
/******************************************************************************/
µBlock.canUseShortcuts = vAPI.commands instanceof Object;
µBlock.canUpdateShortcuts = µBlock.canUseShortcuts &&
typeof vAPI.commands.update === 'function';
/******************************************************************************/
(function() {
if ( µBlock.canUseShortcuts === false ) { return; }
(( ) => {
vAPI.commands.onCommand.addListener(function(command) {
var µb = µBlock;
// *****************************************************************************
// start of local namespace
switch ( command ) {
case 'launch-element-zapper':
case 'launch-element-picker':
vAPI.tabs.get(null, function(tab) {
if ( tab instanceof Object === false ) { return; }
µb.mouseEventRegister.x = µb.mouseEventRegister.y = -1;
µb.elementPickerExec(tab.id, undefined, command === 'launch-element-zapper');
});
break;
case 'launch-logger':
vAPI.tabs.get(null, function(tab) {
let hash = tab.url.startsWith(vAPI.getURL('')) ?
'' :
'#_+' + tab.id;
µb.openNewTab({
url: 'logger-ui.html' + hash,
select: true,
index: -1
});
});
break;
default:
if ( µBlock.canUseShortcuts === false ) { return; }
const toggleBlockingProfile = function(tab) {
if (
tab instanceof Object === false ||
tab.id <= 0
) {
return;
}
const µb = µBlock;
const normalURL = µb.normalizePageURL(tab.id, tab.url);
if ( µb.getNetFilteringSwitch(normalURL) === false ) { return; }
const hn = µb.URI.hostnameFromURI(normalURL);
// Construct current blocking profile
const ssw = µb.sessionSwitches;
const sfw = µb.sessionFirewall;
let currentProfile = 0;
if ( ssw.evaluateZ('no-scripting', hn) ) {
currentProfile |= 0b00000010;
}
if ( µb.userSettings.advancedUserEnabled ) {
if ( sfw.evaluateCellZY(hn, '*', '3p') === 1 ) {
currentProfile |= 0b00000100;
}
if ( sfw.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
currentProfile |= 0b00001000;
}
if ( sfw.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
currentProfile |= 0b00010000;
}
}
const profiles = [];
for ( const s of µb.hiddenSettings.blockingProfiles.split(/\s+/) ) {
const v = parseInt(s, 2);
if ( isNaN(v) ) { continue; }
profiles.push(v);
}
let newProfile;
for ( const profile of profiles ) {
if ( (currentProfile & profile & 0b11111110) !== currentProfile ) {
newProfile = profile;
break;
}
});
}
// TODO: Reset to original blocking profile?
if ( newProfile === undefined ) { return; }
if (
(currentProfile & 0b00000010) !== 0 &&
(newProfile & 0b00000010) === 0
) {
µb.toggleHostnameSwitch({
name: 'no-scripting',
hostname: hn,
state: false,
});
}
if ( µb.userSettings.advancedUserEnabled ) {
if (
(currentProfile & 0b00000100) !== 0 &&
(newProfile & 0b00000100) === 0
) {
µb.toggleFirewallRule({
srcHostname: hn,
desHostname: '*',
requestType: '3p',
action: 3,
});
}
if (
(currentProfile & 0b00001000) !== 0 &&
(newProfile & 0b00001000) === 0
) {
µb.toggleFirewallRule({
srcHostname: hn,
desHostname: '*',
requestType: '3p-script',
action: 3,
});
}
if (
(currentProfile & 0b00010000) !== 0 &&
(newProfile & 0b00010000) === 0
) {
µb.toggleFirewallRule({
srcHostname: hn,
desHostname: '*',
requestType: '3p-frame',
action: 3,
});
}
}
if ( newProfile & 0b00000001 ) {
vAPI.tabs.reload(tab.id);
}
};
vAPI.commands.onCommand.addListener(command => {
const µb = µBlock;
switch ( command ) {
case 'launch-element-picker':
case 'launch-element-zapper':
vAPI.tabs.get(null, tab => {
if ( tab instanceof Object === false ) { return; }
µb.mouseEventRegister.x = µb.mouseEventRegister.y = -1;
µb.elementPickerExec(
tab.id,
undefined,
command === 'launch-element-zapper'
);
});
break;
case 'launch-logger':
vAPI.tabs.get(null, tab => {
const hash = tab.url.startsWith(vAPI.getURL(''))
? ''
: `#_+${tab.id}`;
µb.openNewTab({
url: `logger-ui.html${hash}`,
select: true,
index: -1
});
});
break;
case 'toggle-blocking-profile':
vAPI.tabs.get(null, toggleBlockingProfile);
break;
default:
break;
}
});
// end of local namespace
// *****************************************************************************
})();
/******************************************************************************/

View File

@ -24,11 +24,11 @@
/******************************************************************************/
/******************************************************************************/
{
// *****************************************************************************
// start of local namespace
{
// https://github.com/chrisaljoudi/uBlock/issues/405
// Be more flexible with whitelist syntax
@ -451,20 +451,39 @@ const matchBucket = function(url, hostname, bucket, start) {
// (but not really) redundant rules led to this issue.
µBlock.toggleFirewallRule = function(details) {
let requestType = details.requestType;
let { srcHostname, desHostname, requestType, action } = details;
if ( details.action !== 0 ) {
this.sessionFirewall.setCell(details.srcHostname, details.desHostname, requestType, details.action);
if ( action !== 0 ) {
this.sessionFirewall.setCell(
srcHostname,
desHostname,
requestType,
action
);
} else {
this.sessionFirewall.unsetCell(details.srcHostname, details.desHostname, requestType);
this.sessionFirewall.unsetCell(
srcHostname,
desHostname,
requestType
);
}
// https://github.com/chrisaljoudi/uBlock/issues/731#issuecomment-73937469
if ( details.persist ) {
if ( details.action !== 0 ) {
this.permanentFirewall.setCell(details.srcHostname, details.desHostname, requestType, details.action);
if ( action !== 0 ) {
this.permanentFirewall.setCell(
srcHostname,
desHostname,
requestType,
action
);
} else {
this.permanentFirewall.unsetCell(details.srcHostname, details.desHostname, requestType, details.action);
this.permanentFirewall.unsetCell(
srcHostname,
desHostname,
requestType,
action
);
}
this.savePermanentFirewallRules();
}
@ -473,10 +492,14 @@ const matchBucket = function(url, hostname, bucket, start) {
// Flush all cached `net` cosmetic filters if we are dealing with a
// collapsible type: any of the cached entries could be a resource on the
// target page.
let srcHostname = details.srcHostname;
if (
(srcHostname !== '*') &&
(requestType === '*' || requestType === 'image' || requestType === '3p' || requestType === '3p-frame')
(
requestType === '*' ||
requestType === 'image' ||
requestType === '3p' ||
requestType === '3p-frame'
)
) {
srcHostname = '*';
}
@ -635,3 +658,5 @@ const matchBucket = function(url, hostname, bucket, start) {
report: report
};
})();
/******************************************************************************/