...
 
Commits (3)
......@@ -17,8 +17,11 @@
"use strict";
const {onlyTopURL} = require("../lib/constants.js");
const {testRules} = require("../lib/rule-tester.js");
let earlyExit = (done) => { expect(true); done(); };
describe("filter tests", () =>
{
test("element hiding 1", (done) =>
......@@ -42,7 +45,7 @@ describe("filter tests", () =>
["test.com##.whatever"],
[{
trigger: {
"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]?",
"url-filter-is-case-sensitive": true
},
action: {type: "css-display-none", selector: ".whatever"}
......@@ -51,6 +54,7 @@ describe("filter tests", () =>
test("element hiding exceptions 1", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
[
......@@ -65,7 +69,7 @@ describe("filter tests", () =>
[
["^https?://",
["*test.com", "*special.test.com", "*anothertest.com"]],
["^https?://([^/:]*\\.)?test\\.com[/:]", ["*special.test.com"]]
["^https?://([^/:]*\\.)?test\\.com[/:]?", ["*special.test.com"]]
],
rules => rules.map(rule =>
[rule.trigger["url-filter"], rule.trigger["unless-domain"]]));
......@@ -92,7 +96,7 @@ describe("filter tests", () =>
[{
action: {selector: "whatever", type: "ignore-previous-rules"},
trigger: {
"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]?",
"url-filter-is-case-sensitive": true
}
}]
......@@ -123,7 +127,7 @@ describe("filter tests", () =>
{
action: {selector: "whatever", type: "ignore-previous-rules"},
trigger: {
"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]?",
"url-filter-is-case-sensitive": true
}
}
......@@ -257,6 +261,7 @@ describe("filter tests", () =>
test("domain whitelisting 1", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["@@||example.com^$document"],
......@@ -271,6 +276,7 @@ describe("filter tests", () =>
test("domain whitelisting 2", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["@@||example.com^$document,image"],
......@@ -308,6 +314,7 @@ describe("filter tests", () =>
test("generic block exceptions 1", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["^ad.jpg|", "@@||example.com^$genericblock"],
......@@ -318,6 +325,7 @@ describe("filter tests", () =>
test("generic block exceptions 2", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["^ad.jpg|$domain=test.com", "@@||example.com^$genericblock"],
......@@ -328,6 +336,7 @@ describe("filter tests", () =>
test("generic block exceptions 3", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["^ad.jpg|$domain=~test.com", "@@||example.com^$genericblock"],
......@@ -406,6 +415,7 @@ describe("filter tests", () =>
test("filter options 1", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["1$domain=foo.com"], ["*foo.com"],
......@@ -432,6 +442,7 @@ describe("filter tests", () =>
test("filter options 4", (done) =>
{
// Test subdomain exceptions.
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["1$domain=foo.com|~bar.foo.com"],
......@@ -441,13 +452,14 @@ describe("filter tests", () =>
test("filter options 5", (done) =>
{
if (onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["1$domain=foo.com|~www.foo.com"],
["foo.com"],
rules => rules[0]["trigger"]["if-domain"]);
});
test("web socket", (done) =>
{
testRules(
......
......@@ -31,7 +31,7 @@ describe("element hiding exception handling", () =>
["mydomain.com##.adclass"],
[{
trigger: {
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]?",
"url-filter-is-case-sensitive": true
},
action: {selector: ".adclass", type: "css-display-none"}
......@@ -46,7 +46,7 @@ describe("element hiding exception handling", () =>
["mydomain.com##.adclass1", "mydomain.com##.adclass2"],
[{
trigger: {
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]?",
"url-filter-is-case-sensitive": true
},
action: {selector: ".adclass1, .adclass2", type: "css-display-none"}
......@@ -61,7 +61,7 @@ describe("element hiding exception handling", () =>
["mydomain.com#@#.adclass"],
[{
trigger: {
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]?",
"url-filter-is-case-sensitive": true
},
action: {selector: ".adclass", type: "ignore-previous-rules"}
......@@ -76,7 +76,7 @@ describe("element hiding exception handling", () =>
["mydomain.com#@#.adclass1", "mydomain.com#@#.adclass2"],
[{
trigger: {
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]",
"url-filter": "^https?://([^/:]*\\.)?mydomain\\.com[/:]?",
"url-filter-is-case-sensitive": true
},
action: {
......
/*
* This file is part of Adblock Plus <https://adblockplus.org/>,
* Copyright (C) 2006-present eyeo GmbH
*
* Adblock Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
// Focused testing of *-top-url handling. These tests have been copied from the
// original tests and reimplemented for *-top-url handling.
"use strict";
const {onlyTopURL} = require("../lib/constants.js");
const {testRules} = require("../lib/rule-tester.js");
let earlyExit = (done) => { expect(true); done(); };
describe("top url handling", () =>
{
test("element hiding exceptions", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
[
"##.whatever",
"test.com,anothertest.com###something",
"@@||special.test.com^$elemhide",
"@@||test.com^$generichide",
"@@||anothertest.com^$elemhide",
"@@^something^$elemhide",
"@@^anything^$generichide"
],
[
["^https?://",
["^[^:]+:(//)?([^/]+\\.)?test\\.com[/:]?",
"^[^:]+:(//)?([^/]+\\.)?special\\.test\\.com[/:]?",
"^[^:]+:(//)?([^/]+\\.)?anothertest\\.com[/:]?"]],
["^https?://([^/:]*\\.)?test\\.com[/:]?",
["^[^:]+:(//)?([^/]+\\.)?special\\.test\\.com[/:]?"]]
],
rules => rules.map(rule =>
[rule.trigger["url-filter"], rule.trigger["unless-top-url"]]));
});
test("domain whitelisting topurl a", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["@@||example.com^$document"],
[{
trigger: {
"url-filter": ".*",
"if-top-url": ["^[^:]+:(//)?([^/]+\\.)?example\\.com[/:]?"]
},
action: {type: "ignore-previous-rules"}
}]);
});
test("domain whitelisting topurl b", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["@@||example.com^$document,image"],
[{
trigger: {
"url-filter": ".*",
"if-top-url": ["^[^:]+:(//)?([^/]+\\.)?example\\.com[/:]?"]
},
action: {type: "ignore-previous-rules"}
},
{
trigger: {
"url-filter": "^https?://([^/]+\\.)?example\\.com([^-_.%a-z0-9].*)?$",
"url-filter-is-case-sensitive": true,
"resource-type": ["image"]
},
action: {type: "ignore-previous-rules"}
}]);
});
test("unless top url case sensitivity", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["||mydomain.com^"],
[
{
trigger: {
"url-filter": "^[^:]+:(//)?([^/]+\\.)?mydomain\\.com([^-_.%a-z0-9].*)?$",
"url-filter-is-case-sensitive": true,
"resource-type": ["image", "style-sheet", "script", "font", "media",
"raw", "document"],
"unless-top-url": ["^[^:]+:(//)?([^/]+\\.)?mydomain\\.com([^-_.%a-z0-9].*)?$"],
"top-url-filter-is-case-sensitive": true
},
action: {type: "block"}
}]);
});
test("generic block exceptions topurl a", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["^ad.jpg|", "@@||example.com^$genericblock"],
[[undefined, ["^[^:]+:(//)?([^/]+\\.)?example\\.com[/:]?"]]],
rules => rules.map(rule =>
[rule.trigger["if-top-url"], rule.trigger["unless-top-url"]]));
});
test("generic block exceptions topurl b", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["^ad.jpg|$domain=mydomain.com", "@@||example.com^$genericblock"],
[[["^[^:]+:(//)?([^/]+\\.)?mydomain\\.com[/:]?"], undefined]],
rules => rules.map(rule =>
[rule.trigger["if-top-url"], rule.trigger["unless-top-url"]]));
});
test("generic block exceptions topurl c", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["^ad.jpg|$domain=~mydomain.com", "@@||example.com^$genericblock"],
[[undefined,
["^[^:]+:(//)?([^/]+\\.)?mydomain\\.com[/:]?",
"^[^:]+:(//)?([^/]+\\.)?example\\.com[/:]?"]]],
rules => rules.map(rule =>
[rule.trigger["if-top-url"], rule.trigger["unless-top-url"]]));
});
test("filter options topurl a", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["1$domain=mydomain.com"],
["^[^:]+:(//)?([^/]+\\.)?mydomain\\.com[/:]?"],
rules => rules[0]["trigger"]["if-top-url"]);
});
test("filter options topurl b", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["1$domain=mydomain.com|~www.mydomain.com"],
["^[^:]+:(//)?([^/]+\\.)?mydomain\\.com[/:]?"],
rules => rules[0]["trigger"]["if-top-url"]);
});
test("filter options topurl subdomain exceptions", (done) =>
{
if (!onlyTopURL) { earlyExit(done); return; }
testRules(
done,
["1$domain=mydomain.com|~subdomain.mydomain.com"],
["^[^:]+:(//)?([^/]+\\.)?mydomain\\.com[/:]?",
"^[^:]+:(//)?([^/]+\\.)?www\\.mydomain\\.com[/:]?"],
rules => rules[0]["trigger"]["if-top-url"]);
});
});
......@@ -22,6 +22,7 @@
const filterClasses = require("../adblockpluscore/lib/filterClasses");
const {
ActionType,
onlyTopURL,
ruleLimit,
typeMap,
whitelistableRequestTypes
......@@ -540,8 +541,12 @@ function groupRulesByMergeableProperty(rulesInfo, propertyType, property)
function mergeRules(rules, exhaustive)
{
let rulesInfo = rules.map(rule => ({rule}));
let arrayPropertiesToMergeBy;
let arrayPropertiesToMergeBy = ["resource-type", "if-domain"];
if (onlyTopURL)
arrayPropertiesToMergeBy = ["resource-type", "if-top-url"];
else
arrayPropertiesToMergeBy = ["resource-type", "if-domain"];
return async(() =>
{
......
/*
* This file is part of Adblock Plus <https://adblockplus.org/>,
* Copyright (C) 2006-present eyeo GmbH
*
* Adblock Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
// Builder for content blocking actions.
"use strict";
class Action
{
constructor(build)
{
// Intentionally empty.
}
static get Builder()
{
class Builder
{
constructor(type)
{
this["type"] = type;
}
selector(selectors)
{
this["selector"] = selectors;
return this;
}
build()
{
return new Action(this);
}
}
return Builder;
}
}
module.exports = {
Action
};
/*
* This file is part of Adblock Plus <https://adblockplus.org/>,
* Copyright (C) 2006-present eyeo GmbH
*
* Adblock Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
// Builder for content blocking triggers.
"use strict";
let clone = ((trigger) =>
{
let newTrigger = new Trigger.Builder();
Object.assign(newTrigger, trigger);
return newTrigger;
});
class Trigger
{
constructor(build)
{
// Intentionally empty.
}
static get Builder()
{
class Builder
{
constructor(urlFilter)
{
this["url-filter"] = urlFilter;
}
urlFilter(urlFltr)
{
this["url-filter"] = urlFltr;
return this;
}
caseSensitive(bool)
{
this["url-filter-is-case-sensitive"] = bool;
return this;
}
topURLCaseSensitive(bool)
{
this["top-url-filter-is-case-sensitive"] = bool;
return this;
}
ifTopURL(url)
{
this["if-top-url"] = url;
return this;
}
unlessTopURL(url)
{
this["unless-top-url"] = url;
return this;
}
ifDomain(domain)
{
this["if-domain"] = domain;
return this;
}
unlessDomain(domain)
{
this["unless-domain"] = domain;
return this;
}
loadType(type)
{
this["load-type"] = type;
return this;
}
resourceType(types)
{
this["resource-type"] = types;
return this;
}
build()
{
return new Trigger(this);
}
// Getters:
getURLFilter()
{
return this["url-filter"];
}
getIfDomain()
{
return this["if-domain"];
}
getUnlessDomain()
{
return this["unless-domain"];
}
getIfTopURL()
{
return this["if-top-url"];
}
getUnlessTopURL()
{
return this["unless-top-url"];
}
getCaseSensitive()
{
return this["url-filter-is-case-sensitive"];
}
}
return Builder;
}
}
module.exports = {
clone,
Trigger
};
......@@ -21,6 +21,9 @@
const filterClasses = require("../adblockpluscore/lib/filterClasses");
// When true, only *-top-url rules are generated.
const onlyTopURL = true;
const ruleLimit = 50000;
const selectorLimit = 5000;
const typeMap = filterClasses.RegExpFilter.typeMap;
......@@ -67,6 +70,7 @@ module.exports = {
FilterType,
httpRequestTypes,
LoadType,
onlyTopURL,
rawRequestTypes,
ruleLimit,
selectorLimit,
......
......@@ -19,7 +19,9 @@
"use strict";
const {onlyTopURL} = require("./constants.js");
const {escapeRegExp} = require("./regexps.js");
const {clone} = require("./builders/trigger.js");
function findSubdomainsInList(domain, list)
{
......@@ -36,10 +38,20 @@ function findSubdomainsInList(domain, list)
return subdomains;
}
function justDomain(trigger, name)
{
if (onlyTopURL)
trigger.ifTopURL(trigger.getIfTopURL().concat([wrapDomain(name)])).build();
else
trigger.ifDomain(trigger.getIfDomain().concat([name])).build();
return clone(trigger);
}
function matchDomain(domain)
{
if (!domain) { return "^https?://"; }
return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]";
return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]?";
}
/**
......@@ -52,6 +64,7 @@ function parseDomains(domains, included, excluded)
{
if (!domains)
return;
for (let [domain, enabled] of domains)
{
if (domain !== "")
......@@ -64,8 +77,62 @@ function parseDomains(domains, included, excluded)
}
}
function starDomain(trigger, name)
{
let copy = clone(trigger);
if (onlyTopURL)
copy.ifTopURL(copy.getIfTopURL().concat([wrapDomain(name)])).build();
else
copy.ifDomain(copy.getIfDomain().concat(["*" + name])).build();
return copy;
}
function starDomainExcluded(trigger, exclusions)
{
let copy = clone(trigger);
if (onlyTopURL)
{
copy.unlessTopURL(exclusions.map(name => { return wrapDomain(name); }))
.build();
}
else
{
copy.unlessDomain(exclusions.map(name => { return "*" + name; })).build();
}
return copy;
}
/**
* Domain string is wrapped with regexps appropriate to *-top-url usage.
* @param {string} domain
* @returns {string}
*/
function wrapDomain(domain)
{
return "^[^:]+:(//)?([^/]+\\.)?" + escapeRegExp(domain) + "[/:]?";
}
function wwwDomain(trigger, name)
{
let copy = clone(trigger);
if (onlyTopURL)
{
copy.ifTopURL(copy.getIfTopURL().concat([wrapDomain("www." + name)]))
.build();
}
else { copy.ifDomain(copy.getIfDomain().concat(["www." + name])).build(); }
return copy;
}
module.exports = {
findSubdomainsInList,
justDomain,
matchDomain,
parseDomains
parseDomains,
starDomain,
starDomainExcluded,
wrapDomain,
wwwDomain
};
......@@ -21,7 +21,8 @@
const Error = {
invalidActionType: "Invalid action type",
invalidFilterType: "Invalid filter type"
invalidFilterType: "Invalid filter type",
invalidJSType: "Invalid JS type"
};
module.exports = {
......
This diff is collapsed.