2014-12-28 16:07:43 +01:00
|
|
|
/*******************************************************************************
|
|
|
|
|
2016-09-27 14:31:12 +02:00
|
|
|
uBlock Origin - a browser extension to block requests.
|
2018-03-11 15:59:39 +01:00
|
|
|
Copyright (C) 2014-2018 Raymond Hill
|
2014-12-28 16:07:43 +01: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-09-27 14:31:12 +02:00
|
|
|
/* global punycode */
|
2014-12-28 16:07:43 +01:00
|
|
|
/* jshint bitwise: false */
|
|
|
|
|
2016-09-27 14:31:12 +02:00
|
|
|
'use strict';
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-02-11 06:26:45 +01:00
|
|
|
µBlock.Firewall = (function() {
|
2014-12-28 16:07:43 +01:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
var Matrix = function() {
|
|
|
|
this.reset();
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-01-08 02:42:19 +01:00
|
|
|
var supportedDynamicTypes = {
|
2015-02-04 18:51:43 +01:00
|
|
|
'3p': true,
|
|
|
|
'image': true,
|
2015-01-06 14:01:15 +01:00
|
|
|
'inline-script': true,
|
|
|
|
'1p-script': true,
|
|
|
|
'3p-script': true,
|
2015-07-27 15:20:47 +02:00
|
|
|
'3p-frame': true
|
2015-01-06 14:01:15 +01:00
|
|
|
};
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
var typeBitOffsets = {
|
|
|
|
'*': 0,
|
|
|
|
'inline-script': 2,
|
|
|
|
'1p-script': 4,
|
|
|
|
'3p-script': 6,
|
|
|
|
'3p-frame': 8,
|
2015-01-06 14:01:15 +01:00
|
|
|
'image': 10,
|
2015-07-27 15:20:47 +02:00
|
|
|
'3p': 12
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
2014-12-31 23:26:17 +01:00
|
|
|
var actionToNameMap = {
|
2014-12-28 16:07:43 +01:00
|
|
|
'1': 'block',
|
|
|
|
'2': 'allow',
|
|
|
|
'3': 'noop'
|
|
|
|
};
|
|
|
|
|
2014-12-31 23:26:17 +01:00
|
|
|
var nameToActionMap = {
|
2014-12-28 16:07:43 +01:00
|
|
|
'block': 1,
|
|
|
|
'allow': 2,
|
|
|
|
'noop': 3
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// For performance purpose, as simple tests as possible
|
|
|
|
var reHostnameVeryCoarse = /[g-z_-]/;
|
|
|
|
var reIPv4VeryCoarse = /\.\d+$/;
|
2018-02-12 14:18:24 +01:00
|
|
|
var reBadHostname = /[^0-9a-z_.\[\]:%-]/;
|
2018-03-11 15:59:39 +01:00
|
|
|
var reNotASCII = /[^\x20-\x7F]/;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
|
|
|
// http://tools.ietf.org/html/rfc5952
|
|
|
|
// 4.3: "MUST be represented in lowercase"
|
|
|
|
// Also: http://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers
|
|
|
|
|
|
|
|
var isIPAddress = function(hostname) {
|
|
|
|
if ( reHostnameVeryCoarse.test(hostname) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( reIPv4VeryCoarse.test(hostname) ) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-12-15 16:40:40 +01:00
|
|
|
return hostname.startsWith('[');
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
var toBroaderHostname = function(hostname) {
|
|
|
|
var pos = hostname.indexOf('.');
|
2015-11-23 15:49:50 +01:00
|
|
|
if ( pos !== -1 ) {
|
|
|
|
return hostname.slice(pos + 1);
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
2015-11-23 15:49:50 +01:00
|
|
|
return hostname !== '*' && hostname !== '' ? '*' : '';
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
2016-11-12 19:42:36 +01:00
|
|
|
var toBroaderIPAddress = function(ipaddress) {
|
|
|
|
return ipaddress !== '*' && ipaddress !== '' ? '*' : '';
|
|
|
|
};
|
|
|
|
|
|
|
|
var selectHostnameBroadener = function(hostname) {
|
|
|
|
return isIPAddress(hostname) ? toBroaderIPAddress : toBroaderHostname;
|
|
|
|
};
|
2014-12-28 16:07:43 +01:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.reset = function() {
|
|
|
|
this.r = 0;
|
|
|
|
this.type = '';
|
|
|
|
this.y = '';
|
|
|
|
this.z = '';
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules = new Map();
|
|
|
|
this.changed = false;
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-02-11 06:26:45 +01:00
|
|
|
Matrix.prototype.assign = function(other) {
|
|
|
|
// Remove rules not in other
|
2018-03-11 15:59:39 +01:00
|
|
|
for ( var k of this.rules.keys() ) {
|
|
|
|
if ( other.rules.has(k) === false ) {
|
|
|
|
this.rules.delete(k);
|
|
|
|
this.changed = true;
|
2015-02-11 06:26:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Add/change rules in other
|
2018-03-11 15:59:39 +01:00
|
|
|
for ( var entry of other.rules ) {
|
|
|
|
if ( this.rules.get(entry[0]) !== entry[1] ) {
|
|
|
|
this.rules.set(entry[0], entry[1]);
|
|
|
|
this.changed = true;
|
2015-02-11 06:26:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.copyRules = function(other, srcHostname, desHostnames) {
|
|
|
|
|
|
|
|
// Specific types
|
2018-03-11 15:59:39 +01:00
|
|
|
var bits = other.rules.get('* *');
|
|
|
|
if ( bits !== undefined ) {
|
|
|
|
this.rules.set('* *', bits);
|
2015-03-05 01:43:15 +01:00
|
|
|
} else {
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules.delete('* *');
|
2015-03-05 01:43:15 +01:00
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
var key = srcHostname + ' *';
|
|
|
|
bits = other.rules.get(key);
|
|
|
|
if ( bits !== undefined ) {
|
|
|
|
this.rules.set(key, bits);
|
2015-03-05 01:43:15 +01:00
|
|
|
} else {
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules.delete(key);
|
2015-03-05 01:43:15 +01:00
|
|
|
}
|
2015-02-11 06:26:45 +01:00
|
|
|
|
|
|
|
// Specific destinations
|
|
|
|
for ( var desHostname in desHostnames ) {
|
2018-03-11 15:59:39 +01:00
|
|
|
if ( desHostnames.hasOwnProperty(desHostname) === false ) { continue; }
|
|
|
|
key = '* ' + desHostname;
|
|
|
|
bits = other.rules.get(key);
|
|
|
|
if ( bits !== undefined ) {
|
|
|
|
this.rules.set(key, bits);
|
2015-03-05 01:43:15 +01:00
|
|
|
} else {
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules.delete(key);
|
2015-03-05 01:43:15 +01:00
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
key = srcHostname + ' ' + desHostname ;
|
|
|
|
bits = other.rules.get(key);
|
|
|
|
if ( bits !== undefined ) {
|
|
|
|
this.rules.set(key, bits);
|
2015-03-05 01:43:15 +01:00
|
|
|
} else {
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules.delete(key);
|
2015-03-05 01:43:15 +01:00
|
|
|
}
|
2015-02-11 06:26:45 +01:00
|
|
|
}
|
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
this.changed = true;
|
|
|
|
|
2015-02-11 06:26:45 +01:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// - * * type
|
|
|
|
// - from * type
|
2015-03-07 19:20:18 +01:00
|
|
|
// - * to *
|
2015-02-11 06:26:45 +01:00
|
|
|
// - from to *
|
|
|
|
|
|
|
|
Matrix.prototype.hasSameRules = function(other, srcHostname, desHostnames) {
|
|
|
|
|
|
|
|
// Specific types
|
2018-03-11 15:59:39 +01:00
|
|
|
var key = '* *';
|
|
|
|
if ( this.rules.get(key) !== other.rules.get(key) ) {
|
2015-02-11 06:26:45 +01:00
|
|
|
return false;
|
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
key = srcHostname + ' *';
|
|
|
|
if ( this.rules.get(key) !== other.rules.get(key) ) {
|
2015-02-11 06:26:45 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Specific destinations
|
|
|
|
for ( var desHostname in desHostnames ) {
|
2018-03-11 15:59:39 +01:00
|
|
|
key = '* ' + desHostname;
|
|
|
|
if ( this.rules.get(key) !== other.rules.get(key) ) {
|
2015-02-11 06:26:45 +01:00
|
|
|
return false;
|
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
key = srcHostname + ' ' + desHostname ;
|
|
|
|
if ( this.rules.get(key) !== other.rules.get(key) ) {
|
2015-02-11 06:26:45 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
Matrix.prototype.setCell = function(srcHostname, desHostname, type, state) {
|
|
|
|
var bitOffset = typeBitOffsets[type];
|
|
|
|
var k = srcHostname + ' ' + desHostname;
|
2018-03-11 15:59:39 +01:00
|
|
|
var oldBitmap = this.rules.get(k) || 0;
|
2014-12-28 16:07:43 +01:00
|
|
|
var newBitmap = oldBitmap & ~(3 << bitOffset) | (state << bitOffset);
|
|
|
|
if ( newBitmap === oldBitmap ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( newBitmap === 0 ) {
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules.delete(k);
|
2014-12-28 16:07:43 +01:00
|
|
|
} else {
|
2018-03-11 15:59:39 +01:00
|
|
|
this.rules.set(k, newBitmap);
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
this.changed = true;
|
2014-12-28 16:07:43 +01:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-12-31 16:47:19 +01:00
|
|
|
Matrix.prototype.unsetCell = function(srcHostname, desHostname, type) {
|
2014-12-28 16:07:43 +01:00
|
|
|
this.evaluateCellZY(srcHostname, desHostname, type);
|
2014-12-31 16:47:19 +01:00
|
|
|
if ( this.r === 0 ) {
|
2014-12-28 16:07:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this.setCell(srcHostname, desHostname, type, 0);
|
2018-03-11 15:59:39 +01:00
|
|
|
this.changed = true;
|
2014-12-28 16:07:43 +01:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2014-12-31 16:47:19 +01:00
|
|
|
// https://www.youtube.com/watch?v=Csewb_eIStY
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
Matrix.prototype.evaluateCell = function(srcHostname, desHostname, type) {
|
|
|
|
var key = srcHostname + ' ' + desHostname;
|
2018-03-11 15:59:39 +01:00
|
|
|
var bitmap = this.rules.get(key);
|
2014-12-28 16:07:43 +01:00
|
|
|
if ( bitmap === undefined ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return bitmap >> typeBitOffsets[type] & 3;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.clearRegisters = function() {
|
|
|
|
this.r = 0;
|
2015-01-08 16:37:19 +01:00
|
|
|
this.type = this.y = this.z = '';
|
2014-12-31 23:26:17 +01:00
|
|
|
return this;
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-01-08 16:37:19 +01:00
|
|
|
var is3rdParty = function(srcHostname, desHostname) {
|
2015-04-02 04:13:13 +02:00
|
|
|
// If at least one is party-less, the relation can't be labelled
|
|
|
|
// "3rd-party"
|
|
|
|
if ( desHostname === '*' || srcHostname === '*' || srcHostname === '' ) {
|
2015-02-04 18:51:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
2015-03-31 13:51:01 +02:00
|
|
|
|
2015-04-02 04:13:13 +02:00
|
|
|
// No domain can very well occurs, for examples:
|
2015-03-31 13:51:01 +02:00
|
|
|
// - localhost
|
|
|
|
// - file-scheme
|
|
|
|
// etc.
|
2015-04-02 04:13:13 +02:00
|
|
|
var srcDomain = domainFromHostname(srcHostname) || srcHostname;
|
2015-03-31 13:51:01 +02:00
|
|
|
|
2015-12-15 16:40:40 +01:00
|
|
|
if ( desHostname.endsWith(srcDomain) === false ) {
|
2015-01-06 14:01:15 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-01-08 16:37:19 +01:00
|
|
|
// Do not confuse 'example.com' with 'anotherexample.com'
|
2015-01-26 10:27:58 +01:00
|
|
|
return desHostname.length !== srcDomain.length &&
|
2015-01-08 16:37:19 +01:00
|
|
|
desHostname.charAt(desHostname.length - srcDomain.length - 1) !== '.';
|
2015-01-06 14:01:15 +01:00
|
|
|
};
|
|
|
|
|
2015-01-08 16:37:19 +01:00
|
|
|
var domainFromHostname = µBlock.URI.domainFromHostname;
|
|
|
|
|
2015-01-06 14:01:15 +01:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2016-11-12 19:42:36 +01:00
|
|
|
Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type, broadener) {
|
2015-02-04 18:51:43 +01:00
|
|
|
this.type = type;
|
2014-12-28 16:07:43 +01:00
|
|
|
var bitOffset = typeBitOffsets[type];
|
|
|
|
var s = srcHostname;
|
|
|
|
var v;
|
|
|
|
for (;;) {
|
|
|
|
this.z = s;
|
2018-03-11 15:59:39 +01:00
|
|
|
v = this.rules.get(s + ' ' + desHostname);
|
2014-12-28 16:07:43 +01:00
|
|
|
if ( v !== undefined ) {
|
2015-07-12 14:15:09 +02:00
|
|
|
v = v >>> bitOffset & 3;
|
2014-12-28 16:07:43 +01:00
|
|
|
if ( v !== 0 ) {
|
2015-02-04 18:51:43 +01:00
|
|
|
this.r = v;
|
2014-12-28 16:07:43 +01:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
2016-11-12 19:42:36 +01:00
|
|
|
s = broadener(s);
|
|
|
|
if ( s === '' ) { break; }
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
|
|
|
// srcHostname is '*' at this point
|
2015-02-04 18:51:43 +01:00
|
|
|
this.r = 0;
|
2014-12-28 16:07:43 +01:00
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.evaluateCellZY = function(srcHostname, desHostname, type) {
|
2016-11-12 19:42:36 +01:00
|
|
|
// Pathological cases.
|
2014-12-28 16:07:43 +01:00
|
|
|
var d = desHostname;
|
2015-12-01 00:50:22 +01:00
|
|
|
if ( d === '' ) {
|
|
|
|
this.r = 0;
|
2017-05-12 16:35:11 +02:00
|
|
|
return 0;
|
2015-12-01 00:50:22 +01:00
|
|
|
}
|
2016-11-12 19:42:36 +01:00
|
|
|
|
|
|
|
// Prepare broadening handlers -- depends on whether we are dealing with
|
|
|
|
// a hostname or IP address.
|
|
|
|
var broadenSource = selectHostnameBroadener(srcHostname),
|
|
|
|
broadenDestination = selectHostnameBroadener(desHostname);
|
|
|
|
|
|
|
|
// Precedence: from most specific to least specific
|
|
|
|
|
|
|
|
// Specific-destination, any party, any type
|
2015-02-04 15:03:34 +01:00
|
|
|
while ( d !== '*' ) {
|
2014-12-28 16:07:43 +01:00
|
|
|
this.y = d;
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, d, '*', broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2016-11-12 19:42:36 +01:00
|
|
|
d = broadenDestination(d);
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
|
|
|
|
2015-02-04 18:51:43 +01:00
|
|
|
var thirdParty = is3rdParty(srcHostname, desHostname);
|
|
|
|
|
|
|
|
// Any destination
|
2014-12-28 16:07:43 +01:00
|
|
|
this.y = '*';
|
2015-01-06 14:01:15 +01:00
|
|
|
|
2015-02-04 18:51:43 +01:00
|
|
|
// Specific party
|
|
|
|
if ( thirdParty ) {
|
|
|
|
// 3rd-party, specific type
|
2015-07-27 15:20:47 +02:00
|
|
|
if ( type === 'script' ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, '*', '3p-script', broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2015-02-04 18:51:43 +01:00
|
|
|
} else if ( type === 'sub_frame' ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, '*', '3p-frame', broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2015-02-04 18:51:43 +01:00
|
|
|
}
|
|
|
|
// 3rd-party, any type
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, '*', '3p', broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2015-02-04 18:51:43 +01:00
|
|
|
} else if ( type === 'script' ) {
|
|
|
|
// 1st party, specific type
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, '*', '1p-script', broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2015-01-06 14:01:15 +01:00
|
|
|
}
|
2015-02-04 18:51:43 +01:00
|
|
|
|
|
|
|
// Any destination, any party, specific type
|
2015-01-08 16:37:19 +01:00
|
|
|
if ( supportedDynamicTypes.hasOwnProperty(type) ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, '*', type, broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2015-01-08 02:42:19 +01:00
|
|
|
}
|
|
|
|
|
2015-02-04 18:51:43 +01:00
|
|
|
// Any destination, any party, any type
|
2017-05-12 16:35:11 +02:00
|
|
|
if ( this.evaluateCellZ(srcHostname, '*', '*', broadenSource) !== 0 ) {
|
|
|
|
return this.r;
|
|
|
|
}
|
2015-02-04 06:04:43 +01:00
|
|
|
|
2015-01-08 16:37:19 +01:00
|
|
|
this.type = '';
|
2017-05-12 16:35:11 +02:00
|
|
|
return 0;
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// http://youtu.be/gSGk1bQ9rcU?t=25m6s
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-02-06 05:14:12 +01:00
|
|
|
Matrix.prototype.mustAllowCellZY = function(srcHostname, desHostname, type) {
|
2017-05-12 16:35:11 +02:00
|
|
|
return this.evaluateCellZY(srcHostname, desHostname, type) === 2;
|
2015-02-06 05:14:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
Matrix.prototype.mustBlockOrAllow = function() {
|
|
|
|
return this.r === 1 || this.r === 2;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-02-06 05:14:12 +01:00
|
|
|
Matrix.prototype.mustBlock = function() {
|
|
|
|
return this.r === 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-12-30 22:36:29 +01:00
|
|
|
Matrix.prototype.mustAbort = function() {
|
|
|
|
return this.r === 3;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
Matrix.prototype.lookupRuleData = function(src, des, type) {
|
|
|
|
var r = this.evaluateCellZY(src, des, type);
|
|
|
|
if ( r === 0 ) {
|
|
|
|
return null;
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
return {
|
|
|
|
src: this.z,
|
|
|
|
des: this.y,
|
|
|
|
type: this.type,
|
|
|
|
action: r === 1 ? 'block' : (r === 2 ? 'allow' : 'noop')
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.toLogData = function() {
|
|
|
|
if ( this.r === 0 || this.type === '' ) {
|
|
|
|
return;
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
var logData = {
|
|
|
|
source: 'dynamicHost',
|
|
|
|
result: this.r,
|
|
|
|
raw: this.z + ' ' +
|
|
|
|
this.y + ' ' +
|
|
|
|
this.type + ' ' +
|
|
|
|
this.intToActionMap.get(this.r)
|
|
|
|
};
|
|
|
|
return logData;
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
Matrix.prototype.intToActionMap = new Map([
|
|
|
|
[ 1, ' block' ],
|
|
|
|
[ 2, ' allow' ],
|
|
|
|
[ 3, ' noop' ]
|
|
|
|
]);
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.srcHostnameFromRule = function(rule) {
|
|
|
|
return rule.slice(0, rule.indexOf(' '));
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.desHostnameFromRule = function(rule) {
|
|
|
|
return rule.slice(rule.indexOf(' ') + 1);
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
Matrix.prototype.toArray = function() {
|
2017-05-04 01:43:09 +02:00
|
|
|
var out = [],
|
|
|
|
toUnicode = punycode.toUnicode;
|
2018-03-11 15:59:39 +01:00
|
|
|
for ( var key of this.rules.keys() ) {
|
|
|
|
var srcHostname = this.srcHostnameFromRule(key);
|
|
|
|
var desHostname = this.desHostnameFromRule(key);
|
|
|
|
for ( var type in typeBitOffsets ) {
|
|
|
|
if ( typeBitOffsets.hasOwnProperty(type) === false ) { continue; }
|
|
|
|
var val = this.evaluateCell(srcHostname, desHostname, type);
|
2017-05-04 01:43:09 +02:00
|
|
|
if ( val === 0 ) { continue; }
|
|
|
|
if ( srcHostname.indexOf('xn--') !== -1 ) {
|
|
|
|
srcHostname = toUnicode(srcHostname);
|
|
|
|
}
|
|
|
|
if ( desHostname.indexOf('xn--') !== -1 ) {
|
|
|
|
desHostname = toUnicode(desHostname);
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
|
|
|
out.push(
|
2017-05-04 01:43:09 +02:00
|
|
|
srcHostname + ' ' +
|
|
|
|
desHostname + ' ' +
|
2014-12-28 16:07:43 +01:00
|
|
|
type + ' ' +
|
2014-12-31 23:26:17 +01:00
|
|
|
actionToNameMap[val]
|
2014-12-28 16:07:43 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
return out;
|
|
|
|
};
|
|
|
|
|
|
|
|
Matrix.prototype.toString = function() {
|
|
|
|
return this.toArray().join('\n');
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
Matrix.prototype.fromString = function(text, append) {
|
2018-03-11 15:59:39 +01:00
|
|
|
var lineIter = new µBlock.LineIterator(text);
|
|
|
|
if ( append !== true ) { this.reset(); }
|
|
|
|
while ( lineIter.eot() === false ) {
|
|
|
|
this.addFromRuleParts(lineIter.next().trim().split(/\s+/));
|
2014-12-31 23:26:17 +01:00
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
};
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
/******************************************************************************/
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
Matrix.prototype.validateRuleParts = function(parts) {
|
|
|
|
if ( parts.length < 4 ) { return; }
|
2015-05-21 20:15:17 +02:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
// Ignore hostname-based switch rules
|
|
|
|
if ( parts[0].endsWith(':') ) { return; }
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
// Ignore URL-based rules
|
|
|
|
if ( parts[1].indexOf('/') !== -1 ) { return; }
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
if ( typeBitOffsets.hasOwnProperty(parts[2]) === false ) { return; }
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
if ( nameToActionMap.hasOwnProperty(parts[3]) === false ) { return; }
|
2014-12-31 23:26:17 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/840
|
|
|
|
// Discard invalid rules
|
|
|
|
if ( parts[1] !== '*' && parts[2] !== '*' ) { return; }
|
2015-05-21 20:15:17 +02:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
// Performance: avoid punycoding if hostnames are made only of ASCII chars.
|
|
|
|
if ( reNotASCII.test(parts[0]) ) { parts[0] = punycode.toASCII(parts[0]); }
|
|
|
|
if ( reNotASCII.test(parts[1]) ) { parts[1] = punycode.toASCII(parts[1]); }
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/1082
|
|
|
|
// Discard rules with invalid hostnames
|
|
|
|
if (
|
|
|
|
(parts[0] !== '*' && reBadHostname.test(parts[0])) ||
|
|
|
|
(parts[1] !== '*' && reBadHostname.test(parts[1]))
|
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
2015-03-23 23:49:28 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
return parts;
|
|
|
|
};
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
/******************************************************************************/
|
2015-02-25 02:27:47 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
Matrix.prototype.addFromRuleParts = function(parts) {
|
|
|
|
if ( this.validateRuleParts(parts) !== undefined ) {
|
|
|
|
this.setCell(parts[0], parts[1], parts[2], nameToActionMap[parts[3]]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
Matrix.prototype.removeFromRuleParts = function(parts) {
|
|
|
|
if ( this.validateRuleParts(parts) !== undefined ) {
|
|
|
|
this.setCell(parts[0], parts[1], parts[2], 0);
|
|
|
|
return true;
|
2014-12-28 16:07:43 +01:00
|
|
|
}
|
2018-03-11 15:59:39 +01:00
|
|
|
return false;
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2018-03-11 15:59:39 +01:00
|
|
|
var magicId = 1;
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
Matrix.prototype.toSelfie = function() {
|
|
|
|
return {
|
|
|
|
magicId: magicId,
|
2018-03-11 15:59:39 +01:00
|
|
|
rules: Array.from(this.rules)
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
Matrix.prototype.fromSelfie = function(selfie) {
|
2018-03-11 15:59:39 +01:00
|
|
|
if ( selfie.magicId !== magicId ) { return false; }
|
|
|
|
this.rules = new Map(selfie.rules);
|
|
|
|
this.changed = true;
|
|
|
|
return true;
|
2014-12-28 16:07:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-02-11 06:26:45 +01:00
|
|
|
return Matrix;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// http://youtu.be/5-K8R1hDG9E?t=31m1s
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2015-02-11 06:26:45 +01:00
|
|
|
|
|
|
|
µBlock.sessionFirewall = new µBlock.Firewall();
|
|
|
|
µBlock.permanentFirewall = new µBlock.Firewall();
|
|
|
|
|
|
|
|
/******************************************************************************/
|