Skip to content

Commit

Permalink
Add keyboard support for toggling down blocking profile
Browse files Browse the repository at this point in the history
Related issue:
- uBlockOrigin/uBlock-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.
  • Loading branch information
gorhill committed Jun 26, 2019
1 parent d1df2b5 commit 693687f
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 40 deletions.
3 changes: 3 additions & 0 deletions platform/chromium/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
},
"launch-logger": {
"description": "__MSG_popupTipLog__"
},
"toggle-blocking-profile": {
"description": "__MSG_toggleBlockingProfile__"
}
},
"content_scripts": [
Expand Down
2 changes: 1 addition & 1 deletion platform/chromium/vapi-background.js
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
4 changes: 4 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
171 changes: 144 additions & 27 deletions src/js/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
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;
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
});
}
}

// 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,
});
break;
default:
break;
}
});
}

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
// *****************************************************************************

})();

/******************************************************************************/
49 changes: 37 additions & 12 deletions src/js/ublock.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
/******************************************************************************/
/******************************************************************************/

{

// *****************************************************************************
// start of local namespace

{

// /~https://github.com/chrisaljoudi/uBlock/issues/405
// Be more flexible with whitelist syntax

Expand Down Expand Up @@ -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;

if ( details.action !== 0 ) {
this.sessionFirewall.setCell(details.srcHostname, details.desHostname, requestType, details.action);
let { srcHostname, desHostname, requestType, action } = details;

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();
}
Expand All @@ -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 = '*';
}
Expand Down Expand Up @@ -635,3 +658,5 @@ const matchBucket = function(url, hostname, bucket, start) {
report: report
};
})();

/******************************************************************************/

2 comments on commit 693687f

@gwarser
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see "3rd-party" is also supported. This is what I use currently along with "no-scripting" switch.

@gorhill
Copy link
Owner Author

@gorhill gorhill commented on 693687f Jun 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I forgot to mention.

By the way, just in case, I rather not have documentation for advanced setting blockingProfiles, I am still second guessing myself as to whether I should use list of keywords or bit vectors. I worry lists of keyword could be too verbose, though on the other hand they are more self-explanatory.

Please sign in to comment.