| Left: | ||
| Right: |
| 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-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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 /** | 18 /** |
| 19 * @fileOverview Content policy implementation, responsible for blocking things. | 19 * @fileOverview Content policy implementation, responsible for blocking things. |
| 20 */ | 20 */ |
| 21 | 21 |
| 22 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); | 22 "use strict"; |
| 23 Cu.import("resource://gre/modules/Services.jsm"); | 23 |
| 24 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); | |
| 25 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); | |
| 24 | 26 |
| 25 let {Utils} = require("utils"); | 27 let {Utils} = require("utils"); |
| 26 let {Prefs} = require("prefs"); | 28 let {Prefs} = require("prefs"); |
| 27 let {FilterStorage} = require("filterStorage"); | 29 let {FilterStorage} = require("filterStorage"); |
| 28 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses"); | 30 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses"); |
| 29 let {defaultMatcher} = require("matcher"); | 31 let {defaultMatcher} = require("matcher"); |
| 30 let {objectMouseEventHander} = require("objectTabs"); | 32 let {objectMouseEventHander} = require("objectTabs"); |
| 31 let {RequestNotifier} = require("requestNotifier"); | 33 let {RequestNotifier} = require("requestNotifier"); |
| 32 let {ElemHide} = require("elemHide"); | 34 let {ElemHide} = require("elemHide"); |
| 33 | 35 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 localizedDescr: {}, | 81 localizedDescr: {}, |
| 80 | 82 |
| 81 /** | 83 /** |
| 82 * Lists the non-visual content types. | 84 * Lists the non-visual content types. |
| 83 * @type Object | 85 * @type Object |
| 84 */ | 86 */ |
| 85 nonVisual: {}, | 87 nonVisual: {}, |
| 86 | 88 |
| 87 /** | 89 /** |
| 88 * Map containing all schemes that should be ignored by content policy. | 90 * Map containing all schemes that should be ignored by content policy. |
| 89 * @type Object | 91 * @type Set |
| 90 */ | 92 */ |
| 91 whitelistSchemes: {}, | 93 whitelistSchemes: new Set(), |
| 92 | 94 |
| 93 /** | 95 /** |
| 94 * Called on module startup, initializes various exported properties. | 96 * Called on module startup, initializes various exported properties. |
| 95 */ | 97 */ |
| 96 init: function() | 98 init: function() |
| 97 { | 99 { |
| 98 // type constant by type description and type description by type constant | 100 // type constant by type description and type description by type constant |
| 99 let iface = Ci.nsIContentPolicy; | 101 let iface = Ci.nsIContentPolicy; |
| 100 for (let typeName of contentTypes) | 102 for (let typeName of contentTypes) |
| 101 { | 103 { |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 127 this.type.POPUP = 0xFFFE; | 129 this.type.POPUP = 0xFFFE; |
| 128 this.typeDescr[0xFFFE] = "POPUP"; | 130 this.typeDescr[0xFFFE] = "POPUP"; |
| 129 this.localizedDescr[0xFFFE] = Utils.getString("type_label_popup"); | 131 this.localizedDescr[0xFFFE] = Utils.getString("type_label_popup"); |
| 130 this.typeMask[0xFFFE] = RegExpFilter.typeMap.POPUP; | 132 this.typeMask[0xFFFE] = RegExpFilter.typeMap.POPUP; |
| 131 | 133 |
| 132 for (let type of nonVisualTypes) | 134 for (let type of nonVisualTypes) |
| 133 this.nonVisual[this.type[type]] = true; | 135 this.nonVisual[this.type[type]] = true; |
| 134 | 136 |
| 135 // whitelisted URL schemes | 137 // whitelisted URL schemes |
| 136 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" ")) | 138 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" ")) |
| 137 this.whitelistSchemes[scheme] = true; | 139 this.whitelistSchemes.add(scheme); |
| 138 | 140 |
| 139 // Generate class identifier used to collapse node and register correspondin g | 141 // Generate class identifier used to collapse node and register correspondin g |
| 140 // stylesheet. | 142 // stylesheet. |
| 141 let offset = "a".charCodeAt(0); | 143 let offset = "a".charCodeAt(0); |
| 142 for (let i = 0; i < 20; i++) | 144 for (let i = 0; i < 20; i++) |
| 143 collapsedClass += String.fromCharCode(offset + Math.random() * 26); | 145 collapsedClass += String.fromCharCode(offset + Math.random() * 26); |
| 144 | 146 |
| 145 let collapseStyle = Services.io.newURI("data:text/css," + | 147 let collapseStyle = Services.io.newURI("data:text/css," + |
| 146 encodeURIComponent("." + collapsedClass + | 148 encodeURIComponent("." + collapsedClass + |
| 147 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null); | 149 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null); |
| 148 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET); | 150 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET); |
| 149 onShutdown.add(function() | 151 onShutdown.add(() => |
| 150 { | 152 { |
| 151 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET); | 153 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET); |
| 152 }); | 154 }); |
| 153 }, | 155 }, |
| 154 | 156 |
| 155 /** | 157 /** |
| 156 * Checks whether a node should be blocked, hides it if necessary | 158 * Checks whether a node should be blocked, hides it if necessary |
| 157 * @param wnd {nsIDOMWindow} | 159 * @param wnd {nsIDOMWindow} |
| 158 * @param node {nsIDOMElement} | 160 * @param node {nsIDOMElement} |
| 159 * @param contentType {String} | 161 * @param contentType {String} |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 return !match || match instanceof WhitelistFilter; | 300 return !match || match instanceof WhitelistFilter; |
| 299 }, | 301 }, |
| 300 | 302 |
| 301 /** | 303 /** |
| 302 * Checks whether the location's scheme is blockable. | 304 * Checks whether the location's scheme is blockable. |
| 303 * @param location {nsIURI} | 305 * @param location {nsIURI} |
| 304 * @return {Boolean} | 306 * @return {Boolean} |
| 305 */ | 307 */ |
| 306 isBlockableScheme: function(location) | 308 isBlockableScheme: function(location) |
| 307 { | 309 { |
| 308 return !(location.scheme in Policy.whitelistSchemes); | 310 return !this.whitelistSchemes.has(location.scheme); |
| 309 }, | 311 }, |
| 310 | 312 |
| 311 /** | 313 /** |
| 312 * Checks whether a page is whitelisted. | 314 * Checks whether a page is whitelisted. |
| 313 * @param {String} url | 315 * @param {String} url |
| 314 * @param {String} [parentUrl] location of the parent page | 316 * @param {String} [parentUrl] location of the parent page |
| 315 * @param {String} [sitekey] public key provided on the page | 317 * @param {String} [sitekey] public key provided on the page |
| 316 * @return {Filter} filter that matched the URL or null if not whitelisted | 318 * @return {Filter} filter that matched the URL or null if not whitelisted |
| 317 */ | 319 */ |
| 318 isWhitelisted: function(url, parentUrl, sitekey) | 320 isWhitelisted: function(url, parentUrl, sitekey) |
| 319 { | 321 { |
| 320 if (!url) | 322 if (!url) |
| 321 return null; | 323 return null; |
| 322 | 324 |
| 323 // Do not apply exception rules to schemes on our whitelistschemes list. | 325 // Do not apply exception rules to schemes on our whitelistschemes list. |
| 324 let match = /^([\w\-]+):/.exec(url); | 326 let match = /^([\w\-]+):/.exec(url); |
| 325 if (match && match[1] in Policy.whitelistSchemes) | 327 if (match && this.whitelistSchemes.has(match[1])) |
| 326 return null; | 328 return null; |
| 327 | 329 |
| 328 if (!parentUrl) | 330 if (!parentUrl) |
| 329 parentUrl = url; | 331 parentUrl = url; |
| 330 | 332 |
| 331 // Ignore fragment identifier | 333 // Ignore fragment identifier |
| 332 let index = url.indexOf("#"); | 334 let index = url.indexOf("#"); |
| 333 if (index >= 0) | 335 if (index >= 0) |
| 334 url = url.substring(0, index); | 336 url = url.substring(0, index); |
| 335 | 337 |
| 336 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey); | 338 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey); |
| 337 return (result instanceof WhitelistFilter ? result : null); | 339 return (result instanceof WhitelistFilter ? result : null); |
| 338 }, | 340 }, |
| 339 | 341 |
| 340 /** | 342 /** |
| 341 * Checks whether the page loaded in a window is whitelisted for indication in the UI. | 343 * Checks whether the page loaded in a window is whitelisted for indication in the UI. |
| 342 * @param wnd {nsIDOMWindow} | 344 * @param wnd {nsIDOMWindow} |
| 343 * @return {Filter} matching exception rule or null if not whitelisted | 345 * @return {Filter} matching exception rule or null if not whitelisted |
| 344 */ | 346 */ |
| 345 isWindowWhitelisted: function(wnd) | 347 isWindowWhitelisted: function(wnd) |
| 346 { | 348 { |
| 347 return Policy.isWhitelisted(getWindowLocation(wnd)); | 349 return this.isWhitelisted(getWindowLocation(wnd)); |
| 348 }, | 350 }, |
| 349 | 351 |
| 350 /** | 352 /** |
| 351 * Asynchronously re-checks filters for given nodes. | 353 * Asynchronously re-checks filters for given nodes. |
| 352 * @param {Node[]} nodes | 354 * @param {Node[]} nodes |
| 353 * @param {RequestEntry} entry | 355 * @param {RequestEntry} entry |
| 354 */ | 356 */ |
| 355 refilterNodes: function(nodes, entry) | 357 refilterNodes: function(nodes, entry) |
| 356 { | 358 { |
| 357 // Ignore nodes that have been blocked already | 359 // Ignore nodes that have been blocked already |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 382 { | 384 { |
| 383 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); | 385 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); |
| 384 registrar.registerFactory(this.classID, this.classDescription, this.contract ID, this); | 386 registrar.registerFactory(this.classID, this.classDescription, this.contract ID, this); |
| 385 | 387 |
| 386 let catMan = Utils.categoryManager; | 388 let catMan = Utils.categoryManager; |
| 387 for (let category of this.xpcom_categories) | 389 for (let category of this.xpcom_categories) |
| 388 catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true); | 390 catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true); |
| 389 | 391 |
| 390 Services.obs.addObserver(this, "content-document-global-created", true); | 392 Services.obs.addObserver(this, "content-document-global-created", true); |
| 391 | 393 |
| 392 onShutdown.add(function() | 394 onShutdown.add(() => |
| 393 { | 395 { |
| 394 Services.obs.removeObserver(this, "content-document-global-created"); | 396 Services.obs.removeObserver(this, "content-document-global-created"); |
| 395 | 397 |
| 396 for (let category of this.xpcom_categories) | 398 for (let category of this.xpcom_categories) |
| 397 catMan.deleteCategoryEntry(category, this.contractID, false); | 399 catMan.deleteCategoryEntry(category, this.contractID, false); |
| 398 | 400 |
| 399 registrar.unregisterFactory(this.classID, this); | 401 registrar.unregisterFactory(this.classID, this); |
| 400 }.bind(this)); | 402 }); |
| 401 }, | 403 }, |
| 402 | 404 |
| 403 // | 405 // |
| 404 // nsISupports interface implementation | 406 // nsISupports interface implementation |
| 405 // | 407 // |
| 406 | 408 |
| 407 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver, | 409 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver, |
| 408 Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]), | 410 Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]), |
| 409 | 411 |
| 410 // | 412 // |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 let uri = additional || Utils.makeURI(subject.location.href); | 460 let uri = additional || Utils.makeURI(subject.location.href); |
| 459 if (!Policy.processNode(subject.opener, subject.opener.document, Policy. type.POPUP, uri, false)) | 461 if (!Policy.processNode(subject.opener, subject.opener.document, Policy. type.POPUP, uri, false)) |
| 460 { | 462 { |
| 461 subject.stop(); | 463 subject.stop(); |
| 462 Utils.runAsync(() => subject.close()); | 464 Utils.runAsync(() => subject.close()); |
| 463 } | 465 } |
| 464 else if (uri.spec == "about:blank") | 466 else if (uri.spec == "about:blank") |
| 465 { | 467 { |
| 466 // An about:blank pop-up most likely means that a load will be | 468 // An about:blank pop-up most likely means that a load will be |
| 467 // initiated asynchronously. Wait for that. | 469 // initiated asynchronously. Wait for that. |
| 468 Utils.runAsync(function() | 470 Utils.runAsync(() => |
| 469 { | 471 { |
| 470 let channel = subject.QueryInterface(Ci.nsIInterfaceRequestor) | 472 let channel = subject.QueryInterface(Ci.nsIInterfaceRequestor) |
| 471 .getInterface(Ci.nsIDocShell) | 473 .getInterface(Ci.nsIDocShell) |
| 472 .QueryInterface(Ci.nsIDocumentLoader) | 474 .QueryInterface(Ci.nsIDocumentLoader) |
| 473 .documentChannel; | 475 .documentChannel; |
| 474 if (channel) | 476 if (channel) |
| 475 this.observe(subject, topic, data, channel.URI); | 477 this.observe(subject, topic, data, channel.URI); |
| 476 }); | 478 }); |
| 477 } | 479 } |
| 478 break; | 480 break; |
| 479 } | 481 } |
| 480 } | 482 } |
| 481 }, | 483 }, |
| 482 | 484 |
| 483 // | 485 // |
| 484 // nsIChannelEventSink interface implementation | 486 // nsIChannelEventSink interface implementation |
| 485 // | 487 // |
| 486 | 488 |
| 487 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) | 489 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) |
| 488 { | 490 { |
| 489 let result = Cr.NS_OK; | 491 let result = Cr.NS_OK; |
| 490 try | 492 try |
| 491 { | 493 { |
| 492 // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then | 494 // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then |
| 493 // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44. | 495 // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44. |
| 494 let loadInfo = oldChannel.loadInfo; | 496 let loadInfo = oldChannel.loadInfo; |
| 495 let contentType = loadInfo.externalContentPolicyType || loadInfo.contentPo licyType; | 497 let contentType = ("externalContentPolicyType" in loadInfo ? |
| 498 loadInfo.externalContentPolicyType : loadInfo.contentPolicyType); | |
| 496 if (!contentType) | 499 if (!contentType) |
| 497 return; | 500 return; |
| 498 | 501 |
| 499 let wnd = Utils.getRequestWindow(newChannel); | 502 let wnd = Utils.getRequestWindow(newChannel); |
| 500 if (!wnd) | 503 if (!wnd) |
| 501 return; | 504 return; |
| 502 | 505 |
| 503 if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) | 506 if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) |
| 504 { | 507 { |
| 505 if (wnd.history.length <= 1 && wnd.opener) | 508 if (wnd.history.length <= 1 && wnd.opener) |
| 506 { | 509 { |
| 507 // Special treatment for pop-up windows. Note that we might not have | 510 // Special treatment for pop-up windows - this will close the window |
| 511 // rather than preventing the redirect. Note that we might not have | |
| 508 // seen the original channel yet because the redirect happened before | 512 // seen the original channel yet because the redirect happened before |
| 509 // the async code in observe() had a chance to run. | 513 // the async code in observe() had a chance to run. |
| 510 this.observe(wnd, "content-document-global-created", null, oldChannel. URI); | 514 this.observe(wnd, "content-document-global-created", null, oldChannel. URI); |
| 511 this.observe(wnd, "content-document-global-created", null, newChannel. URI); | 515 this.observe(wnd, "content-document-global-created", null, newChannel. URI); |
| 512 } | 516 } |
|
tschuster
2015/11/05 15:27:18
I think your comment about this patch set would he
Wladimir Palant
2015/11/05 15:51:59
Done.
| |
| 513 return; | 517 return; |
| 514 } | 518 } |
| 515 | 519 |
| 516 if (!Policy.processNode(wnd, wnd.document, contentType, newChannel.URI, fa lse)) | 520 if (!Policy.processNode(wnd, wnd.document, contentType, newChannel.URI, fa lse)) |
| 517 result = Cr.NS_BINDING_ABORTED; | 521 result = Cr.NS_BINDING_ABORTED; |
| 518 } | 522 } |
| 519 catch (e) | 523 catch (e) |
| 520 { | 524 { |
| 521 // We shouldn't throw exceptions here - this will prevent the redirect. | 525 // We shouldn't throw exceptions here - this will prevent the redirect. |
| 522 Cu.reportError(e); | 526 Cu.reportError(e); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 725 if (!wnd || wnd.closed) | 729 if (!wnd || wnd.closed) |
| 726 return; | 730 return; |
| 727 | 731 |
| 728 if (entry.type == Policy.type.OBJECT) | 732 if (entry.type == Policy.type.OBJECT) |
| 729 { | 733 { |
| 730 node.removeEventListener("mouseover", objectMouseEventHander, true); | 734 node.removeEventListener("mouseover", objectMouseEventHander, true); |
| 731 node.removeEventListener("mouseout", objectMouseEventHander, true); | 735 node.removeEventListener("mouseout", objectMouseEventHander, true); |
| 732 } | 736 } |
| 733 Policy.processNode(wnd, node, entry.type, Utils.makeURI(entry.location), true) ; | 737 Policy.processNode(wnd, node, entry.type, Utils.makeURI(entry.location), true) ; |
| 734 } | 738 } |
| LEFT | RIGHT |