Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/filterClasses.js

Issue 29737558: Issue 6538, 6781 - Implement support for snippet filters (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Fix normalization and add more tests Created April 26, 2018, 3:07 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/elemHide.js ('k') | lib/filterListener.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/filterClasses.js
===================================================================
--- a/lib/filterClasses.js
+++ b/lib/filterClasses.js
@@ -79,20 +79,20 @@
/**
* Cache for known filters, maps string representation to filter objects.
* @type {Map.<string,Filter>}
*/
Filter.knownFilters = new Map();
/**
- * Regular expression that element hiding filters should match
+ * Regular expression that code injection filters should match
* @type {RegExp}
*/
-Filter.elemhideRegExp = /^([^/*|@"!]*?)#([@?])?#(.+)$/;
+Filter.codeInjectionRegExp = /^([^/*|@"!]*?)#([@?$])?#(.+)$/;
/**
* Regular expression that RegExp filters specified as RegExps should match
* @type {RegExp}
*/
Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w-]+(?:=[^,\s]+)?(?:,~?[\w-]+(?:=[^,\s]+)?)*)?$/;
/**
* Regular expression that options on a RegExp filter should match
* @type {RegExp}
@@ -112,31 +112,34 @@
* @return {Filter}
*/
Filter.fromText = function(text)
{
let filter = Filter.knownFilters.get(text);
if (filter)
return filter;
- let match = (text.includes("#") ? Filter.elemhideRegExp.exec(text) : null);
+ let match = text.includes("#") ? Filter.codeInjectionRegExp.exec(text) : null;
if (match)
{
let propsMatch;
if (!match[2] &&
(propsMatch = /\[-abp-properties=(["'])([^"']+)\1\]/.exec(match[3])))
{
// This is legacy CSS properties syntax, convert to current syntax
let prefix = match[3].substr(0, propsMatch.index);
let expression = propsMatch[2];
let suffix = match[3].substr(propsMatch.index + propsMatch[0].length);
return Filter.fromText(`${match[1]}#?#` +
`${prefix}:-abp-properties(${expression})${suffix}`);
}
+ if (match[2] == "$")
+ return new SnippetFilter(text, match[1], match[3]);
+
filter = ElemHideBase.fromText(
text, match[1], match[2], match[3]
);
}
else if (text[0] == "!")
filter = new CommentFilter(text);
else
filter = RegExpFilter.fromText(text);
@@ -179,22 +182,22 @@
// Remove line breaks, tabs etc
text = text.replace(/[^\S ]+/g, "");
// Don't remove spaces inside comments
if (/^ *!/.test(text))
return text.trim();
- // Special treatment for element hiding filters, right side is allowed to
+ // Special treatment for code injection filters, right side is allowed to
// contain spaces
- if (Filter.elemhideRegExp.test(text))
+ if (Filter.codeInjectionRegExp.test(text))
{
- let [, domain, separator, selector] = /^(.*?)(#[@?]?#?)(.*)$/.exec(text);
- return domain.replace(/ +/g, "") + separator + selector.trim();
+ let [, domain, separator, code] = /^(.*?)(#[@?$]?#?)(.*)$/.exec(text);
+ return domain.replace(/ +/g, "") + separator + code.trim();
}
// For most regexp filters we strip all spaces, but $csp filter options
// are allowed to contain single (non trailing) spaces.
let strippedText = text.replace(/ +/g, "");
if (!strippedText.includes("$") || !/\bcsp=/i.test(strippedText))
return strippedText;
@@ -945,65 +948,84 @@
}
exports.WhitelistFilter = WhitelistFilter;
WhitelistFilter.prototype = extend(RegExpFilter, {
type: "whitelist"
});
/**
- * Base class for element hiding filters
+ * Base class for code injection filters
* @param {string} text see Filter()
* @param {string} [domains] Host names or domains the filter should be
* restricted to
- * @param {string} selector CSS selector for the HTML elements that should be
- * hidden
+ * @param {string} code Code that should be injected
* @constructor
* @augments ActiveFilter
*/
-function ElemHideBase(text, domains, selector)
+function CodeInjectionFilter(text, domains, code)
{
ActiveFilter.call(this, text, domains || null);
if (domains)
{
- this.selectorDomain = domains.replace(/,~[^,]+/g, "")
- .replace(/^~[^,]+,?/, "").toLowerCase();
+ this.injectionDomain = domains.replace(/,~[^,]+/g, "")
+ .replace(/^~[^,]+,?/, "").toLowerCase();
}
- // Braces are being escaped to prevent CSS rule injection.
- this.selector = selector.replace("{", "\\7B ").replace("}", "\\7D ");
+ this.code = code;
}
-exports.ElemHideBase = ElemHideBase;
+exports.CodeInjectionFilter = CodeInjectionFilter;
-ElemHideBase.prototype = extend(ActiveFilter, {
+CodeInjectionFilter.prototype = extend(ActiveFilter, {
/**
* @see ActiveFilter.domainSeparator
*/
domainSeparator: ",",
/**
* @see ActiveFilter.ignoreTrailingDot
*/
ignoreTrailingDot: false,
/**
* Host name or domain the filter should be restricted to (can be null for
* no restriction)
* @type {string}
*/
- selectorDomain: null,
+ injectionDomain: null,
+
/**
- * CSS selector for the HTML elements that should be hidden
+ * Code that should be injected
* @type {string}
*/
- selector: null
+ code: null
});
/**
+ * Base class for element hiding filters
+ * @param {string} text see Filter()
+ * @param {string} [domains] see CodeInjectionFilter()
+ * @param {string} selector CSS selector for the HTML elements that should be
+ * hidden
+ * @constructor
+ * @augments CodeInjectionFilter
+ */
+function ElemHideBase(text, domains, selector)
+{
+ CodeInjectionFilter.call(this, text, domains, selector);
+
+ // Braces are being escaped to prevent CSS rule injection.
+ this.code = this.code.replace("{", "\\7B ").replace("}", "\\7D ");
+}
+exports.ElemHideBase = ElemHideBase;
+
+ElemHideBase.prototype = extend(CodeInjectionFilter, {});
+
+/**
* Creates an element hiding filter from a pre-parsed text representation
*
* @param {string} text same as in Filter()
* @param {string?} domain
* domain part of the text representation
* @param {string?} type
* rule type, either empty or @ (exception) or ? (emulation rule)
* @param {string} selector raw CSS selector
@@ -1082,8 +1104,26 @@
{
ElemHideBase.call(this, text, domains, selector);
}
exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
type: "elemhideemulation"
});
+
+/**
+ * Class for snippet filters
+ * @param {string} text see Filter()
+ * @param {string} [domains] see CodeInjectionFilter()
+ * @param {string} script Script that should be executed
+ * @constructor
+ * @augments CodeInjectionFilter
+ */
+function SnippetFilter(text, domains, script)
+{
+ CodeInjectionFilter.call(this, text, domains, script);
+}
+exports.SnippetFilter = SnippetFilter;
+
+SnippetFilter.prototype = extend(CodeInjectionFilter, {
+ type: "snippet"
+});
« no previous file with comments | « lib/elemHide.js ('k') | lib/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld