| Index: lib/filterClasses.js |
| diff --git a/lib/filterClasses.js b/lib/filterClasses.js |
| index 1cf4f48e192c33afc7d9fb3d731c5a0f4de94946..fd65d3ec771e513c2b6778d129f431b2291fcfb5 100644 |
| --- a/lib/filterClasses.js |
| +++ b/lib/filterClasses.js |
| @@ -703,6 +703,7 @@ Object.defineProperty(RegExpFilter.prototype, "0", { |
| RegExpFilter.fromText = function(text) |
| { |
| let contentType = null; |
| + let csp = null; |
| let matchCase = null; |
| let domains = null; |
| let sitekeys = null; |
| @@ -718,7 +719,22 @@ RegExpFilter.fromText = function(text) |
| else |
| { |
| text = match.input.substring(0, match.index).replace(/\s/g, ""); |
| - let options = match[1].replace(/\s/g, ""); |
| + |
| + // Strip all whitespace from the options string, except for CSP values which |
| + // we only trim. |
| + let rawOptions = match[1]; |
| + let options = ""; |
| + let offset = 0; |
| + let cspMatch; |
| + let cspRegexp = /((?:^|,)csp=)([^,]+)/gi; |
| + while ((cspMatch = cspRegexp.exec(rawOptions))) |
| + { |
| + options += rawOptions.substring(offset, cspMatch.index).replace(/\s/g, ""); |
| + options += cspMatch[1] + cspMatch[2].trim(); |
| + offset = cspRegexp.lastIndex; |
| + } |
| + options += rawOptions.substring(offset).replace(/\s/g, ""); |
| + |
| origText = text + "$" + options; |
| for (let option of options.toUpperCase().split(",")) |
| @@ -736,6 +752,14 @@ RegExpFilter.fromText = function(text) |
| if (contentType == null) |
| contentType = 0; |
| contentType |= RegExpFilter.typeMap[option]; |
| + |
| + if (option == "CSP" && typeof value == "string") |
| + { |
| + csp = value.toLowerCase(); |
|
Manish Jethani
2018/02/06 05:54:20
We could avoid uppercasing and then lowercasing th
kzar
2018/03/06 15:37:53
Done.
|
| + // Quick check to prevent report-uri and report-to directives |
| + if (csp.includes("report-")) |
|
Manish Jethani
2018/02/06 05:54:20
Couldn't the value contain "report-" in a differen
kzar
2018/03/06 15:37:53
Done.
|
| + return new InvalidFilter(origText, "filter_invalid_csp"); |
| + } |
| } |
| else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap) |
| { |
| @@ -772,7 +796,7 @@ RegExpFilter.fromText = function(text) |
| matchCase, domains, thirdParty, sitekeys); |
| } |
| return new BlockingFilter(origText, text, contentType, matchCase, domains, |
| - thirdParty, sitekeys, collapse); |
| + thirdParty, sitekeys, collapse, csp); |
| } |
| catch (e) |
| { |
| @@ -792,6 +816,7 @@ RegExpFilter.typeMap = { |
| SUBDOCUMENT: 32, |
| DOCUMENT: 64, |
| WEBSOCKET: 128, |
| + CSP: 512, |
|
Manish Jethani
2018/02/06 05:54:20
Perhaps a good idea to place CSP after WEBRTC?
kzar
2018/03/06 15:37:53
Done.
|
| WEBRTC: 256, |
| XBL: 1, |
| PING: 1024, |
| @@ -809,9 +834,10 @@ RegExpFilter.typeMap = { |
| GENERICHIDE: 0x80000000 |
| }; |
| -// DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't |
| -// be there by default |
| -RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT | |
| +// CSP, DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options |
| +// shouldn't be there by default |
| +RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.CSP | |
| + RegExpFilter.typeMap.DOCUMENT | |
| RegExpFilter.typeMap.ELEMHIDE | |
| RegExpFilter.typeMap.POPUP | |
| RegExpFilter.typeMap.GENERICHIDE | |
| @@ -828,16 +854,19 @@ RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT | |
| * @param {string} sitekeys see RegExpFilter() |
| * @param {boolean} collapse |
| * defines whether the filter should collapse blocked content, can be null |
| + * @param {string} [csp] |
| + * Content Security Policy to inject when the filter matches |
| * @constructor |
| * @augments RegExpFilter |
| */ |
| function BlockingFilter(text, regexpSource, contentType, matchCase, domains, |
| - thirdParty, sitekeys, collapse) |
| + thirdParty, sitekeys, collapse, csp) |
| { |
| RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, |
| thirdParty, sitekeys); |
| this.collapse = collapse; |
| + this.csp = csp; |
| } |
| exports.BlockingFilter = BlockingFilter; |
| @@ -849,7 +878,13 @@ BlockingFilter.prototype = extend(RegExpFilter, { |
| * Can be null (use the global preference). |
| * @type {boolean} |
| */ |
| - collapse: null |
| + collapse: null, |
| + |
| + /** |
| + * Content Security Policy to inject for matching requests. |
| + * @type {string} |
| + */ |
| + csp: null |
| }); |
| /** |