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

Unified Diff: lib/filterClasses.js

Issue 4559243822759936: Issue 431/432 - Remove special handling for the $sitekey option (Closed)
Patch Set: Created July 28, 2014, 2:44 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
Index: lib/filterClasses.js
===================================================================
--- a/lib/filterClasses.js
+++ b/lib/filterClasses.js
@@ -20,6 +20,7 @@
*/
let {FilterNotifier} = require("filterNotifier");
+let {Utils} = require("utils");
Wladimir Palant 2014/08/01 10:50:21 This is a pretty self-contained module, it shouldn
Thomas Greiner 2014/08/11 17:18:15 Done.
/**
* Abstract base class for filters
@@ -216,14 +217,16 @@
* Abstract base class for filters that can get hits
* @param {String} text see Filter()
* @param {String} domains (optional) Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com"
+ * @param {String} siteKeys (optional) Public keys of websites that this filter should apply to, e.g. "foo|bar|~baz"
Wladimir Palant 2014/08/01 10:50:21 I don't really see how exceptions are useful here,
Thomas Greiner 2014/08/11 17:18:15 The issue stated that $sitekey should be handled e
* @constructor
* @augments Filter
*/
-function ActiveFilter(text, domains)
+function ActiveFilter(text, domains, siteKeys)
{
Filter.call(this, text);
this.domainSource = domains;
+ this.siteKeySource = siteKeys;
Thomas Greiner 2014/08/11 17:18:15 Done.
}
exports.ActiveFilter = ActiveFilter;
@@ -381,6 +384,66 @@
},
/**
+ * String that the siteKey property should be generated from
+ * @type String
+ */
+ siteKeySource: null,
+
+ /**
+ * Map containing public keys of websites that this filter should apply to
+ * @type Object
+ */
+ get siteKeys()
+ {
+ let siteKeys = null;
+
+ if (this.siteKeySource)
+ {
+ let source = this.siteKeySource;
+ let list = source.split("|");
+ if (list.length == 1 && list[0][0] != "~")
+ {
+ // Fast track for the common one-sitekey scenario
+ siteKeys = {__proto__: null, "": false};
+ siteKeys[list[0]] = true;
+ }
+ else
+ {
+ let hasIncludes = false;
+ for (let i = 0; i < list.length; i++)
+ {
+ let siteKey = list[i];
+ if (siteKey == "")
+ continue;
+
+ let include;
+ if (siteKey[0] == "~")
+ {
+ include = false;
+ siteKey = siteKey.substr(1);
+ }
+ else
+ {
+ include = true;
+ hasIncludes = true;
+ }
+
+ if (!siteKeys)
+ siteKeys = Object.create(null);
+
+ siteKeys[siteKey] = include;
+ }
+ siteKeys[""] = !hasIncludes;
+ }
+
+ this.siteKeySource = null;
+ }
+
+ Object.defineProperty(this, "siteKeys", {value: siteKeys, enumerable: true});
+ return this.siteKeys;
+ },
+
+ /**
* Checks whether this filter is active on a domain.
*/
isActiveOnDomain: function(/**String*/ docDomain) /**Boolean*/
@@ -430,6 +493,44 @@
},
/**
+ * Checks whether the provided site key is valid and active on a page
+ */
+ isActiveOnPage: function(/**String*/ docDomain, /**String*/ docLocation, /**String*/ siteKey) /**Boolean*/
Wladimir Palant 2014/08/01 10:50:21 I don't think that this is the right place to perf
Thomas Greiner 2014/08/11 17:18:15 Done.
+ {
+ // If no site keys are set the rule matches everywhere
+ if (!this.siteKeys)
+ return true;
+
+ // If the document has not provided a sitekey, match only if the filter isn't restricted by sitekeys
+ if (!docDomain || !siteKey)
+ return this.siteKeys[""];
+
+ // If the document has provided an invalid sitekey the filter should not match
+ if (siteKey.indexOf("_") < 0)
+ return false;
+
+ let [key, signature] = siteKey.split("_", 2);
+ let formattedKey = key.replace(/=/g, "").toUpperCase();
+ if (!(formattedKey in this.siteKeys) || !Utils.crypto)
+ return this.siteKeys[""];
+
+ // Website specifies a key that we know but is the signature valid?
+ let uri = Services.io.newURI(docLocation, null, null);
+ let host = uri.asciiHost;
+ if (uri.port > 0)
+ host += ":" + uri.port;
+ let params = [
+ uri.path.replace(/#.*/, ""), // REQUEST_URI
+ host, // HTTP_HOST
+ Utils.httpProtocol.userAgent // HTTP_USER_AGENT
+ ];
+ if (Utils.verifySignature(key, signature, params.join("\0")))
+ return this.siteKeys[formattedKey];
+
+ return !this.siteKeys[formattedKey];
+ },
+
+ /**
* See Filter.serialize()
*/
serialize: function(buffer)
@@ -455,12 +556,13 @@
* @param {Boolean} matchCase (optional) Defines whether the filter should distinguish between lower and upper case letters
* @param {String} domains (optional) Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
* @param {Boolean} thirdParty (optional) Defines whether the filter should apply to third-party or first-party content only
+ * @param {String} siteKeys (optional) Public keys of websites that this filter should apply to, e.g. "foo|bar|~baz"
* @constructor
* @augments ActiveFilter
*/
-function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty)
+function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys)
{
- ActiveFilter.call(this, text, domains);
+ ActiveFilter.call(this, text, domains, siteKeys);
if (contentType != null)
this.contentType = contentType;
@@ -554,14 +656,17 @@
* @param {String} contentType content type identifier of the URL
* @param {String} docDomain domain name of the document that loads the URL
* @param {Boolean} thirdParty should be true if the URL is a third-party request
+ * @param {String} docLocation location of the document that loads the URL
+ * @param {String} siteKey public key provided by the document
* @return {Boolean} true in case of a match
*/
- matches: function(location, contentType, docDomain, thirdParty)
+ matches: function(location, contentType, docDomain, thirdParty, docLocation, siteKey)
{
if (this.regexp.test(location) &&
(RegExpFilter.typeMap[contentType] & this.contentType) != 0 &&
(this.thirdParty == null || this.thirdParty == thirdParty) &&
- this.isActiveOnDomain(docDomain))
+ this.isActiveOnDomain(docDomain) &&
+ this.isActiveOnPage(docDomain, docLocation, siteKey))
{
return true;
}
@@ -639,7 +744,7 @@
else if (option == "~COLLAPSE")
collapse = false;
else if (option == "SITEKEY" && typeof value != "undefined")
- siteKeys = value.split(/\|/);
+ siteKeys = value;
else
return new InvalidFilter(origText, "Unknown option " + option.toLowerCase());
}
@@ -653,13 +758,11 @@
contentType = RegExpFilter.prototype.contentType;
contentType &= ~RegExpFilter.typeMap.DOCUMENT;
}
- if (!blocking && siteKeys)
- contentType = RegExpFilter.typeMap.DOCUMENT;
try
{
if (blocking)
- return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, collapse);
+ return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, siteKeys, collapse);
else
return new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, siteKeys);
}
@@ -705,13 +808,14 @@
* @param {Boolean} matchCase see RegExpFilter()
* @param {String} domains see RegExpFilter()
* @param {Boolean} thirdParty see RegExpFilter()
+ * @param {String} siteKeys see RegExpFilter()
* @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null
* @constructor
* @augments RegExpFilter
*/
-function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, collapse)
+function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys, collapse)
{
- RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty);
+ RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys);
this.collapse = collapse;
}
@@ -736,28 +840,19 @@
* @param {Boolean} matchCase see RegExpFilter()
* @param {String} domains see RegExpFilter()
* @param {Boolean} thirdParty see RegExpFilter()
- * @param {String[]} siteKeys public keys of websites that this filter should apply to
+ * @param {String} siteKeys see RegExpFilter()
* @constructor
* @augments RegExpFilter
*/
function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys)
{
- RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty);
-
- if (siteKeys != null)
- this.siteKeys = siteKeys;
+ RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys);
}
exports.WhitelistFilter = WhitelistFilter;
WhitelistFilter.prototype =
{
- __proto__: RegExpFilter.prototype,
-
- /**
- * List of public keys of websites that this filter should apply to
- * @type String[]
- */
- siteKeys: null
+ __proto__: RegExpFilter.prototype
}
/**
« lib/contentPolicy.js ('K') | « lib/contentPolicy.js ('k') | lib/matcher.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld