2014-06-24 00:42:43 +02:00
|
|
|
/*******************************************************************************
|
|
|
|
|
|
|
|
µBlock - a Chromium browser extension to block requests.
|
|
|
|
Copyright (C) 2014 Raymond Hill
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2014-12-12 23:59:47 +01:00
|
|
|
/* global vAPI, µBlock */
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
|
2014-10-19 13:11:27 +02:00
|
|
|
'use strict';
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-08-02 17:40:27 +02:00
|
|
|
µBlock.getNetFilteringSwitch = function(url, domain) {
|
|
|
|
var keyHostname = this.URI.hostnameFromURI(url);
|
|
|
|
var pos = url.indexOf('#');
|
|
|
|
var keyURL = pos !== -1 ? url.slice(0, pos) : url;
|
|
|
|
|
|
|
|
// The caller may provide an already known domain -- convenient to reduce
|
|
|
|
// overhead of extracting a domain from the url
|
2014-08-27 08:01:10 +02:00
|
|
|
if ( typeof domain !== 'string' ) {
|
2014-08-02 17:40:27 +02:00
|
|
|
domain = this.URI.domainFromHostname(keyHostname);
|
|
|
|
}
|
2014-08-27 08:01:10 +02:00
|
|
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/185
|
|
|
|
// Use hostname if no domain can be extracted
|
|
|
|
if ( domain === '' ) {
|
|
|
|
domain = keyHostname;
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
|
|
|
|
var exceptions = this.netWhitelist[domain];
|
|
|
|
if ( !exceptions ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
var i = exceptions.length;
|
|
|
|
while ( i-- ) {
|
2014-12-12 23:59:47 +01:00
|
|
|
if ( matchWhitelistException(keyURL, keyHostname, exceptions[i]) ) {
|
2014-12-08 18:37:35 +01:00
|
|
|
// console.log('"%s" matche url "%s"', exceptions[i], keyURL);
|
2014-06-24 00:42:43 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-08-02 17:40:27 +02:00
|
|
|
µBlock.toggleNetFilteringSwitch = function(url, scope, newState) {
|
|
|
|
var keyHostname = this.URI.hostnameFromURI(url);
|
|
|
|
var pos = url.indexOf('#');
|
|
|
|
var keyURL = pos !== -1 ? url.slice(0, pos) : url;
|
|
|
|
var key = scope === 'page' ? keyURL : keyHostname;
|
|
|
|
|
|
|
|
// The caller may provide an already known domain -- convenient to reduce
|
|
|
|
// overhead of extracting a domain from `key`
|
|
|
|
var domain = this.URI.domainFromHostname(keyHostname);
|
2014-08-27 08:01:10 +02:00
|
|
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/185
|
|
|
|
// Use hostname if no domain can be extracted
|
|
|
|
if ( domain === '' ) {
|
|
|
|
domain = keyHostname;
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var currentState = this.getNetFilteringSwitch(url, domain);
|
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
|
|
|
|
|
|
|
var netWhitelist = this.netWhitelist;
|
|
|
|
var exceptions = netWhitelist[domain];
|
|
|
|
if ( !exceptions ) {
|
|
|
|
exceptions = netWhitelist[domain] = [];
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
// Add to exception list
|
|
|
|
if ( !newState ) {
|
2014-08-02 17:40:27 +02:00
|
|
|
exceptions.push(key);
|
|
|
|
this.saveWhitelist();
|
2014-06-24 00:42:43 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-08 18:37:35 +01:00
|
|
|
// Remove from exception list whatever causes current URL to be whitelisted
|
2014-08-02 17:40:27 +02:00
|
|
|
var i = exceptions.length;
|
|
|
|
while ( i-- ) {
|
2014-12-12 23:59:47 +01:00
|
|
|
if ( matchWhitelistException(keyURL, keyHostname, exceptions[i]) ) {
|
2014-08-02 17:40:27 +02:00
|
|
|
exceptions.splice(i, 1);
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
if ( exceptions.length === 0 ) {
|
|
|
|
delete netWhitelist[domain];
|
|
|
|
}
|
|
|
|
this.saveWhitelist();
|
|
|
|
return true;
|
2014-06-24 00:42:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-12-08 18:37:35 +01:00
|
|
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/405
|
|
|
|
// Be more flexible with whitelist syntax
|
|
|
|
|
|
|
|
// TODO: Need to harden it against edge cases, like when an asterisk is used in
|
|
|
|
// place of protocol.
|
|
|
|
|
2014-12-12 23:59:47 +01:00
|
|
|
var matchWhitelistException = function(url, hostname, exception) {
|
2014-12-08 18:37:35 +01:00
|
|
|
// Exception is a plain hostname
|
|
|
|
if ( exception.indexOf('/') === -1 ) {
|
|
|
|
return hostname.slice(-exception.length) === exception;
|
|
|
|
}
|
|
|
|
// Match URL exactly
|
|
|
|
if ( exception.indexOf('*') === -1 ) {
|
|
|
|
return url === exception;
|
|
|
|
}
|
|
|
|
// Regex escape code inspired from:
|
|
|
|
// "Is there a RegExp.escape function in Javascript?"
|
|
|
|
// http://stackoverflow.com/a/3561711
|
2014-12-12 23:59:47 +01:00
|
|
|
var reStr = exception.replace(whitelistExceptionEscape, '\\$&')
|
|
|
|
.replace(whitelistExceptionEscapeAsterisk, '.*');
|
2014-12-08 18:37:35 +01:00
|
|
|
var re = new RegExp(reStr);
|
|
|
|
return re.test(url);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Any special regexp char will be escaped
|
2014-12-12 23:59:47 +01:00
|
|
|
var whitelistExceptionEscape = /[-\/\\^$+?.()|[\]{}]/g;
|
2014-12-08 18:37:35 +01:00
|
|
|
|
|
|
|
// All `*` will be expanded into `.*`
|
2014-12-12 23:59:47 +01:00
|
|
|
var whitelistExceptionEscapeAsterisk = /\*/g;
|
2014-12-08 18:37:35 +01:00
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2014-06-24 01:23:36 +02:00
|
|
|
// For now we will use the net exception list
|
|
|
|
|
2014-08-02 17:40:27 +02:00
|
|
|
µBlock.getCosmeticFilteringSwitch = function(url, domain) {
|
|
|
|
return this.getNetFilteringSwitch(url, domain);
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
µBlock.stringFromWhitelist = function(exceptions) {
|
|
|
|
var r = {};
|
|
|
|
var i, bucket;
|
|
|
|
for ( var domain in exceptions ) {
|
|
|
|
if ( exceptions.hasOwnProperty(domain) === false ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bucket = exceptions[domain];
|
|
|
|
for ( i = 0; i < bucket.length; i++ ) {
|
|
|
|
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) {
|
|
|
|
var exceptions = {};
|
|
|
|
var lines = s.split(/[\n\r]+/);
|
2014-08-27 08:01:10 +02:00
|
|
|
var line, hostname, domain, bucket;
|
2014-08-02 17:40:27 +02:00
|
|
|
for ( var i = 0; i < lines.length; i++ ) {
|
|
|
|
line = lines[i].trim();
|
2014-08-27 08:01:10 +02:00
|
|
|
hostname = line.indexOf('/') !== -1 ? this.URI.hostnameFromURI(line) : line;
|
|
|
|
domain = this.URI.domainFromHostname(hostname);
|
|
|
|
// https://github.com/gorhill/uBlock/issues/185
|
|
|
|
// Use hostname if no domain can be extracted
|
|
|
|
if ( domain === '' ) {
|
|
|
|
domain = hostname;
|
2014-08-02 17:40:27 +02:00
|
|
|
}
|
|
|
|
bucket = exceptions[domain];
|
|
|
|
if ( bucket === undefined ) {
|
|
|
|
exceptions[domain] = [line];
|
|
|
|
} else {
|
|
|
|
bucket.push(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return exceptions;
|
2014-06-24 00:42:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-06-25 00:29:55 +02:00
|
|
|
// Return all settings if none specified.
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
µBlock.changeUserSettings = function(name, value) {
|
2014-06-25 00:29:55 +02:00
|
|
|
if ( name === undefined ) {
|
2014-09-28 18:05:46 +02:00
|
|
|
return this.userSettings;
|
2014-06-25 00:29:55 +02:00
|
|
|
}
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
if ( typeof name !== 'string' || name === '' ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not allow an unknown user setting to be created
|
2014-09-28 18:05:46 +02:00
|
|
|
if ( this.userSettings[name] === undefined ) {
|
2014-06-24 00:42:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( value === undefined ) {
|
2014-09-28 18:05:46 +02:00
|
|
|
return this.userSettings[name];
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pre-change
|
|
|
|
switch ( name ) {
|
2014-10-17 21:44:19 +02:00
|
|
|
default:
|
2014-06-26 15:46:38 +02:00
|
|
|
break;
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Change
|
2014-09-28 18:05:46 +02:00
|
|
|
this.userSettings[name] = value;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
// Post-change
|
|
|
|
switch ( name ) {
|
2014-09-28 18:05:46 +02:00
|
|
|
case 'contextMenuEnabled':
|
2014-09-30 21:55:18 +02:00
|
|
|
this.contextMenu.toggle(value);
|
|
|
|
break;
|
|
|
|
case 'experimentalEnabled':
|
|
|
|
if ( typeof this.mirrors === 'object' ) {
|
|
|
|
this.mirrors.toggle(value);
|
|
|
|
}
|
2014-09-28 18:05:46 +02:00
|
|
|
break;
|
2014-06-26 15:46:38 +02:00
|
|
|
default:
|
|
|
|
break;
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
|
2014-09-28 18:05:46 +02:00
|
|
|
this.saveUserSettings();
|
2014-06-24 00:42:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
µBlock.transposeType = function(type, path) {
|
2014-09-20 16:44:04 +02:00
|
|
|
if ( type !== 'other' ) {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
var pos = path.lastIndexOf('.');
|
|
|
|
if ( pos === -1 ) {
|
|
|
|
return type;
|
|
|
|
}
|
2014-09-20 16:47:30 +02:00
|
|
|
var ext = path.slice(pos) + '.';
|
2014-10-06 20:02:44 +02:00
|
|
|
if ( '.css.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
|
2014-09-20 16:44:04 +02:00
|
|
|
return 'stylesheet';
|
|
|
|
}
|
2014-09-20 16:47:30 +02:00
|
|
|
if ( '.ico.png.gif.jpg.jpeg.'.indexOf(ext) !== -1 ) {
|
2014-09-20 16:44:04 +02:00
|
|
|
return 'image';
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
|
|
|
return type;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-09-28 18:05:46 +02:00
|
|
|
|
|
|
|
µBlock.elementPickerExec = function(tabId, targetElement) {
|
|
|
|
this.elementPickerTarget = targetElement || '';
|
2014-10-20 13:26:02 +02:00
|
|
|
vAPI.tabs.injectScript(tabId, { file: 'js/element-picker.js' });
|
2014-09-28 18:05:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-10-06 20:02:44 +02:00
|
|
|
|
|
|
|
µBlock.toggleDynamicFilter = function(details) {
|
|
|
|
var changed = false;
|
|
|
|
if ( details.block ) {
|
|
|
|
changed = this.netFilteringEngine.dynamicFilterBlock(details.hostname, details.requestType, details.firstParty);
|
|
|
|
} else {
|
|
|
|
changed = this.netFilteringEngine.dynamicFilterUnblock(details.hostname, details.requestType, details.firstParty);
|
|
|
|
}
|
|
|
|
if ( changed ) {
|
|
|
|
this.userSettings.dynamicFilteringSelfie = this.netFilteringEngine.selfieFromDynamicFilters();
|
2014-10-07 14:59:35 +02:00
|
|
|
this.XAL.keyvalSetOne('dynamicFilteringSelfie', this.userSettings.dynamicFilteringSelfie);
|
2014-10-06 20:02:44 +02:00
|
|
|
}
|
|
|
|
};
|
2014-12-12 23:59:47 +01:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
})();
|