mirror of https://github.com/gorhill/uBlock.git
[mv3] Add support for redirect= filters
This adds support for `redirect=` filters. As with `removeparam=` filters, `redirect=` filters can only be enforced when the default filtering mode is set to Optimal or Complete, since these filters require broad host permissions to be enforced by the DNR engine. `redirect-rule=` filters are not supported since there is no corresponding DNR syntax. Additionally, fixed the dropping of whole network filters even though those filters are still useful despite not being completely enforceable -- for example a filter with a single (unsupported) domain using entity syntax in its `domain=` option should not be wholly dropped when there are other valid domains in the list.
This commit is contained in:
parent
5a9cd724ca
commit
985ea24e82
|
@ -291,9 +291,9 @@ async function init() {
|
||||||
const div = qs$('#templates .rulesetDetails').cloneNode(true);
|
const div = qs$('#templates .rulesetDetails').cloneNode(true);
|
||||||
dom.text(qs$('h1', div), details.name);
|
dom.text(qs$('h1', div), details.name);
|
||||||
const { rules, filters, css } = details;
|
const { rules, filters, css } = details;
|
||||||
let ruleCount = rules.plain + rules.regexes;
|
let ruleCount = rules.plain + rules.regex;
|
||||||
if ( popupPanelData.hasOmnipotence ) {
|
if ( popupPanelData.hasOmnipotence ) {
|
||||||
ruleCount += rules.removeparams;
|
ruleCount += rules.removeparam + rules.redirect;
|
||||||
}
|
}
|
||||||
dom.text(
|
dom.text(
|
||||||
qs$('p', div),
|
qs$('p', div),
|
||||||
|
|
|
@ -33,8 +33,10 @@ import { fetchJSON } from './fetch.js';
|
||||||
const RULE_REALM_SIZE = 1000000;
|
const RULE_REALM_SIZE = 1000000;
|
||||||
const REGEXES_REALM_START = 1000000;
|
const REGEXES_REALM_START = 1000000;
|
||||||
const REGEXES_REALM_END = REGEXES_REALM_START + RULE_REALM_SIZE;
|
const REGEXES_REALM_END = REGEXES_REALM_START + RULE_REALM_SIZE;
|
||||||
const REMOVEPARAMS_REALM_START = 2000000;
|
const REMOVEPARAMS_REALM_START = REGEXES_REALM_END;
|
||||||
const REMOVEPARAMS_REALM_END = REMOVEPARAMS_REALM_START + RULE_REALM_SIZE;
|
const REMOVEPARAMS_REALM_END = REMOVEPARAMS_REALM_START + RULE_REALM_SIZE;
|
||||||
|
const REDIRECT_REALM_START = REMOVEPARAMS_REALM_END;
|
||||||
|
const REDIRECT_REALM_END = REDIRECT_REALM_START + RULE_REALM_SIZE;
|
||||||
const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000;
|
const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000;
|
||||||
const BLOCKING_MODES_RULE_ID = TRUSTED_DIRECTIVE_BASE_RULE_ID + 1;
|
const BLOCKING_MODES_RULE_ID = TRUSTED_DIRECTIVE_BASE_RULE_ID + 1;
|
||||||
const CURRENT_CONFIG_BASE_RULE_ID = 9000000;
|
const CURRENT_CONFIG_BASE_RULE_ID = 9000000;
|
||||||
|
@ -100,8 +102,8 @@ async function updateRegexRules() {
|
||||||
// Fetch regexes for all enabled rulesets
|
// Fetch regexes for all enabled rulesets
|
||||||
const toFetch = [];
|
const toFetch = [];
|
||||||
for ( const details of rulesetDetails ) {
|
for ( const details of rulesetDetails ) {
|
||||||
if ( details.rules.regexes === 0 ) { continue; }
|
if ( details.rules.regex === 0 ) { continue; }
|
||||||
toFetch.push(fetchJSON(`/rulesets/regex/${details.id}.regexes`));
|
toFetch.push(fetchJSON(`/rulesets/regex/${details.id}`));
|
||||||
}
|
}
|
||||||
const regexRulesets = await Promise.all(toFetch);
|
const regexRulesets = await Promise.all(toFetch);
|
||||||
|
|
||||||
|
@ -195,8 +197,8 @@ async function updateRemoveparamRules() {
|
||||||
// Fetch removeparam rules for all enabled rulesets
|
// Fetch removeparam rules for all enabled rulesets
|
||||||
const toFetch = [];
|
const toFetch = [];
|
||||||
for ( const details of rulesetDetails ) {
|
for ( const details of rulesetDetails ) {
|
||||||
if ( details.rules.removeparams === 0 ) { continue; }
|
if ( details.rules.removeparam === 0 ) { continue; }
|
||||||
toFetch.push(fetchJSON(`/rulesets/removeparam/${details.id}.removeparams`));
|
toFetch.push(fetchJSON(`/rulesets/removeparam/${details.id}`));
|
||||||
}
|
}
|
||||||
const removeparamRulesets = await Promise.all(toFetch);
|
const removeparamRulesets = await Promise.all(toFetch);
|
||||||
|
|
||||||
|
@ -253,17 +255,90 @@ async function updateRemoveparamRules() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
async function updateRedirectRules() {
|
||||||
|
const [
|
||||||
|
hasOmnipotence,
|
||||||
|
rulesetDetails,
|
||||||
|
dynamicRuleMap,
|
||||||
|
] = await Promise.all([
|
||||||
|
browser.permissions.contains({ origins: [ '<all_urls>' ] }),
|
||||||
|
getEnabledRulesetsDetails(),
|
||||||
|
getDynamicRules(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Fetch redirect rules for all enabled rulesets
|
||||||
|
const toFetch = [];
|
||||||
|
for ( const details of rulesetDetails ) {
|
||||||
|
if ( details.rules.redirect === 0 ) { continue; }
|
||||||
|
toFetch.push(fetchJSON(`/rulesets/redirect/${details.id}`));
|
||||||
|
}
|
||||||
|
const redirectRulesets = await Promise.all(toFetch);
|
||||||
|
|
||||||
|
// Redirect rules can only be enforced with omnipotence
|
||||||
|
const newRules = [];
|
||||||
|
if ( hasOmnipotence ) {
|
||||||
|
let redirectRuleId = REDIRECT_REALM_START;
|
||||||
|
for ( const rules of redirectRulesets ) {
|
||||||
|
if ( Array.isArray(rules) === false ) { continue; }
|
||||||
|
for ( const rule of rules ) {
|
||||||
|
rule.id = redirectRuleId++;
|
||||||
|
newRules.push(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add redirect rules to dynamic ruleset without affecting rules
|
||||||
|
// outside redirect rules realm.
|
||||||
|
const newRuleMap = new Map(newRules.map(rule => [ rule.id, rule ]));
|
||||||
|
const addRules = [];
|
||||||
|
const removeRuleIds = [];
|
||||||
|
|
||||||
|
for ( const oldRule of dynamicRuleMap.values() ) {
|
||||||
|
if ( oldRule.id < REDIRECT_REALM_START ) { continue; }
|
||||||
|
if ( oldRule.id >= REDIRECT_REALM_END ) { continue; }
|
||||||
|
const newRule = newRuleMap.get(oldRule.id);
|
||||||
|
if ( newRule === undefined ) {
|
||||||
|
removeRuleIds.push(oldRule.id);
|
||||||
|
dynamicRuleMap.delete(oldRule.id);
|
||||||
|
} else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) {
|
||||||
|
removeRuleIds.push(oldRule.id);
|
||||||
|
addRules.push(newRule);
|
||||||
|
dynamicRuleMap.set(oldRule.id, newRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const newRule of newRuleMap.values() ) {
|
||||||
|
if ( dynamicRuleMap.has(newRule.id) ) { continue; }
|
||||||
|
addRules.push(newRule);
|
||||||
|
dynamicRuleMap.set(newRule.id, newRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; }
|
||||||
|
|
||||||
|
if ( removeRuleIds.length !== 0 ) {
|
||||||
|
console.info(`Remove ${removeRuleIds.length} DNR redirect rules`);
|
||||||
|
}
|
||||||
|
if ( addRules.length !== 0 ) {
|
||||||
|
console.info(`Add ${addRules.length} DNR redirect rules`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dnr.updateDynamicRules({ addRules, removeRuleIds });
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
async function updateDynamicRules() {
|
async function updateDynamicRules() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
updateRegexRules(),
|
updateRegexRules(),
|
||||||
updateRemoveparamRules(),
|
updateRemoveparamRules(),
|
||||||
|
updateRedirectRules(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
async function defaultRulesetsFromLanguage() {
|
async function defaultRulesetsFromLanguage() {
|
||||||
const out = [ 'default' ];
|
const out = [ 'default', 'cname-trackers' ];
|
||||||
|
|
||||||
const dropCountry = lang => {
|
const dropCountry = lang => {
|
||||||
const pos = lang.indexOf('-');
|
const pos = lang.indexOf('-');
|
||||||
|
@ -335,10 +410,7 @@ async function enableRulesets(ids) {
|
||||||
}
|
}
|
||||||
await dnr.updateEnabledRulesets({ enableRulesetIds, disableRulesetIds });
|
await dnr.updateEnabledRulesets({ enableRulesetIds, disableRulesetIds });
|
||||||
|
|
||||||
return Promise.all([
|
return updateDynamicRules();
|
||||||
updateRegexRules(),
|
|
||||||
updateRemoveparamRules(),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -47,9 +47,9 @@ function rulesetStats(rulesetId) {
|
||||||
const rulesetDetails = rulesetMap.get(rulesetId);
|
const rulesetDetails = rulesetMap.get(rulesetId);
|
||||||
if ( rulesetDetails === undefined ) { return; }
|
if ( rulesetDetails === undefined ) { return; }
|
||||||
const { rules, filters } = rulesetDetails;
|
const { rules, filters } = rulesetDetails;
|
||||||
let ruleCount = rules.plain + rules.regexes;
|
let ruleCount = rules.plain + rules.regex;
|
||||||
if ( canRemoveParams ) {
|
if ( canRemoveParams ) {
|
||||||
ruleCount += rules.removeparams;
|
ruleCount += rules.removeparam + rules.redirect;
|
||||||
}
|
}
|
||||||
const filterCount = filters.accepted;
|
const filterCount = filters.accepted;
|
||||||
return { ruleCount, filterCount };
|
return { ruleCount, filterCount };
|
||||||
|
|
|
@ -37,5 +37,6 @@
|
||||||
"scripting"
|
"scripting"
|
||||||
],
|
],
|
||||||
"short_name": "uBO Lite",
|
"short_name": "uBO Lite",
|
||||||
"version": "0.1"
|
"version": "0.1",
|
||||||
|
"web_accessible_resources": []
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import https from 'https';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import process from 'process';
|
import process from 'process';
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
|
import redirectResourcesMap from './js/redirect-resources.js';
|
||||||
import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js';
|
import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js';
|
||||||
import { StaticFilteringParser } from './js/static-filtering-parser.js';
|
import { StaticFilteringParser } from './js/static-filtering-parser.js';
|
||||||
import { fnameFromFileId } from './js/utils.js';
|
import { fnameFromFileId } from './js/utils.js';
|
||||||
|
@ -142,6 +143,14 @@ const writeFile = async (fname, data) => {
|
||||||
return promise;
|
return promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const copyFile = async (from, to) => {
|
||||||
|
const dir = path.dirname(to);
|
||||||
|
await fs.mkdir(dir, { recursive: true });
|
||||||
|
const promise = fs.copyFile(from, to);
|
||||||
|
writeOps.push(promise);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
const writeOps = [];
|
const writeOps = [];
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -153,6 +162,7 @@ const proceduralDetails = new Map();
|
||||||
const scriptletStats = new Map();
|
const scriptletStats = new Map();
|
||||||
const specificDetails = new Map();
|
const specificDetails = new Map();
|
||||||
const genericDetails = new Map();
|
const genericDetails = new Map();
|
||||||
|
const requiredRedirectResources = new Set();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -265,7 +275,12 @@ async function processNetworkFilters(assetDetails, network) {
|
||||||
isUnsupported(rule) === false &&
|
isUnsupported(rule) === false &&
|
||||||
isRedirect(rule)
|
isRedirect(rule)
|
||||||
);
|
);
|
||||||
log(`\tredirect-rule= (discarded): ${redirects.length}`);
|
redirects.forEach(rule => {
|
||||||
|
requiredRedirectResources.add(
|
||||||
|
rule.action.redirect.extensionPath.replace(/^\/+/, '')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
log(`\tredirect=: ${redirects.length}`);
|
||||||
|
|
||||||
const headers = rules.filter(rule =>
|
const headers = rules.filter(rule =>
|
||||||
isUnsupported(rule) === false &&
|
isUnsupported(rule) === false &&
|
||||||
|
@ -294,25 +309,33 @@ async function processNetworkFilters(assetDetails, network) {
|
||||||
|
|
||||||
if ( regexes.length !== 0 ) {
|
if ( regexes.length !== 0 ) {
|
||||||
writeFile(
|
writeFile(
|
||||||
`${rulesetDir}/regex/${assetDetails.id}.regexes.json`,
|
`${rulesetDir}/regex/${assetDetails.id}.json`,
|
||||||
`${JSON.stringify(regexes, replacer)}\n`
|
`${JSON.stringify(regexes, replacer)}\n`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( removeparamsGood.length !== 0 ) {
|
if ( removeparamsGood.length !== 0 ) {
|
||||||
writeFile(
|
writeFile(
|
||||||
`${rulesetDir}/removeparam/${assetDetails.id}.removeparams.json`,
|
`${rulesetDir}/removeparam/${assetDetails.id}.json`,
|
||||||
`${JSON.stringify(removeparamsGood, replacer)}\n`
|
`${JSON.stringify(removeparamsGood, replacer)}\n`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( redirects.length !== 0 ) {
|
||||||
|
writeFile(
|
||||||
|
`${rulesetDir}/redirect/${assetDetails.id}.json`,
|
||||||
|
`${JSON.stringify(redirects, replacer)}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total: rules.length,
|
total: rules.length,
|
||||||
plain: plainGood.length,
|
plain: plainGood.length,
|
||||||
discarded: redirects.length + headers.length + removeparamsBad.length,
|
discarded: redirects.length + headers.length + removeparamsBad.length,
|
||||||
rejected: bad.length,
|
rejected: bad.length,
|
||||||
regexes: regexes.length,
|
regex: regexes.length,
|
||||||
removeparams: removeparamsGood.length,
|
removeparam: removeparamsGood.length,
|
||||||
|
redirect: redirects.length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,9 +925,25 @@ async function rulesetFromURLs(assetDetails) {
|
||||||
assetDetails.text = text;
|
assetDetails.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const extensionPaths = [];
|
||||||
|
for ( const [ fname, details ] of redirectResourcesMap ) {
|
||||||
|
const path = `/web_accessible_resources/${fname}`;
|
||||||
|
extensionPaths.push([ fname, path ]);
|
||||||
|
if ( details.alias === undefined ) { continue; }
|
||||||
|
if ( typeof details.alias === 'string' ) {
|
||||||
|
extensionPaths.push([ details.alias, path ]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( Array.isArray(details.alias) === false ) { continue; }
|
||||||
|
for ( const alias of details.alias ) {
|
||||||
|
extensionPaths.push([ alias, path ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const results = await dnrRulesetFromRawLists(
|
const results = await dnrRulesetFromRawLists(
|
||||||
[ { name: assetDetails.id, text: assetDetails.text } ],
|
[ { name: assetDetails.id, text: assetDetails.text } ],
|
||||||
{ env }
|
{ env, extensionPaths }
|
||||||
);
|
);
|
||||||
|
|
||||||
const netStats = await processNetworkFilters(
|
const netStats = await processNetworkFilters(
|
||||||
|
@ -972,8 +1011,9 @@ async function rulesetFromURLs(assetDetails) {
|
||||||
rules: {
|
rules: {
|
||||||
total: netStats.total,
|
total: netStats.total,
|
||||||
plain: netStats.plain,
|
plain: netStats.plain,
|
||||||
regexes: netStats.regexes,
|
regex: netStats.regex,
|
||||||
removeparams: netStats.removeparams,
|
removeparam: netStats.removeparam,
|
||||||
|
redirect: netStats.redirect,
|
||||||
discarded: netStats.discarded,
|
discarded: netStats.discarded,
|
||||||
rejected: netStats.rejected,
|
rejected: netStats.rejected,
|
||||||
},
|
},
|
||||||
|
@ -1113,6 +1153,7 @@ async function main() {
|
||||||
urls: [ 'https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/combined_disguised_trackers.txt' ],
|
urls: [ 'https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/combined_disguised_trackers.txt' ],
|
||||||
homeURL: 'https://github.com/AdguardTeam/cname-trackers#cname-cloaked-trackers',
|
homeURL: 'https://github.com/AdguardTeam/cname-trackers#cname-cloaked-trackers',
|
||||||
});
|
});
|
||||||
|
|
||||||
await rulesetFromURLs({
|
await rulesetFromURLs({
|
||||||
id: 'stevenblack-hosts',
|
id: 'stevenblack-hosts',
|
||||||
name: 'Steven Black\'s hosts file',
|
name: 'Steven Black\'s hosts file',
|
||||||
|
@ -1159,16 +1200,30 @@ async function main() {
|
||||||
`${JSON.stringify(genericDetails, jsonSetMapReplacer, 1)}\n`
|
`${JSON.stringify(genericDetails, jsonSetMapReplacer, 1)}\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Copy required redirect resources
|
||||||
|
for ( const path of requiredRedirectResources ) {
|
||||||
|
copyFile(`./${path}`, `${outputDir}/${path}`);
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(writeOps);
|
await Promise.all(writeOps);
|
||||||
|
|
||||||
// Patch manifest
|
// Patch manifest
|
||||||
|
// Patch declarative_net_request key
|
||||||
manifest.declarative_net_request = { rule_resources: ruleResources };
|
manifest.declarative_net_request = { rule_resources: ruleResources };
|
||||||
|
// Patch web_accessible_resources key
|
||||||
|
manifest.web_accessible_resources = [{
|
||||||
|
resources: Array.from(requiredRedirectResources).map(path => `/${path}`),
|
||||||
|
matches: [ '<all_urls>' ],
|
||||||
|
use_dynamic_url: true,
|
||||||
|
}];
|
||||||
|
// Patch version key
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const yearPart = now.getUTCFullYear() - 2000;
|
const yearPart = now.getUTCFullYear() - 2000;
|
||||||
const monthPart = (now.getUTCMonth() + 1) * 1000;
|
const monthPart = (now.getUTCMonth() + 1) * 1000;
|
||||||
const dayPart = now.getUTCDate() * 10;
|
const dayPart = now.getUTCDate() * 10;
|
||||||
const hourPart = Math.floor(now.getUTCHours() / 3) + 1;
|
const hourPart = Math.floor(now.getUTCHours() / 3) + 1;
|
||||||
manifest.version = manifest.version + `.${yearPart}.${monthPart + dayPart + hourPart}`;
|
manifest.version = manifest.version + `.${yearPart}.${monthPart + dayPart + hourPart}`;
|
||||||
|
// Commit changes
|
||||||
await fs.writeFile(
|
await fs.writeFile(
|
||||||
`${outputDir}/manifest.json`,
|
`${outputDir}/manifest.json`,
|
||||||
JSON.stringify(manifest, null, 2) + '\n'
|
JSON.stringify(manifest, null, 2) + '\n'
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
import redirectableResources from './redirect-resources.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
LineIterator,
|
LineIterator,
|
||||||
orphanizeString,
|
orphanizeString,
|
||||||
|
@ -30,165 +32,6 @@ import {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// The resources referenced below are found in ./web_accessible_resources/
|
|
||||||
//
|
|
||||||
// The content of the resources which declare a `data` property will be loaded
|
|
||||||
// in memory, and converted to a suitable internal format depending on the
|
|
||||||
// type of the loaded data. The `data` property allows for manual injection
|
|
||||||
// through `+js(...)`, or for redirection to a data: URI when a redirection
|
|
||||||
// to a web accessible resource is not desirable.
|
|
||||||
|
|
||||||
const redirectableResources = new Map([
|
|
||||||
[ '1x1.gif', {
|
|
||||||
alias: '1x1-transparent.gif',
|
|
||||||
data: 'blob',
|
|
||||||
} ],
|
|
||||||
[ '2x2.png', {
|
|
||||||
alias: '2x2-transparent.png',
|
|
||||||
data: 'blob',
|
|
||||||
} ],
|
|
||||||
[ '3x2.png', {
|
|
||||||
alias: '3x2-transparent.png',
|
|
||||||
data: 'blob',
|
|
||||||
} ],
|
|
||||||
[ '32x32.png', {
|
|
||||||
alias: '32x32-transparent.png',
|
|
||||||
data: 'blob',
|
|
||||||
} ],
|
|
||||||
[ 'addthis_widget.js', {
|
|
||||||
alias: 'addthis.com/addthis_widget.js',
|
|
||||||
} ],
|
|
||||||
[ 'amazon_ads.js', {
|
|
||||||
alias: 'amazon-adsystem.com/aax2/amzn_ads.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'amazon_apstag.js', {
|
|
||||||
} ],
|
|
||||||
[ 'ampproject_v0.js', {
|
|
||||||
alias: 'ampproject.org/v0.js',
|
|
||||||
} ],
|
|
||||||
[ 'chartbeat.js', {
|
|
||||||
alias: 'static.chartbeat.com/chartbeat.js',
|
|
||||||
} ],
|
|
||||||
[ 'click2load.html', {
|
|
||||||
params: [ 'aliasURL', 'url' ],
|
|
||||||
} ],
|
|
||||||
[ 'doubleclick_instream_ad_status.js', {
|
|
||||||
alias: 'doubleclick.net/instream/ad_status.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'empty', {
|
|
||||||
data: 'text', // Important!
|
|
||||||
} ],
|
|
||||||
[ 'fingerprint2.js', {
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'fingerprint3.js', {
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'google-analytics_analytics.js', {
|
|
||||||
alias: [
|
|
||||||
'google-analytics.com/analytics.js',
|
|
||||||
'googletagmanager_gtm.js',
|
|
||||||
'googletagmanager.com/gtm.js'
|
|
||||||
],
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'google-analytics_cx_api.js', {
|
|
||||||
alias: 'google-analytics.com/cx/api.js',
|
|
||||||
} ],
|
|
||||||
[ 'google-analytics_ga.js', {
|
|
||||||
alias: 'google-analytics.com/ga.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'google-analytics_inpage_linkid.js', {
|
|
||||||
alias: 'google-analytics.com/inpage_linkid.js',
|
|
||||||
} ],
|
|
||||||
[ 'google-ima.js', {
|
|
||||||
} ],
|
|
||||||
[ 'googlesyndication_adsbygoogle.js', {
|
|
||||||
alias: 'googlesyndication.com/adsbygoogle.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'googletagservices_gpt.js', {
|
|
||||||
alias: 'googletagservices.com/gpt.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'hd-main.js', {
|
|
||||||
} ],
|
|
||||||
[ 'ligatus_angular-tag.js', {
|
|
||||||
alias: 'ligatus.com/*/angular-tag.js',
|
|
||||||
} ],
|
|
||||||
[ 'mxpnl_mixpanel.js', {
|
|
||||||
} ],
|
|
||||||
[ 'monkeybroker.js', {
|
|
||||||
alias: 'd3pkae9owd2lcf.cloudfront.net/mb105.js',
|
|
||||||
} ],
|
|
||||||
[ 'noeval.js', {
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'noeval-silent.js', {
|
|
||||||
alias: 'silent-noeval.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'nobab.js', {
|
|
||||||
alias: 'bab-defuser.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'nobab2.js', {
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'nofab.js', {
|
|
||||||
alias: 'fuckadblock.js-3.2.0',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'noop-0.1s.mp3', {
|
|
||||||
alias: [ 'noopmp3-0.1s', 'abp-resource:blank-mp3' ],
|
|
||||||
data: 'blob',
|
|
||||||
} ],
|
|
||||||
[ 'noop-0.5s.mp3', {
|
|
||||||
} ],
|
|
||||||
[ 'noop-1s.mp4', {
|
|
||||||
alias: 'noopmp4-1s',
|
|
||||||
data: 'blob',
|
|
||||||
} ],
|
|
||||||
[ 'noop.html', {
|
|
||||||
alias: 'noopframe',
|
|
||||||
} ],
|
|
||||||
[ 'noop.js', {
|
|
||||||
alias: [ 'noopjs', 'abp-resource:blank-js' ],
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'noop.txt', {
|
|
||||||
alias: 'nooptext',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'noop-vmap1.0.xml', {
|
|
||||||
alias: 'noopvmap-1.0',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'outbrain-widget.js', {
|
|
||||||
alias: 'widgets.outbrain.com/outbrain.js',
|
|
||||||
} ],
|
|
||||||
[ 'popads.js', {
|
|
||||||
alias: 'popads.net.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'popads-dummy.js', {
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'prebid-ads.js', {
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
[ 'scorecardresearch_beacon.js', {
|
|
||||||
alias: 'scorecardresearch.com/beacon.js',
|
|
||||||
} ],
|
|
||||||
[ 'window.open-defuser.js', {
|
|
||||||
alias: 'nowoif.js',
|
|
||||||
data: 'text',
|
|
||||||
} ],
|
|
||||||
]);
|
|
||||||
|
|
||||||
const extToMimeMap = new Map([
|
const extToMimeMap = new Map([
|
||||||
[ 'gif', 'image/gif' ],
|
[ 'gif', 'image/gif' ],
|
||||||
[ 'html', 'text/html' ],
|
[ 'html', 'text/html' ],
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2015-present 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// The resources referenced below are found in ./web_accessible_resources/
|
||||||
|
//
|
||||||
|
// The content of the resources which declare a `data` property will be loaded
|
||||||
|
// in memory, and converted to a suitable internal format depending on the
|
||||||
|
// type of the loaded data. The `data` property allows for manual injection
|
||||||
|
// through `+js(...)`, or for redirection to a data: URI when a redirection
|
||||||
|
// to a web accessible resource is not desirable.
|
||||||
|
|
||||||
|
export default new Map([
|
||||||
|
[ '1x1.gif', {
|
||||||
|
alias: '1x1-transparent.gif',
|
||||||
|
data: 'blob',
|
||||||
|
} ],
|
||||||
|
[ '2x2.png', {
|
||||||
|
alias: '2x2-transparent.png',
|
||||||
|
data: 'blob',
|
||||||
|
} ],
|
||||||
|
[ '3x2.png', {
|
||||||
|
alias: '3x2-transparent.png',
|
||||||
|
data: 'blob',
|
||||||
|
} ],
|
||||||
|
[ '32x32.png', {
|
||||||
|
alias: '32x32-transparent.png',
|
||||||
|
data: 'blob',
|
||||||
|
} ],
|
||||||
|
[ 'addthis_widget.js', {
|
||||||
|
alias: 'addthis.com/addthis_widget.js',
|
||||||
|
} ],
|
||||||
|
[ 'amazon_ads.js', {
|
||||||
|
alias: 'amazon-adsystem.com/aax2/amzn_ads.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'amazon_apstag.js', {
|
||||||
|
} ],
|
||||||
|
[ 'ampproject_v0.js', {
|
||||||
|
alias: 'ampproject.org/v0.js',
|
||||||
|
} ],
|
||||||
|
[ 'chartbeat.js', {
|
||||||
|
alias: 'static.chartbeat.com/chartbeat.js',
|
||||||
|
} ],
|
||||||
|
[ 'click2load.html', {
|
||||||
|
params: [ 'aliasURL', 'url' ],
|
||||||
|
} ],
|
||||||
|
[ 'doubleclick_instream_ad_status.js', {
|
||||||
|
alias: 'doubleclick.net/instream/ad_status.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'empty', {
|
||||||
|
data: 'text', // Important!
|
||||||
|
} ],
|
||||||
|
[ 'fingerprint2.js', {
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'fingerprint3.js', {
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'google-analytics_analytics.js', {
|
||||||
|
alias: [
|
||||||
|
'google-analytics.com/analytics.js',
|
||||||
|
'googletagmanager_gtm.js',
|
||||||
|
'googletagmanager.com/gtm.js'
|
||||||
|
],
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'google-analytics_cx_api.js', {
|
||||||
|
alias: 'google-analytics.com/cx/api.js',
|
||||||
|
} ],
|
||||||
|
[ 'google-analytics_ga.js', {
|
||||||
|
alias: 'google-analytics.com/ga.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'google-analytics_inpage_linkid.js', {
|
||||||
|
alias: 'google-analytics.com/inpage_linkid.js',
|
||||||
|
} ],
|
||||||
|
[ 'google-ima.js', {
|
||||||
|
} ],
|
||||||
|
[ 'googlesyndication_adsbygoogle.js', {
|
||||||
|
alias: 'googlesyndication.com/adsbygoogle.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'googletagservices_gpt.js', {
|
||||||
|
alias: 'googletagservices.com/gpt.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'hd-main.js', {
|
||||||
|
} ],
|
||||||
|
[ 'ligatus_angular-tag.js', {
|
||||||
|
alias: 'ligatus.com/*/angular-tag.js',
|
||||||
|
} ],
|
||||||
|
[ 'mxpnl_mixpanel.js', {
|
||||||
|
} ],
|
||||||
|
[ 'monkeybroker.js', {
|
||||||
|
alias: 'd3pkae9owd2lcf.cloudfront.net/mb105.js',
|
||||||
|
} ],
|
||||||
|
[ 'noeval.js', {
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'noeval-silent.js', {
|
||||||
|
alias: 'silent-noeval.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'nobab.js', {
|
||||||
|
alias: 'bab-defuser.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'nobab2.js', {
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'nofab.js', {
|
||||||
|
alias: 'fuckadblock.js-3.2.0',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'noop-0.1s.mp3', {
|
||||||
|
alias: [ 'noopmp3-0.1s', 'abp-resource:blank-mp3' ],
|
||||||
|
data: 'blob',
|
||||||
|
} ],
|
||||||
|
[ 'noop-0.5s.mp3', {
|
||||||
|
} ],
|
||||||
|
[ 'noop-1s.mp4', {
|
||||||
|
alias: 'noopmp4-1s',
|
||||||
|
data: 'blob',
|
||||||
|
} ],
|
||||||
|
[ 'noop.html', {
|
||||||
|
alias: 'noopframe',
|
||||||
|
} ],
|
||||||
|
[ 'noop.js', {
|
||||||
|
alias: [ 'noopjs', 'abp-resource:blank-js' ],
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'noop.txt', {
|
||||||
|
alias: 'nooptext',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'noop-vmap1.0.xml', {
|
||||||
|
alias: 'noopvmap-1.0',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'outbrain-widget.js', {
|
||||||
|
alias: 'widgets.outbrain.com/outbrain.js',
|
||||||
|
} ],
|
||||||
|
[ 'popads.js', {
|
||||||
|
alias: 'popads.net.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'popads-dummy.js', {
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'prebid-ads.js', {
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
[ 'scorecardresearch_beacon.js', {
|
||||||
|
alias: 'scorecardresearch.com/beacon.js',
|
||||||
|
} ],
|
||||||
|
[ 'window.open-defuser.js', {
|
||||||
|
alias: 'nowoif.js',
|
||||||
|
data: 'text',
|
||||||
|
} ],
|
||||||
|
]);
|
|
@ -219,6 +219,9 @@ function addToDNR(context, list) {
|
||||||
});
|
});
|
||||||
const compiler = staticNetFilteringEngine.createCompiler(parser);
|
const compiler = staticNetFilteringEngine.createCompiler(parser);
|
||||||
|
|
||||||
|
// Can't enforce `redirect-rule=` with DNR
|
||||||
|
compiler.excludeOptions([ parser.OPTTokenRedirectRule ]);
|
||||||
|
|
||||||
writer.properties.set('name', list.name);
|
writer.properties.set('name', list.name);
|
||||||
compiler.start(writer);
|
compiler.start(writer);
|
||||||
|
|
||||||
|
|
|
@ -1742,8 +1742,7 @@ const FilterOriginEntityHit = class extends FilterOriginHit {
|
||||||
}
|
}
|
||||||
|
|
||||||
static dnrFromCompiled(args, rule) {
|
static dnrFromCompiled(args, rule) {
|
||||||
dnrAddRuleError(rule, `Entity not supported: ${args[1]}`);
|
dnrAddRuleError(rule, `FilterOriginEntityHit: Entity ${args[1]} not supported`);
|
||||||
super.dnrFromCompiled(args, rule);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1761,8 +1760,7 @@ const FilterOriginEntityMiss = class extends FilterOriginMiss {
|
||||||
}
|
}
|
||||||
|
|
||||||
static dnrFromCompiled(args, rule) {
|
static dnrFromCompiled(args, rule) {
|
||||||
dnrAddRuleError(rule, `Entity not supported: ${args[1]}`);
|
dnrAddRuleError(rule, `FilterOriginEntityMiss: Entity ${args[1]} not supported`);
|
||||||
super.dnrFromCompiled(args, rule);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2623,7 +2621,7 @@ const FilterStrictParty = class {
|
||||||
|
|
||||||
static dnrFromCompiled(args, rule) {
|
static dnrFromCompiled(args, rule) {
|
||||||
const partyness = args[1] === 0 ? 1 : 3;
|
const partyness = args[1] === 0 ? 1 : 3;
|
||||||
dnrAddRuleError(rule, `Strict partyness not supported: strict${partyness}p`);
|
dnrAddRuleError(rule, `FilterStrictParty: Strict partyness strict${partyness}p not supported`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static keyFromArgs(args) {
|
static keyFromArgs(args) {
|
||||||
|
@ -2891,6 +2889,7 @@ class FilterCompiler {
|
||||||
[ parser.OPTTokenWebrtc, bitFromType('unsupported') ],
|
[ parser.OPTTokenWebrtc, bitFromType('unsupported') ],
|
||||||
[ parser.OPTTokenWebsocket, bitFromType('websocket') ],
|
[ parser.OPTTokenWebsocket, bitFromType('websocket') ],
|
||||||
]);
|
]);
|
||||||
|
this.excludedOptionSet = new Set();
|
||||||
// These top 100 "bad tokens" are collated using the "miss" histogram
|
// These top 100 "bad tokens" are collated using the "miss" histogram
|
||||||
// from tokenHistograms(). The "score" is their occurrence among the
|
// from tokenHistograms(). The "score" is their occurrence among the
|
||||||
// 200K+ URLs used in the benchmark and executed against default
|
// 200K+ URLs used in the benchmark and executed against default
|
||||||
|
@ -3053,6 +3052,12 @@ class FilterCompiler {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
excludeOptions(options) {
|
||||||
|
for ( const option of options ) {
|
||||||
|
this.excludedOptionSet.add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/589
|
// https://github.com/chrisaljoudi/uBlock/issues/589
|
||||||
// Be ready to handle multiple negated types
|
// Be ready to handle multiple negated types
|
||||||
|
|
||||||
|
@ -3109,30 +3114,31 @@ class FilterCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
processOptions() {
|
processOptions() {
|
||||||
for ( let { id, val, not } of this.parser.netOptions() ) {
|
const { parser } = this;
|
||||||
|
for ( let { id, val, not } of parser.netOptions() ) {
|
||||||
switch ( id ) {
|
switch ( id ) {
|
||||||
case this.parser.OPTToken1p:
|
case parser.OPTToken1p:
|
||||||
this.processPartyOption(true, not);
|
this.processPartyOption(true, not);
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTToken1pStrict:
|
case parser.OPTToken1pStrict:
|
||||||
this.strictParty = this.strictParty === -1 ? 0 : 1;
|
this.strictParty = this.strictParty === -1 ? 0 : 1;
|
||||||
this.optionUnitBits |= this.STRICT_PARTY_BIT;
|
this.optionUnitBits |= this.STRICT_PARTY_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTToken3p:
|
case parser.OPTToken3p:
|
||||||
this.processPartyOption(false, not);
|
this.processPartyOption(false, not);
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTToken3pStrict:
|
case parser.OPTToken3pStrict:
|
||||||
this.strictParty = this.strictParty === 1 ? 0 : -1;
|
this.strictParty = this.strictParty === 1 ? 0 : -1;
|
||||||
this.optionUnitBits |= this.STRICT_PARTY_BIT;
|
this.optionUnitBits |= this.STRICT_PARTY_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenAll:
|
case parser.OPTTokenAll:
|
||||||
this.processTypeOption(-1);
|
this.processTypeOption(-1);
|
||||||
break;
|
break;
|
||||||
// https://github.com/uBlockOrigin/uAssets/issues/192
|
// https://github.com/uBlockOrigin/uAssets/issues/192
|
||||||
case this.parser.OPTTokenBadfilter:
|
case parser.OPTTokenBadfilter:
|
||||||
this.badFilter = true;
|
this.badFilter = true;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenCsp:
|
case parser.OPTTokenCsp:
|
||||||
if ( this.processModifierOption(id, val) === false ) {
|
if ( this.processModifierOption(id, val) === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3144,7 +3150,7 @@ class FilterCompiler {
|
||||||
// https://github.com/gorhill/uBlock/issues/2294
|
// https://github.com/gorhill/uBlock/issues/2294
|
||||||
// Detect and discard filter if domain option contains
|
// Detect and discard filter if domain option contains
|
||||||
// nonsensical characters.
|
// nonsensical characters.
|
||||||
case this.parser.OPTTokenDomain:
|
case parser.OPTTokenDomain:
|
||||||
this.domainOpt = this.processHostnameList(
|
this.domainOpt = this.processHostnameList(
|
||||||
val,
|
val,
|
||||||
0b1010,
|
0b1010,
|
||||||
|
@ -3153,73 +3159,76 @@ class FilterCompiler {
|
||||||
if ( this.domainOpt === '' ) { return false; }
|
if ( this.domainOpt === '' ) { return false; }
|
||||||
this.optionUnitBits |= this.DOMAIN_BIT;
|
this.optionUnitBits |= this.DOMAIN_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenDenyAllow:
|
case parser.OPTTokenDenyAllow:
|
||||||
this.denyallowOpt = this.processHostnameList(val, 0b0000);
|
this.denyallowOpt = this.processHostnameList(val, 0b0000);
|
||||||
if ( this.denyallowOpt === '' ) { return false; }
|
if ( this.denyallowOpt === '' ) { return false; }
|
||||||
this.optionUnitBits |= this.DENYALLOW_BIT;
|
this.optionUnitBits |= this.DENYALLOW_BIT;
|
||||||
break;
|
break;
|
||||||
// https://www.reddit.com/r/uBlockOrigin/comments/d6vxzj/
|
// https://www.reddit.com/r/uBlockOrigin/comments/d6vxzj/
|
||||||
// Add support for `elemhide`. Rarely used but it happens.
|
// Add support for `elemhide`. Rarely used but it happens.
|
||||||
case this.parser.OPTTokenEhide:
|
case parser.OPTTokenEhide:
|
||||||
this.processTypeOption(this.parser.OPTTokenShide, not);
|
this.processTypeOption(parser.OPTTokenShide, not);
|
||||||
this.processTypeOption(this.parser.OPTTokenGhide, not);
|
this.processTypeOption(parser.OPTTokenGhide, not);
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenHeader:
|
case parser.OPTTokenHeader:
|
||||||
this.headerOpt = val !== undefined ? val : '';
|
this.headerOpt = val !== undefined ? val : '';
|
||||||
this.optionUnitBits |= this.HEADER_BIT;
|
this.optionUnitBits |= this.HEADER_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenImportant:
|
case parser.OPTTokenImportant:
|
||||||
if ( this.action === AllowAction ) { return false; }
|
if ( this.action === AllowAction ) { return false; }
|
||||||
this.optionUnitBits |= this.IMPORTANT_BIT;
|
this.optionUnitBits |= this.IMPORTANT_BIT;
|
||||||
this.action = BlockImportant;
|
this.action = BlockImportant;
|
||||||
break;
|
break;
|
||||||
// Used by Adguard:
|
// Used by Adguard:
|
||||||
// https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#empty-modifier
|
// https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#empty-modifier
|
||||||
case this.parser.OPTTokenEmpty:
|
case parser.OPTTokenEmpty:
|
||||||
id = this.action === AllowAction
|
id = this.action === AllowAction
|
||||||
? this.parser.OPTTokenRedirectRule
|
? parser.OPTTokenRedirectRule
|
||||||
: this.parser.OPTTokenRedirect;
|
: parser.OPTTokenRedirect;
|
||||||
if ( this.processModifierOption(id, 'empty') === false ) {
|
if ( this.processModifierOption(id, 'empty') === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.optionUnitBits |= this.REDIRECT_BIT;
|
this.optionUnitBits |= this.REDIRECT_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenMatchCase:
|
case parser.OPTTokenMatchCase:
|
||||||
this.patternMatchCase = true;
|
this.patternMatchCase = true;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenMp4:
|
case parser.OPTTokenMp4:
|
||||||
id = this.action === AllowAction
|
id = this.action === AllowAction
|
||||||
? this.parser.OPTTokenRedirectRule
|
? parser.OPTTokenRedirectRule
|
||||||
: this.parser.OPTTokenRedirect;
|
: parser.OPTTokenRedirect;
|
||||||
if ( this.processModifierOption(id, 'noopmp4-1s') === false ) {
|
if ( this.processModifierOption(id, 'noopmp4-1s') === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.optionUnitBits |= this.REDIRECT_BIT;
|
this.optionUnitBits |= this.REDIRECT_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenNoop:
|
case parser.OPTTokenNoop:
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenRemoveparam:
|
case parser.OPTTokenRemoveparam:
|
||||||
if ( this.processModifierOption(id, val) === false ) {
|
if ( this.processModifierOption(id, val) === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.optionUnitBits |= this.REMOVEPARAM_BIT;
|
this.optionUnitBits |= this.REMOVEPARAM_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenRedirect:
|
case parser.OPTTokenRedirect:
|
||||||
if ( this.action === AllowAction ) {
|
if ( this.action === AllowAction ) {
|
||||||
id = this.parser.OPTTokenRedirectRule;
|
id = parser.OPTTokenRedirectRule;
|
||||||
}
|
}
|
||||||
if ( this.processModifierOption(id, val) === false ) {
|
if ( this.processModifierOption(id, val) === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.optionUnitBits |= this.REDIRECT_BIT;
|
this.optionUnitBits |= this.REDIRECT_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenRedirectRule:
|
case parser.OPTTokenRedirectRule:
|
||||||
|
if ( this.excludedOptionSet.has(parser.OPTTokenRedirectRule) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ( this.processModifierOption(id, val) === false ) {
|
if ( this.processModifierOption(id, val) === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.optionUnitBits |= this.REDIRECT_BIT;
|
this.optionUnitBits |= this.REDIRECT_BIT;
|
||||||
break;
|
break;
|
||||||
case this.parser.OPTTokenInvalid:
|
case parser.OPTTokenInvalid:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
if ( this.tokenIdToNormalizedType.has(id) === false ) {
|
if ( this.tokenIdToNormalizedType.has(id) === false ) {
|
||||||
|
@ -4051,6 +4060,34 @@ FilterContainer.prototype.dnrFromCompiled = function(op, context, ...args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to recover from errors for when the rule is still useful despite not
|
||||||
|
// being complete.
|
||||||
|
for ( const rule of ruleset ) {
|
||||||
|
if ( rule._error === undefined ) { continue; }
|
||||||
|
let i = rule._error.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
const error = rule._error[i];
|
||||||
|
if ( error.startsWith('FilterOriginEntityHit:') ) {
|
||||||
|
if (
|
||||||
|
Array.isArray(rule.condition.initiatorDomains) &&
|
||||||
|
rule.condition.initiatorDomains.length > 0
|
||||||
|
) {
|
||||||
|
rule._error.splice(i, 1);
|
||||||
|
}
|
||||||
|
} else if ( error.startsWith('FilterOriginEntityMiss:') ) {
|
||||||
|
if (
|
||||||
|
Array.isArray(rule.condition.excludedInitiatorDomains) &&
|
||||||
|
rule.condition.excludedInitiatorDomains.length > 0
|
||||||
|
) {
|
||||||
|
rule._error.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( rule._error.length === 0 ) {
|
||||||
|
delete rule._error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Patch modifier filters
|
// Patch modifier filters
|
||||||
for ( const rule of ruleset ) {
|
for ( const rule of ruleset ) {
|
||||||
if ( rule.__modifierType === undefined ) { continue; }
|
if ( rule.__modifierType === undefined ) { continue; }
|
||||||
|
@ -4067,10 +4104,12 @@ FilterContainer.prototype.dnrFromCompiled = function(op, context, ...args) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'redirect-rule': {
|
case 'redirect-rule': {
|
||||||
|
let priority = rule.priority || 0;
|
||||||
let token = rule.__modifierValue;
|
let token = rule.__modifierValue;
|
||||||
if ( token !== '' ) {
|
if ( token !== '' ) {
|
||||||
const match = /:\d+$/.exec(token);
|
const match = /:(\d+)$/.exec(token);
|
||||||
if ( match !== null ) {
|
if ( match !== null ) {
|
||||||
|
priority += parseInt(match[1], 10);
|
||||||
token = token.slice(0, match.index);
|
token = token.slice(0, match.index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4078,14 +4117,14 @@ FilterContainer.prototype.dnrFromCompiled = function(op, context, ...args) {
|
||||||
if ( rule.__modifierValue !== '' && resource === undefined ) {
|
if ( rule.__modifierValue !== '' && resource === undefined ) {
|
||||||
dnrAddRuleError(rule, `Unpatchable redirect filter: ${rule.__modifierValue}`);
|
dnrAddRuleError(rule, `Unpatchable redirect filter: ${rule.__modifierValue}`);
|
||||||
}
|
}
|
||||||
const extensionPath = resource && resource.extensionPath || token;
|
|
||||||
if ( rule.__modifierAction !== AllowAction ) {
|
if ( rule.__modifierAction !== AllowAction ) {
|
||||||
|
const extensionPath = resource || token;
|
||||||
rule.action.type = 'redirect';
|
rule.action.type = 'redirect';
|
||||||
rule.action.redirect = { extensionPath };
|
rule.action.redirect = { extensionPath };
|
||||||
rule.priority = (rule.priority || 1) + 1;
|
rule.priority = priority + 1;
|
||||||
} else {
|
} else {
|
||||||
rule.action.type = 'block';
|
rule.action.type = 'block';
|
||||||
rule.priority = (rule.priority || 1) + 2;
|
rule.priority = priority + 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ if [ "$1" != "quick" ]; then
|
||||||
cp platform/mv3/extension/js/utils.js $TMPDIR/js/
|
cp platform/mv3/extension/js/utils.js $TMPDIR/js/
|
||||||
cp assets/assets.json $TMPDIR/
|
cp assets/assets.json $TMPDIR/
|
||||||
cp -R platform/mv3/scriptlets $TMPDIR/
|
cp -R platform/mv3/scriptlets $TMPDIR/
|
||||||
|
mkdir -p $TMPDIR/web_accessible_resources
|
||||||
|
cp src/web_accessible_resources/* $TMPDIR/web_accessible_resources/
|
||||||
cd $TMPDIR
|
cd $TMPDIR
|
||||||
node --no-warnings make-rulesets.js output=$DES
|
node --no-warnings make-rulesets.js output=$DES
|
||||||
cd - > /dev/null
|
cd - > /dev/null
|
||||||
|
|
|
@ -13,6 +13,7 @@ cp src/js/dynamic-net-filtering.js $DES/js
|
||||||
cp src/js/filtering-context.js $DES/js
|
cp src/js/filtering-context.js $DES/js
|
||||||
cp src/js/hnswitches.js $DES/js
|
cp src/js/hnswitches.js $DES/js
|
||||||
cp src/js/hntrie.js $DES/js
|
cp src/js/hntrie.js $DES/js
|
||||||
|
cp src/js/redirect-resources.js $DES/js
|
||||||
cp src/js/static-dnr-filtering.js $DES/js
|
cp src/js/static-dnr-filtering.js $DES/js
|
||||||
cp src/js/static-filtering-parser.js $DES/js
|
cp src/js/static-filtering-parser.js $DES/js
|
||||||
cp src/js/static-net-filtering.js $DES/js
|
cp src/js/static-net-filtering.js $DES/js
|
||||||
|
|
Loading…
Reference in New Issue