| LEFT | RIGHT | 
|    1 /* |    1 /* | 
|    2  * This file is part of Adblock Plus <https://adblockplus.org/>, |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|    3  * Copyright (C) 2006-present eyeo GmbH |    3  * Copyright (C) 2006-present eyeo GmbH | 
|    4  * |    4  * | 
|    5  * Adblock Plus is free software: you can redistribute it and/or modify |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|    6  * it under the terms of the GNU General Public License version 3 as |    6  * it under the terms of the GNU General Public License version 3 as | 
|    7  * published by the Free Software Foundation. |    7  * published by the Free Software Foundation. | 
|    8  * |    8  * | 
|    9  * Adblock Plus is distributed in the hope that it will be useful, |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
|   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|   12  * GNU General Public License for more details. |   12  * GNU General Public License for more details. | 
|   13  * |   13  * | 
|   14  * You should have received a copy of the GNU General Public License |   14  * You should have received a copy of the GNU General Public License | 
|   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|   16  */ |   16  */ | 
|   17  |   17  | 
|   18 /** @module whitelisting */ |   18 /** @module whitelisting */ | 
|   19  |   19  | 
|   20 "use strict"; |   20 "use strict"; | 
|   21  |   21  | 
|   22 const {defaultMatcher} = require("matcher"); |   22 const {defaultMatcher} = require("../adblockpluscore/lib/matcher"); | 
|   23 const {Filter, RegExpFilter} = require("filterClasses"); |   23 const {Filter, RegExpFilter} = require("../adblockpluscore/lib/filterClasses"); | 
|   24 const {FilterNotifier} = require("filterNotifier"); |   24 const {FilterNotifier} = require("../adblockpluscore/lib/filterNotifier"); | 
|   25 const {FilterStorage} = require("filterStorage"); |   25 const {FilterStorage} = require("../adblockpluscore/lib/filterStorage"); | 
|   26 const {stringifyURL, getDecodedHostname, |   26 const {extractHostFromFrame, isThirdParty} = require("./url"); | 
|   27        extractHostFromFrame, isThirdParty} = require("url"); |   27 const {port} = require("./messaging"); | 
|   28 const {port} = require("messaging"); |   28 const {logWhitelistedDocument} = require("./hitLogger"); | 
|   29 const {logWhitelistedDocument} = require("devLogger"); |   29 const {verifySignature} = require("../adblockpluscore/lib/rsa"); | 
|   30 const {verifySignature} = require("rsa"); |  | 
|   31  |   30  | 
|   32 let sitekeys = new ext.PageMap(); |   31 let sitekeys = new ext.PageMap(); | 
|   33  |   32  | 
|   34 function match(page, url, typeMask, docDomain, sitekey) |   33 function match(page, url, typeMask, docDomain, sitekey) | 
|   35 { |   34 { | 
|   36   let thirdParty = !!docDomain && isThirdParty(url, docDomain); |   35   let thirdParty = !!docDomain && isThirdParty(url, docDomain); | 
|   37   let urlString = stringifyURL(url); |  | 
|   38  |   36  | 
|   39   if (!docDomain) |   37   if (!docDomain) | 
|   40     docDomain = getDecodedHostname(url); |   38     docDomain = url.hostname; | 
|   41  |   39  | 
|   42   let filter = defaultMatcher.whitelist.matchesAny( |   40   let filter = defaultMatcher.whitelist.matchesAny( | 
|   43     urlString, typeMask, docDomain, thirdParty, sitekey |   41     url.href, typeMask, docDomain, thirdParty, sitekey | 
|   44   ); |   42   ); | 
|   45  |   43  | 
|   46   if (filter) |   44   if (filter && page) | 
|   47   { |   45     logWhitelistedDocument(page.id, url.href, typeMask, docDomain, filter); | 
|   48     logWhitelistedDocument( |  | 
|   49       page, urlString, typeMask, docDomain, filter |  | 
|   50     ); |  | 
|   51   } |  | 
|   52  |   46  | 
|   53   return filter; |   47   return filter; | 
|   54 } |   48 } | 
|   55  |   49  | 
|   56 let checkWhitelisted = |   50 let checkWhitelisted = | 
|   57 /** |   51 /** | 
|   58  * Gets the active whitelisting filter for the document associated |   52  * Gets the active whitelisting filter for the document associated | 
|   59  * with the given page/frame, or null if it's not whitelisted. |   53  * with the given page/frame, or null if it's not whitelisted. | 
|   60  * |   54  * | 
|   61  * @param {Page}   page |   55  * @param {?Page}   page | 
|   62  * @param {Frame}  [frame] |   56  * @param {?Frame} [frame] | 
 |   57  * @param {?URL}   [originUrl] | 
|   63  * @param {number} [typeMask=RegExpFilter.typeMap.DOCUMENT] |   58  * @param {number} [typeMask=RegExpFilter.typeMap.DOCUMENT] | 
|   64  * @return {?WhitelistFilter} |   59  * @return {?WhitelistFilter} | 
|   65  */ |   60  */ | 
|   66 exports.checkWhitelisted = (page, frame, typeMask) => |   61 exports.checkWhitelisted = (page, frame, originUrl, | 
|   67 { |   62                             typeMask = RegExpFilter.typeMap.DOCUMENT) => | 
|   68   if (typeof typeMask == "undefined") |   63 { | 
|   69     typeMask = RegExpFilter.typeMap.DOCUMENT; |   64   if (frame || originUrl) | 
|   70  |   65   { | 
|   71   if (frame) |   66     while (frame) | 
|   72   { |   67     { | 
|   73     let filter = null; |   68       let parentFrame = frame.parent; | 
|   74  |   69       let filter = match(page, frame.url, typeMask, | 
|   75     while (frame && !filter) |   70                          extractHostFromFrame(parentFrame, originUrl), | 
|   76     { |   71                          getKey(page, frame, originUrl)); | 
|   77       let {parent} = frame; |   72  | 
|   78       let docDomain = extractHostFromFrame(parent); |   73       if (filter) | 
|   79       let sitekey = getKey(page, frame); |   74         return filter; | 
|   80  |   75  | 
|   81       filter = match(page, frame.url, typeMask, docDomain, sitekey); |   76       frame = parentFrame; | 
|   82       frame = parent; |   77     } | 
|   83     } |   78  | 
|   84  |   79     return originUrl && match(page, originUrl, typeMask, null, | 
|   85     return filter; |   80                               getKey(null, null, originUrl)); | 
|   86   } |   81   } | 
|   87  |   82  | 
|   88   return match(page, page.url, typeMask); |   83   return page && match(page, page.url, typeMask); | 
|   89 }; |   84 }; | 
|   90  |   85  | 
|   91 port.on("filters.isWhitelisted", message => |   86 port.on("filters.isWhitelisted", message => | 
|   92 { |   87 { | 
|   93   return !!checkWhitelisted(new ext.Page(message.tab)); |   88   return !!checkWhitelisted(new ext.Page(message.tab)); | 
|   94 }); |   89 }); | 
|   95  |   90  | 
|   96 port.on("filters.whitelist", message => |   91 port.on("filters.whitelist", message => | 
|   97 { |   92 { | 
|   98   let page = new ext.Page(message.tab); |   93   let page = new ext.Page(message.tab); | 
|   99   let host = getDecodedHostname(page.url).replace(/^www\./, ""); |   94   let host = page.url.hostname.replace(/^www\./, ""); | 
|  100   let filter = Filter.fromText("@@||" + host + "^$document"); |   95   let filter = Filter.fromText("@@||" + host + "^$document"); | 
|  101   if (filter.subscriptions.length && filter.disabled) |   96   if (filter.subscriptions.length && filter.disabled) | 
|  102   { |   97   { | 
|  103     filter.disabled = false; |   98     filter.disabled = false; | 
|  104   } |   99   } | 
|  105   else |  100   else | 
|  106   { |  101   { | 
|  107     filter.disabled = false; |  102     filter.disabled = false; | 
|  108     FilterStorage.addFilter(filter); |  103     FilterStorage.addFilter(filter); | 
|  109   } |  104   } | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|  140   }); |  135   }); | 
|  141 }); |  136 }); | 
|  142  |  137  | 
|  143 ext.pages.onLoading.addListener(revalidateWhitelistingState); |  138 ext.pages.onLoading.addListener(revalidateWhitelistingState); | 
|  144  |  139  | 
|  145 let getKey = |  140 let getKey = | 
|  146 /** |  141 /** | 
|  147  * Gets the public key, previously recorded for the given page |  142  * Gets the public key, previously recorded for the given page | 
|  148  * and frame, to be considered for the $sitekey filter option. |  143  * and frame, to be considered for the $sitekey filter option. | 
|  149  * |  144  * | 
|  150  * @param {Page}  page |  145  * @param {?Page}   page | 
|  151  * @param {Frame} frame |  146  * @param {?Frame}  frame | 
 |  147  * @param {URL}    [originUrl] | 
|  152  * @return {string} |  148  * @return {string} | 
|  153  */ |  149  */ | 
|  154 exports.getKey = (page, frame) => |  150 exports.getKey = (page, frame, originUrl) => | 
|  155 { |  151 { | 
|  156   let keys = sitekeys.get(page); |  152   if (page) | 
|  157   if (!keys) |  153   { | 
|  158     return null; |  154     let keys = sitekeys.get(page); | 
|  159  |  155     if (keys) | 
|  160   for (; frame != null; frame = frame.parent) |  156     { | 
|  161   { |  157       for (; frame; frame = frame.parent) | 
|  162     let key = keys.get(stringifyURL(frame.url)); |  158       { | 
|  163     if (key) |  159         let key = keys.get(frame.url.href); | 
|  164       return key; |  160         if (key) | 
 |  161           return key; | 
 |  162       } | 
 |  163     } | 
 |  164   } | 
 |  165  | 
 |  166   if (originUrl) | 
 |  167   { | 
 |  168     for (let keys of sitekeys._map.values()) | 
 |  169     { | 
 |  170       let key = keys.get(originUrl.href); | 
 |  171       if (key) | 
 |  172         return key; | 
 |  173     } | 
|  165   } |  174   } | 
|  166  |  175  | 
|  167   return null; |  176   return null; | 
|  168 }; |  177 }; | 
|  169  |  178  | 
|  170 function checkKey(token, url) |  179 function checkKey(token, url) | 
|  171 { |  180 { | 
|  172   let parts = token.split("_"); |  181   let parts = token.split("_"); | 
|  173   if (parts.length < 2) |  182   if (parts.length < 2) | 
|  174     return false; |  183     return false; | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|  185 } |  194 } | 
|  186  |  195  | 
|  187 function recordKey(key, page, url) |  196 function recordKey(key, page, url) | 
|  188 { |  197 { | 
|  189   let keys = sitekeys.get(page); |  198   let keys = sitekeys.get(page); | 
|  190   if (!keys) |  199   if (!keys) | 
|  191   { |  200   { | 
|  192     keys = new Map(); |  201     keys = new Map(); | 
|  193     sitekeys.set(page, keys); |  202     sitekeys.set(page, keys); | 
|  194   } |  203   } | 
|  195   keys.set(stringifyURL(url), key); |  204   keys.set(url.href, key); | 
|  196 } |  205 } | 
|  197  |  206  | 
|  198 port.on("filters.addKey", (message, sender) => |  207 port.on("filters.addKey", (message, sender) => | 
|  199 { |  208 { | 
|  200   let key = checkKey(message.token, sender.frame.url); |  209   let key = checkKey(message.token, sender.frame.url); | 
|  201   if (key) |  210   if (key) | 
|  202     recordKey(key, sender.page, sender.frame.url); |  211     recordKey(key, sender.page, sender.frame.url); | 
|  203 }); |  212 }); | 
|  204  |  213  | 
|  205 function onHeadersReceived(details) |  214 function onHeadersReceived(details) | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  225 { |  234 { | 
|  226   browser.webRequest.onHeadersReceived.addListener( |  235   browser.webRequest.onHeadersReceived.addListener( | 
|  227     onHeadersReceived, |  236     onHeadersReceived, | 
|  228     { |  237     { | 
|  229       urls: ["http://*/*", "https://*/*"], |  238       urls: ["http://*/*", "https://*/*"], | 
|  230       types: ["main_frame", "sub_frame"] |  239       types: ["main_frame", "sub_frame"] | 
|  231     }, |  240     }, | 
|  232     ["responseHeaders"] |  241     ["responseHeaders"] | 
|  233   ); |  242   ); | 
|  234 } |  243 } | 
| LEFT | RIGHT |