2014-06-24 00:42:43 +02:00
|
|
|
/*******************************************************************************
|
|
|
|
|
2016-05-03 14:22:48 +02:00
|
|
|
uBlock Origin - a browser extension to block requests.
|
2018-09-03 20:06:49 +02:00
|
|
|
Copyright (C) 2014-present Raymond Hill
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
|
|
|
|
|
|
|
Home: https://github.com/gorhill/uBlock
|
|
|
|
*/
|
|
|
|
|
2016-11-05 19:48:42 +01:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-12-12 23:59:47 +01:00
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/405
|
2014-12-14 14:57:00 +01:00
|
|
|
// Be more flexible with whitelist syntax
|
|
|
|
|
|
|
|
// Any special regexp char will be escaped
|
|
|
|
var whitelistDirectiveEscape = /[-\/\\^$+?.()|[\]{}]/g;
|
|
|
|
|
|
|
|
// All `*` will be expanded into `.*`
|
|
|
|
var whitelistDirectiveEscapeAsterisk = /\*/g;
|
|
|
|
|
2016-11-06 22:51:19 +01:00
|
|
|
// Remember encountered regexps for reuse.
|
|
|
|
var directiveToRegexpMap = new Map();
|
|
|
|
|
2014-12-14 14:57:00 +01:00
|
|
|
// Probably manually entered whitelist directive
|
|
|
|
var isHandcraftedWhitelistDirective = function(directive) {
|
2016-11-06 22:51:19 +01:00
|
|
|
return directive.startsWith('/') && directive.endsWith('/') ||
|
|
|
|
directive.indexOf('/') !== -1 && directive.indexOf('*') !== -1;
|
2014-12-14 23:21:59 +01:00
|
|
|
};
|
|
|
|
|
2016-11-06 22:51:19 +01:00
|
|
|
var matchDirective = function(url, hostname, directive) {
|
|
|
|
// Directive is a plain hostname.
|
2014-12-14 14:57:00 +01:00
|
|
|
if ( directive.indexOf('/') === -1 ) {
|
2015-12-15 16:40:40 +01:00
|
|
|
return hostname.endsWith(directive) &&
|
|
|
|
(hostname.length === directive.length ||
|
|
|
|
hostname.charAt(hostname.length - directive.length - 1) === '.');
|
2014-12-14 23:21:59 +01:00
|
|
|
}
|
2016-11-06 22:51:19 +01:00
|
|
|
// Match URL exactly.
|
|
|
|
if ( directive.startsWith('/') === false && directive.indexOf('*') === -1 ) {
|
2014-12-14 23:21:59 +01:00
|
|
|
return url === directive;
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
2016-11-06 22:51:19 +01:00
|
|
|
// Transpose into a regular expression.
|
|
|
|
var re = directiveToRegexpMap.get(directive);
|
|
|
|
if ( re === undefined ) {
|
|
|
|
var reStr;
|
|
|
|
if ( directive.startsWith('/') && directive.endsWith('/') ) {
|
|
|
|
reStr = directive.slice(1, -1);
|
|
|
|
} else {
|
|
|
|
reStr = directive.replace(whitelistDirectiveEscape, '\\$&')
|
|
|
|
.replace(whitelistDirectiveEscapeAsterisk, '.*');
|
|
|
|
}
|
|
|
|
re = new RegExp(reStr);
|
|
|
|
directiveToRegexpMap.set(directive, re);
|
|
|
|
}
|
2014-12-14 23:21:59 +01:00
|
|
|
return re.test(url);
|
2014-12-14 14:57:00 +01:00
|
|
|
};
|
|
|
|
|
2016-11-06 22:51:19 +01:00
|
|
|
var matchBucket = function(url, hostname, bucket, start) {
|
|
|
|
if ( bucket ) {
|
|
|
|
for ( var i = start || 0, n = bucket.length; i < n; i++ ) {
|
|
|
|
if ( matchDirective(url, hostname, bucket[i]) ) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
|
|
|
|
// https://www.youtube.com/watch?v=RL2W_XK-UJ4&list=PLhPp-QAUKF_hRMjWsYvvdazGw0qIjtSXJ
|
|
|
|
|
2014-12-14 14:57:00 +01:00
|
|
|
/******************************************************************************/
|
2014-08-02 17:40:27 +02:00
|
|
|
|
2014-12-14 14:57:00 +01:00
|
|
|
µBlock.getNetFilteringSwitch = function(url) {
|
2016-11-06 22:51:19 +01:00
|
|
|
var targetHostname = this.URI.hostnameFromURI(url),
|
|
|
|
key = targetHostname,
|
|
|
|
pos;
|
2014-12-14 14:57:00 +01:00
|
|
|
for (;;) {
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( matchBucket(url, targetHostname, this.netWhitelist[key]) !== -1 ) {
|
|
|
|
return false;
|
2014-12-14 14:57:00 +01:00
|
|
|
}
|
2014-12-14 23:21:59 +01:00
|
|
|
pos = key.indexOf('.');
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( pos === -1 ) { break; }
|
2014-12-14 23:21:59 +01:00
|
|
|
key = key.slice(pos + 1);
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( matchBucket(url, targetHostname, this.netWhitelist['//']) !== -1 ) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-08-02 17:40:27 +02:00
|
|
|
µBlock.toggleNetFilteringSwitch = function(url, scope, newState) {
|
2014-12-14 14:57:00 +01:00
|
|
|
var currentState = this.getNetFilteringSwitch(url);
|
2014-06-24 00:42:43 +02:00
|
|
|
if ( newState === undefined ) {
|
|
|
|
newState = !currentState;
|
|
|
|
}
|
|
|
|
if ( newState === currentState ) {
|
|
|
|
return currentState;
|
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
|
2016-11-06 22:51:19 +01:00
|
|
|
var netWhitelist = this.netWhitelist,
|
|
|
|
pos = url.indexOf('#'),
|
|
|
|
targetURL = pos !== -1 ? url.slice(0, pos) : url,
|
|
|
|
targetHostname = this.URI.hostnameFromURI(targetURL),
|
|
|
|
key = targetHostname,
|
|
|
|
directive = scope === 'page' ? targetURL : targetHostname;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2014-12-14 23:21:59 +01:00
|
|
|
// Add to directive list
|
2014-12-14 14:57:00 +01:00
|
|
|
if ( newState === false ) {
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( netWhitelist[key] === undefined ) {
|
2014-12-22 20:48:17 +01:00
|
|
|
netWhitelist[key] = [];
|
2014-12-14 14:57:00 +01:00
|
|
|
}
|
2014-12-22 20:48:17 +01:00
|
|
|
netWhitelist[key].push(directive);
|
2014-08-02 17:40:27 +02:00
|
|
|
this.saveWhitelist();
|
2014-06-24 00:42:43 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-14 23:21:59 +01:00
|
|
|
// Remove from directive list whatever causes current URL to be whitelisted
|
2016-11-06 22:51:19 +01:00
|
|
|
var bucket, i;
|
2014-12-14 14:57:00 +01:00
|
|
|
for (;;) {
|
2016-11-06 22:51:19 +01:00
|
|
|
bucket = netWhitelist[key];
|
|
|
|
if ( bucket !== undefined ) {
|
|
|
|
i = undefined;
|
|
|
|
for (;;) {
|
|
|
|
i = matchBucket(targetURL, targetHostname, bucket, i);
|
|
|
|
if ( i === -1 ) { break; }
|
|
|
|
directive = bucket.splice(i, 1)[0];
|
2014-12-14 14:57:00 +01:00
|
|
|
if ( isHandcraftedWhitelistDirective(directive) ) {
|
|
|
|
netWhitelist['#'].push('# ' + directive);
|
|
|
|
}
|
|
|
|
}
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( bucket.length === 0 ) {
|
2014-12-14 23:21:59 +01:00
|
|
|
delete netWhitelist[key];
|
2014-12-14 14:57:00 +01:00
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
2014-12-14 23:21:59 +01:00
|
|
|
pos = key.indexOf('.');
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( pos === -1 ) { break; }
|
2014-12-14 23:21:59 +01:00
|
|
|
key = key.slice(pos + 1);
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
2016-11-06 22:51:19 +01:00
|
|
|
bucket = netWhitelist['//'];
|
|
|
|
if ( bucket !== undefined ) {
|
|
|
|
i = undefined;
|
|
|
|
for (;;) {
|
|
|
|
i = matchBucket(targetURL, targetHostname, bucket, i);
|
|
|
|
if ( i === -1 ) { break; }
|
|
|
|
directive = bucket.splice(i, 1)[0];
|
|
|
|
if ( isHandcraftedWhitelistDirective(directive) ) {
|
|
|
|
netWhitelist['#'].push('# ' + directive);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( bucket.length === 0 ) {
|
|
|
|
delete netWhitelist['//'];
|
|
|
|
}
|
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
this.saveWhitelist();
|
|
|
|
return true;
|
2014-06-24 00:42:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-12-08 18:37:35 +01:00
|
|
|
|
2014-12-14 14:57:00 +01:00
|
|
|
µBlock.stringFromWhitelist = function(whitelist) {
|
2014-08-02 17:40:27 +02:00
|
|
|
var r = {};
|
|
|
|
var i, bucket;
|
2014-12-14 14:57:00 +01:00
|
|
|
for ( var key in whitelist ) {
|
|
|
|
bucket = whitelist[key];
|
|
|
|
i = bucket.length;
|
|
|
|
while ( i-- ) {
|
2014-08-02 17:40:27 +02:00
|
|
|
r[bucket[i]] = true;
|
2014-06-24 01:23:36 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
return Object.keys(r).sort(function(a,b){return a.localeCompare(b);}).join('\n');
|
2014-06-24 01:23:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-08-02 17:40:27 +02:00
|
|
|
µBlock.whitelistFromString = function(s) {
|
2016-11-06 22:51:19 +01:00
|
|
|
var whitelist = Object.create(null),
|
2016-12-26 17:35:37 +01:00
|
|
|
lineIter = new this.LineIterator(s),
|
2016-11-06 22:51:19 +01:00
|
|
|
line, matches, key, directive, re;
|
|
|
|
|
|
|
|
// Comment bucket must always be ready to be used.
|
|
|
|
whitelist['#'] = [];
|
|
|
|
|
|
|
|
// New set of directives, scrap cached data.
|
|
|
|
directiveToRegexpMap.clear();
|
|
|
|
|
2016-12-26 17:35:37 +01:00
|
|
|
while ( !lineIter.eot() ) {
|
|
|
|
line = lineIter.next().trim();
|
|
|
|
|
2015-05-04 23:10:55 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/171
|
|
|
|
// Skip empty lines
|
|
|
|
if ( line === '' ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-12-14 14:57:00 +01:00
|
|
|
// Don't throw out commented out lines: user might want to fix them
|
2015-12-15 16:40:40 +01:00
|
|
|
if ( line.startsWith('#') ) {
|
2014-12-14 14:57:00 +01:00
|
|
|
key = '#';
|
|
|
|
directive = line;
|
|
|
|
}
|
|
|
|
// Plain hostname
|
|
|
|
else if ( line.indexOf('/') === -1 ) {
|
2018-03-12 13:28:07 +01:00
|
|
|
if ( this.reWhitelistBadHostname.test(line) ) {
|
2014-12-14 14:57:00 +01:00
|
|
|
key = '#';
|
|
|
|
directive = '# ' + line;
|
|
|
|
} else {
|
|
|
|
key = directive = line;
|
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
2016-11-06 22:51:19 +01:00
|
|
|
// Regex-based (ensure it is valid)
|
2016-12-26 17:35:37 +01:00
|
|
|
else if ( line.length > 2 && line.startsWith('/') && line.endsWith('/') ) {
|
2016-11-06 22:51:19 +01:00
|
|
|
key = '//';
|
|
|
|
directive = line;
|
|
|
|
try {
|
|
|
|
re = new RegExp(directive.slice(1, -1));
|
|
|
|
directiveToRegexpMap.set(directive, re);
|
|
|
|
} catch(ex) {
|
|
|
|
key = '#';
|
|
|
|
directive = '# ' + line;
|
|
|
|
}
|
|
|
|
}
|
2014-12-14 14:57:00 +01:00
|
|
|
// URL, possibly wildcarded: there MUST be at least one hostname
|
|
|
|
// label (or else it would be just impossible to make an efficient
|
|
|
|
// dict.
|
|
|
|
else {
|
2018-03-12 13:28:07 +01:00
|
|
|
matches = this.reWhitelistHostnameExtractor.exec(line);
|
2014-12-14 14:57:00 +01:00
|
|
|
if ( !matches || matches.length !== 2 ) {
|
|
|
|
key = '#';
|
|
|
|
directive = '# ' + line;
|
|
|
|
} else {
|
|
|
|
key = matches[1];
|
|
|
|
directive = line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-04 23:10:55 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/171
|
|
|
|
// Skip empty keys
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( key === '' ) { continue; }
|
2015-05-04 23:10:55 +02:00
|
|
|
|
2014-12-14 14:57:00 +01:00
|
|
|
// Be sure this stays fixed:
|
2015-04-07 03:26:05 +02:00
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/185
|
2016-11-06 22:51:19 +01:00
|
|
|
if ( whitelist[key] === undefined ) {
|
2014-12-14 14:57:00 +01:00
|
|
|
whitelist[key] = [];
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
2014-12-14 14:57:00 +01:00
|
|
|
whitelist[key].push(directive);
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
2014-12-14 14:57:00 +01:00
|
|
|
return whitelist;
|
2014-06-24 00:42:43 +02:00
|
|
|
};
|
|
|
|
|
2018-04-20 22:09:41 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/3717
|
|
|
|
µBlock.reWhitelistBadHostname = /[^a-z0-9.\-_\[\]:]/;
|
|
|
|
µBlock.reWhitelistHostnameExtractor = /([a-z0-9.\-_\[\]]+)(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/;
|
2016-12-26 17:35:37 +01:00
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2016-11-06 22:51:19 +01:00
|
|
|
})();
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
µBlock.changeUserSettings = function(name, value) {
|
2018-09-03 20:06:49 +02:00
|
|
|
let us = this.userSettings;
|
2016-01-17 19:30:43 +01:00
|
|
|
|
|
|
|
// Return all settings if none specified.
|
2014-06-25 00:29:55 +02:00
|
|
|
if ( name === undefined ) {
|
2016-01-17 19:30:43 +01:00
|
|
|
us = JSON.parse(JSON.stringify(us));
|
2018-09-03 20:06:49 +02:00
|
|
|
us.noCosmeticFiltering = this.sessionSwitches.evaluate('no-cosmetic-filtering', '*') === 1;
|
|
|
|
us.noLargeMedia = this.sessionSwitches.evaluate('no-large-media', '*') === 1;
|
|
|
|
us.noRemoteFonts = this.sessionSwitches.evaluate('no-remote-fonts', '*') === 1;
|
|
|
|
us.noScripting = this.sessionSwitches.evaluate('no-scripting', '*') === 1;
|
|
|
|
us.noCSPReports = this.sessionSwitches.evaluate('no-csp-reports', '*') === 1;
|
2016-01-17 19:30:43 +01:00
|
|
|
return us;
|
2014-06-25 00:29:55 +02:00
|
|
|
}
|
|
|
|
|
2018-09-03 20:06:49 +02:00
|
|
|
if ( typeof name !== 'string' || name === '' ) { return; }
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
if ( value === undefined ) {
|
2016-01-17 19:30:43 +01:00
|
|
|
return us[name];
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pre-change
|
|
|
|
switch ( name ) {
|
2016-01-17 19:30:43 +01:00
|
|
|
case 'largeMediaSize':
|
|
|
|
if ( typeof value !== 'number' ) {
|
|
|
|
value = parseInt(value, 10) || 0;
|
|
|
|
}
|
|
|
|
value = Math.ceil(Math.max(value, 0));
|
|
|
|
break;
|
2015-05-21 20:15:17 +02:00
|
|
|
default:
|
|
|
|
break;
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
|
2016-01-17 19:30:43 +01:00
|
|
|
// Change -- but only if the user setting actually exists.
|
2018-09-03 20:06:49 +02:00
|
|
|
let mustSave = us.hasOwnProperty(name) && value !== us[name];
|
2016-01-17 19:30:43 +01:00
|
|
|
if ( mustSave ) {
|
|
|
|
us[name] = value;
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
// Post-change
|
|
|
|
switch ( name ) {
|
2016-11-05 19:48:42 +01:00
|
|
|
case 'advancedUserEnabled':
|
|
|
|
if ( value === true ) {
|
|
|
|
us.dynamicFilteringEnabled = true;
|
|
|
|
}
|
|
|
|
break;
|
2017-01-18 19:17:47 +01:00
|
|
|
case 'autoUpdate':
|
|
|
|
this.scheduleAssetUpdater(value ? 7 * 60 * 1000 : 0);
|
|
|
|
break;
|
2015-05-21 20:15:17 +02:00
|
|
|
case 'collapseBlocked':
|
|
|
|
if ( value === false ) {
|
|
|
|
this.cosmeticFilteringEngine.removeFromSelectorCache('*', 'net');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'contextMenuEnabled':
|
2016-01-17 19:30:43 +01:00
|
|
|
this.contextMenu.update(null);
|
2015-05-21 20:15:17 +02:00
|
|
|
break;
|
2015-06-02 15:27:18 +02:00
|
|
|
case 'hyperlinkAuditingDisabled':
|
2016-10-19 16:20:26 +02:00
|
|
|
if ( this.privacySettingsSupported ) {
|
|
|
|
vAPI.browserSettings.set({ 'hyperlinkAuditing': !value });
|
|
|
|
}
|
2015-06-02 15:27:18 +02:00
|
|
|
break;
|
2016-01-17 19:30:43 +01:00
|
|
|
case 'noCosmeticFiltering':
|
|
|
|
case 'noLargeMedia':
|
|
|
|
case 'noRemoteFonts':
|
2018-09-01 00:47:02 +02:00
|
|
|
case 'noScripting':
|
2017-10-19 15:35:28 +02:00
|
|
|
case 'noCSPReports':
|
2018-09-03 20:06:49 +02:00
|
|
|
let switchName;
|
|
|
|
switch ( name ) {
|
|
|
|
case 'noCosmeticFiltering':
|
|
|
|
switchName = 'no-cosmetic-filtering'; break;
|
|
|
|
case 'noLargeMedia':
|
|
|
|
switchName = 'no-large-media'; break;
|
|
|
|
case 'noRemoteFonts':
|
|
|
|
switchName = 'no-remote-fonts'; break;
|
|
|
|
case 'noScripting':
|
|
|
|
switchName = 'no-scripting'; break;
|
|
|
|
case 'noCSPReports':
|
|
|
|
switchName = 'no-csp-reports'; break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( switchName === undefined ) { break; }
|
|
|
|
let switchState = value ? 1 : 0;
|
|
|
|
this.sessionSwitches.toggle(switchName, '*', switchState);
|
|
|
|
if ( this.permanentSwitches.toggle(switchName, '*', switchState) ) {
|
2017-10-19 15:35:28 +02:00
|
|
|
this.saveHostnameSwitches();
|
|
|
|
}
|
|
|
|
break;
|
2015-06-01 21:03:22 +02:00
|
|
|
case 'prefetchingDisabled':
|
2016-10-19 16:20:26 +02:00
|
|
|
if ( this.privacySettingsSupported ) {
|
|
|
|
vAPI.browserSettings.set({ 'prefetching': !value });
|
|
|
|
}
|
2015-06-01 21:03:22 +02:00
|
|
|
break;
|
2015-06-25 02:01:27 +02:00
|
|
|
case 'webrtcIPAddressHidden':
|
2016-10-19 16:20:26 +02:00
|
|
|
if ( this.privacySettingsSupported ) {
|
|
|
|
vAPI.browserSettings.set({ 'webrtcIPAddress': !value });
|
|
|
|
}
|
2015-06-25 02:01:27 +02:00
|
|
|
break;
|
2015-05-21 20:15:17 +02:00
|
|
|
default:
|
|
|
|
break;
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
|
2016-01-17 19:30:43 +01:00
|
|
|
if ( mustSave ) {
|
|
|
|
this.saveUserSettings();
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2018-03-19 15:25:03 +01:00
|
|
|
|
|
|
|
// https://www.reddit.com/r/uBlockOrigin/comments/8524cf/my_custom_scriptlets_doesnt_work_what_am_i_doing/
|
|
|
|
|
|
|
|
µBlock.changeHiddenSettings = function(hs) {
|
|
|
|
var mustReloadResources =
|
|
|
|
hs.userResourcesLocation !== this.hiddenSettings.userResourcesLocation;
|
|
|
|
this.hiddenSettings = hs;
|
|
|
|
this.saveHiddenSettings();
|
|
|
|
if ( mustReloadResources ) {
|
|
|
|
this.redirectEngine.invalidateResourcesSelfie();
|
|
|
|
this.loadRedirectResources();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2017-05-27 17:51:24 +02:00
|
|
|
µBlock.elementPickerExec = function(tabId, targetElement, zap) {
|
2018-07-20 13:11:21 +02:00
|
|
|
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
|
|
|
|
2015-03-20 16:39:20 +01:00
|
|
|
this.epickerTarget = targetElement || '';
|
2017-05-27 17:51:24 +02:00
|
|
|
this.epickerZap = zap || false;
|
2018-08-15 02:14:13 +02:00
|
|
|
|
2018-12-20 23:29:39 +01:00
|
|
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/40
|
|
|
|
// The element picker needs this library
|
|
|
|
vAPI.tabs.injectScript(
|
|
|
|
tabId,
|
|
|
|
{
|
|
|
|
file: '/lib/diff/swatinem_diff.js',
|
|
|
|
runAt: 'document_end'
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2018-08-15 02:14:13 +02:00
|
|
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/168
|
|
|
|
// Force activate the target tab once the element picker has been
|
|
|
|
// injected.
|
|
|
|
vAPI.tabs.injectScript(
|
|
|
|
tabId,
|
|
|
|
{
|
|
|
|
file: '/js/scriptlets/element-picker.js',
|
|
|
|
runAt: 'document_end'
|
|
|
|
},
|
|
|
|
( ) => {
|
|
|
|
vAPI.tabs.select(tabId);
|
|
|
|
}
|
|
|
|
);
|
2014-09-28 18:05:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-10-06 20:02:44 +02:00
|
|
|
|
2016-09-27 14:31:12 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/2033
|
|
|
|
// Always set own rules, trying to be fancy to avoid setting seemingly
|
|
|
|
// (but not really) redundant rules led to this issue.
|
|
|
|
|
2015-02-11 06:26:45 +01:00
|
|
|
µBlock.toggleFirewallRule = function(details) {
|
2018-09-03 20:06:49 +02:00
|
|
|
let requestType = details.requestType;
|
2016-05-28 15:18:36 +02:00
|
|
|
|
2014-12-31 16:47:19 +01:00
|
|
|
if ( details.action !== 0 ) {
|
2016-09-27 14:31:12 +02:00
|
|
|
this.sessionFirewall.setCell(details.srcHostname, details.desHostname, requestType, details.action);
|
2014-10-06 20:02:44 +02:00
|
|
|
} else {
|
2016-05-28 15:18:36 +02:00
|
|
|
this.sessionFirewall.unsetCell(details.srcHostname, details.desHostname, requestType);
|
2014-10-06 20:02:44 +02:00
|
|
|
}
|
2014-12-17 16:32:50 +01:00
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/731#issuecomment-73937469
|
2015-02-11 21:48:39 +01:00
|
|
|
if ( details.persist ) {
|
|
|
|
if ( details.action !== 0 ) {
|
2016-09-27 14:31:12 +02:00
|
|
|
this.permanentFirewall.setCell(details.srcHostname, details.desHostname, requestType, details.action);
|
2015-02-11 21:48:39 +01:00
|
|
|
} else {
|
2016-05-28 15:18:36 +02:00
|
|
|
this.permanentFirewall.unsetCell(details.srcHostname, details.desHostname, requestType, details.action);
|
2015-02-11 21:48:39 +01:00
|
|
|
}
|
|
|
|
this.savePermanentFirewallRules();
|
|
|
|
}
|
|
|
|
|
2016-05-28 15:18:36 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/1662
|
|
|
|
// Flush all cached `net` cosmetic filters if we are dealing with a
|
2016-05-28 15:19:35 +02:00
|
|
|
// collapsible type: any of the cached entries could be a resource on the
|
2016-05-28 15:18:36 +02:00
|
|
|
// target page.
|
2018-09-03 20:06:49 +02:00
|
|
|
let srcHostname = details.srcHostname;
|
2016-05-28 15:18:36 +02:00
|
|
|
if (
|
|
|
|
(srcHostname !== '*') &&
|
|
|
|
(requestType === '*' || requestType === 'image' || requestType === '3p' || requestType === '3p-frame')
|
|
|
|
) {
|
|
|
|
srcHostname = '*';
|
|
|
|
}
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/420
|
2016-05-28 15:18:36 +02:00
|
|
|
this.cosmeticFilteringEngine.removeFromSelectorCache(srcHostname, 'net');
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-05-21 20:15:17 +02:00
|
|
|
µBlock.toggleURLFilteringRule = function(details) {
|
2018-09-03 20:06:49 +02:00
|
|
|
let changed = this.sessionURLFiltering.setRule(
|
2015-05-21 20:15:17 +02:00
|
|
|
details.context,
|
|
|
|
details.url,
|
|
|
|
details.type,
|
|
|
|
details.action
|
|
|
|
);
|
2018-09-03 20:06:49 +02:00
|
|
|
if ( changed === false ) { return; }
|
2015-05-21 20:15:17 +02:00
|
|
|
|
|
|
|
this.cosmeticFilteringEngine.removeFromSelectorCache(details.context, 'net');
|
2015-05-22 14:05:55 +02:00
|
|
|
|
2018-09-03 20:06:49 +02:00
|
|
|
if ( details.persist !== true ) { return; }
|
2015-05-22 14:05:55 +02:00
|
|
|
|
|
|
|
changed = this.permanentURLFiltering.setRule(
|
|
|
|
details.context,
|
|
|
|
details.url,
|
|
|
|
details.type,
|
|
|
|
details.action
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( changed ) {
|
|
|
|
this.savePermanentFirewallRules();
|
|
|
|
}
|
2015-05-21 20:15:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-03-27 18:00:55 +01:00
|
|
|
µBlock.toggleHostnameSwitch = function(details) {
|
2018-09-03 20:06:49 +02:00
|
|
|
let changed = this.sessionSwitches.toggleZ(
|
|
|
|
details.name,
|
|
|
|
details.hostname,
|
|
|
|
!!details.deep,
|
|
|
|
details.state
|
|
|
|
);
|
|
|
|
if ( changed === false ) { return; }
|
2015-04-05 18:03:14 +02:00
|
|
|
|
|
|
|
// Take action if needed
|
2016-01-17 19:30:43 +01:00
|
|
|
switch ( details.name ) {
|
|
|
|
case 'no-cosmetic-filtering':
|
2015-06-26 06:08:41 +02:00
|
|
|
this.scriptlets.injectDeep(
|
|
|
|
details.tabId,
|
|
|
|
details.state ? 'cosmetic-off' : 'cosmetic-on'
|
|
|
|
);
|
2016-01-17 19:30:43 +01:00
|
|
|
break;
|
|
|
|
case 'no-large-media':
|
2017-09-12 17:43:43 +02:00
|
|
|
var pageStore = this.pageStoreFromTabId(details.tabId);
|
|
|
|
if ( pageStore !== null ) {
|
|
|
|
pageStore.temporarilyAllowLargeMediaElements(!details.state);
|
2016-01-17 19:30:43 +01:00
|
|
|
}
|
|
|
|
break;
|
2015-04-05 18:03:14 +02:00
|
|
|
}
|
2018-09-03 20:06:49 +02:00
|
|
|
|
|
|
|
if ( details.persist !== true ) { return; }
|
|
|
|
|
|
|
|
changed = this.permanentSwitches.toggleZ(
|
|
|
|
details.name,
|
|
|
|
details.hostname,
|
|
|
|
!!details.deep,
|
|
|
|
details.state
|
|
|
|
);
|
|
|
|
if ( changed ) {
|
|
|
|
this.saveHostnameSwitches();
|
|
|
|
}
|
2015-04-05 18:03:14 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2018-08-21 13:07:14 +02:00
|
|
|
// https://github.com/NanoMeow/QuickReports/issues/6#issuecomment-414516623
|
|
|
|
// Inject as early as possible to make the cosmetic logger code less
|
|
|
|
// sensitive to the removal of DOM nodes which may match injected
|
|
|
|
// cosmetic filters.
|
|
|
|
|
2018-07-04 21:03:09 +02:00
|
|
|
µBlock.logCosmeticFilters = function(tabId, frameId) {
|
2018-12-21 20:16:17 +01:00
|
|
|
vAPI.tabs.injectScript(tabId, {
|
|
|
|
file: '/js/scriptlets/cosmetic-logger.js',
|
|
|
|
frameId: frameId,
|
|
|
|
runAt: 'document_start'
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
µBlock.logInlineScript = function(tabId, frameId) {
|
|
|
|
vAPI.tabs.injectScript(tabId, {
|
|
|
|
frameId: frameId,
|
|
|
|
file: '/js/scriptlets/inlinescript-logger.js',
|
2018-12-22 14:33:42 +01:00
|
|
|
runAt: 'document_end'
|
2018-12-21 20:16:17 +01:00
|
|
|
});
|
2018-07-04 21:03:09 +02:00
|
|
|
};
|
2015-04-25 13:28:35 +02:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-06-26 06:08:41 +02:00
|
|
|
µBlock.scriptlets = (function() {
|
2017-10-25 17:37:58 +02:00
|
|
|
var pendingEntries = new Map();
|
2015-06-26 06:08:41 +02:00
|
|
|
|
|
|
|
var Entry = function(tabId, scriptlet, callback) {
|
|
|
|
this.tabId = tabId;
|
|
|
|
this.scriptlet = scriptlet;
|
|
|
|
this.callback = callback;
|
|
|
|
this.timer = vAPI.setTimeout(this.service.bind(this), 1000);
|
|
|
|
};
|
|
|
|
|
|
|
|
Entry.prototype.service = function(response) {
|
|
|
|
if ( this.timer !== null ) {
|
|
|
|
clearTimeout(this.timer);
|
2017-10-25 17:37:58 +02:00
|
|
|
this.timer = null;
|
2015-06-26 06:08:41 +02:00
|
|
|
}
|
2017-10-25 17:37:58 +02:00
|
|
|
pendingEntries.delete(makeKey(this.tabId, this.scriptlet));
|
2015-06-26 06:08:41 +02:00
|
|
|
this.callback(response);
|
|
|
|
};
|
|
|
|
|
|
|
|
var makeKey = function(tabId, scriptlet) {
|
|
|
|
return tabId + ' ' + scriptlet;
|
|
|
|
};
|
|
|
|
|
|
|
|
var report = function(tabId, scriptlet, response) {
|
|
|
|
var key = makeKey(tabId, scriptlet);
|
2017-10-25 17:37:58 +02:00
|
|
|
var entry = pendingEntries.get(key);
|
|
|
|
if ( entry === undefined ) { return; }
|
2015-06-26 06:08:41 +02:00
|
|
|
entry.service(response);
|
|
|
|
};
|
|
|
|
|
|
|
|
var inject = function(tabId, scriptlet, callback) {
|
|
|
|
if ( typeof callback === 'function' ) {
|
|
|
|
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
|
|
|
|
callback();
|
|
|
|
return;
|
|
|
|
}
|
2017-10-25 17:37:58 +02:00
|
|
|
var key = makeKey(tabId, scriptlet),
|
|
|
|
entry = pendingEntries.get(key);
|
|
|
|
if ( entry !== undefined ) {
|
|
|
|
if ( callback !== entry.callback ) {
|
|
|
|
callback();
|
|
|
|
}
|
2015-06-26 06:08:41 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-25 17:37:58 +02:00
|
|
|
pendingEntries.set(key, new Entry(tabId, scriptlet, callback));
|
2015-06-26 06:08:41 +02:00
|
|
|
}
|
2017-10-25 17:37:58 +02:00
|
|
|
vAPI.tabs.injectScript(tabId, {
|
2017-11-20 14:42:32 +01:00
|
|
|
file: '/js/scriptlets/' + scriptlet + '.js'
|
2017-10-25 17:37:58 +02:00
|
|
|
});
|
2015-06-26 06:08:41 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: think about a callback mechanism.
|
|
|
|
var injectDeep = function(tabId, scriptlet) {
|
|
|
|
vAPI.tabs.injectScript(tabId, {
|
2017-11-20 14:42:32 +01:00
|
|
|
file: '/js/scriptlets/' + scriptlet + '.js',
|
2015-06-26 06:08:41 +02:00
|
|
|
allFrames: true
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return {
|
|
|
|
inject: inject,
|
|
|
|
injectDeep: injectDeep,
|
|
|
|
report: report
|
|
|
|
};
|
|
|
|
})();
|