From 583cb454ed795ae5a8540e9187231df05e6ba76c Mon Sep 17 00:00:00 2001 From: Martin Kimmerle Date: Sat, 8 Nov 2014 17:08:05 +0100 Subject: [PATCH] whitelist known non-host uri schemes, see #447 --- src/content/overlay.js | 50 +++++++++++++ src/content/requestLog.js | 10 +-- src/modules/Request.jsm | 120 +++++++++++++++++++++++++++++++ src/modules/RequestProcessor.jsm | 7 ++ src/modules/Util.jsm | 9 +++ 5 files changed, 188 insertions(+), 8 deletions(-) diff --git a/src/content/overlay.js b/src/content/overlay.js index 65f4a932..958d5877 100644 --- a/src/content/overlay.js +++ b/src/content/overlay.js @@ -337,6 +337,56 @@ requestpolicy.overlay = { } }, + /** + * Shows a notification that an unknown scheme has been detected. + * This notification in only necessary for 1.0 beta versions until custom + * URI schemes are supported in RequestPolicy. + * + * issue: https://github.com/RequestPolicyContinued/requestpolicy/issues/447 + * + * @param {nsIDOMWindow} contentWindow + * @param {String} scheme + */ + showSchemeNotification : function(contentWindow, scheme) { + let browser = gBrowser.getBrowserForContentWindow(contentWindow); + let notificationBox = gBrowser.getNotificationBox(browser) + let notificationValue = "requestpolicy-scheme-notification"; + + let notification = notificationBox + .getNotificationWithValue(notificationValue); + + var notificationLabel = "This page contains a request with a '" + scheme + + "' scheme which is unknown to RequestPolicy. Please report it."; + + if (notification) { + notification.label = notificationLabel; + } else { + var buttons = [ + { + label : "report this / more info", + accessKey : "r", + popup : null, + callback : function() { + let url = "https://github.com/RequestPolicyContinued/requestpolicy/issues/447"; + window.openUILinkIn(url, "tab", {relatedToCurrent: true}); + } + }, + { + label : "hide", + accessKey : "h", + popup : null, + callback : function() { + // Do nothing. The notification closes when this is called. + } + } + ]; + const priority = notificationBox.PRIORITY_WARNING_LOW; + let iconURI = "chrome://requestpolicy/skin/requestpolicy-icon-blocked.png"; + notificationBox.appendNotification(notificationLabel, notificationValue, + iconURI, priority, buttons); + } + }, + /** * Shows a notification that a redirect was requested by a page (meta refresh * or with headers). diff --git a/src/content/requestLog.js b/src/content/requestLog.js index 22de6a20..94ef72a2 100644 --- a/src/content/requestLog.js +++ b/src/content/requestLog.js @@ -26,6 +26,7 @@ if (!rp) { } Components.utils.import("resource://requestpolicy/DomainUtil.jsm", rp.mod); +Components.utils.import("resource://requestpolicy/Util.jsm", rp.mod); Components.utils.import("resource://requestpolicy/Prompter.jsm", rp.mod); requestpolicy.requestLog = { @@ -89,15 +90,8 @@ requestpolicy.requestLog = { return; } - var mainWindow = window - .QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIWebNavigation) - .QueryInterface(Components.interfaces.nsIDocShellTreeItem).rootTreeItem - .QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIDOMWindow); - mainWindow.gBrowser.addTab(content); + rp.mod.Util.getChromeWindow(window).gBrowser.addTab(content); } - }; addEventListener("load", function(event) { diff --git a/src/modules/Request.jsm b/src/modules/Request.jsm index 6f079b16..de4bb29d 100644 --- a/src/modules/Request.jsm +++ b/src/modules/Request.jsm @@ -42,6 +42,7 @@ if (!rp) { } Components.utils.import("resource://requestpolicy/DomainUtil.jsm", rp.mod); Components.utils.import("resource://requestpolicy/Logger.jsm", rp.mod); +Components.utils.import("resource://requestpolicy/Util.jsm", rp.mod); @@ -198,6 +199,125 @@ NormalRequest.prototype.isInternal = function() { return false; }; +/** + * Get the nsIDOMWindow related to this request. + */ +NormalRequest.prototype.getWindow = function() { + let context = this.aContext; + if (!context) { + return null; + } + + let win; + try { + win = context.QueryInterface(CI.nsIDOMWindow); + } catch (e) { + let doc; + try { + doc = context.QueryInterface(CI.nsIDOMDocument); + } catch (e) { + try { + doc = context.QueryInterface(CI.nsIDOMNode).ownerDocument; + } catch(e) { + return null; + } + } + win = doc.defaultView; + } + return win; +}; + + +// see https://github.com/RequestPolicyContinued/requestpolicy/issues/447 +var knownSchemesWithoutHost = [ + // common schemes + "about", + "feed", + "mediasource", + "mailto", + + // custom schemes + "magnet", + "UT2004" +]; + +function isKnownSchemeWithoutHost(scheme) { + for (let i = 0, len = knownSchemesWithoutHost.length; i < len; ++i) { + if (scheme == knownSchemesWithoutHost[i]) { + return true; + } + } + return false; +} + +NormalRequest.prototype.checkURISchemes = function() { +/** + * This is a workaround to the problem that RequestPolicy currently cannot + * handle some URIs. This workaround should be removed not later than for + * the stable 1.0 release. + * + * see https://github.com/RequestPolicyContinued/requestpolicy/issues/447 + * + * TODO: solve this problem and remove this workaround. + */ + let uris = [this.aContentLocation, this.aRequestOrigin]; + for (let i = 0; i < 2; ++i) { + let uri = uris[i]; + + // filter URIs which *do* have a host + try { + // this might throw NS_ERROR_FAILURE + if (uri.host) { + continue; + } + } catch(e) {} + + // ensure that the URI has a scheme + try { + if (!uri.scheme) { + throw "no scheme!"; + } + } catch(e) { + rp.mod.Logger.warning(rp.mod.Logger.TYPE_CONTENT, + "URI <" + uri.spec + "> has no scheme!"); + continue; + } + + let scheme = uri.scheme; + if (scheme == "file") { + continue; + } + + if (isKnownSchemeWithoutHost(scheme)) { + rp.mod.Logger.warning(rp.mod.Logger.TYPE_CONTENT, + "RequestPolicy currently cannot handle '" + scheme + "' schemes. " + + "Therefore the request from <" + this.originURI + "> to <" + + this.destURI + "> is allowed (but not recorded)."); + // tell shouldLoad() to return CP_OK: + return {shouldLoad: true}; + } + + // if we get here, the scheme is unknown. try to show a notification. + rp.mod.Logger.warning(rp.mod.Logger.TYPE_CONTENT, + "uncatched scheme '" + scheme + "'. The request is from <" + + this.originURI + "> to <" + this.destURI + "> "); + try { + let win = this.getWindow(); + if (!win) { + throw "The window could not be extracted from aContext."; + } + rp.mod.Util.getChromeWindow(win).requestpolicy.overlay + .showSchemeNotification(win, scheme); + } catch (e) { + rp.mod.Logger.warning(rp.mod.Logger.TYPE_ERROR, + "The user could not be informed about the " + + "unknown scheme. Error was: " + e); + } + } + + return {shouldLoad: null}; +}; + diff --git a/src/modules/RequestProcessor.jsm b/src/modules/RequestProcessor.jsm index b15f1a3f..5b23f05a 100644 --- a/src/modules/RequestProcessor.jsm +++ b/src/modules/RequestProcessor.jsm @@ -232,6 +232,13 @@ RequestProcessor.prototype.process = function(request) { } } + + if (request.checkURISchemes().shouldLoad === true) { + return CP_OK; + } + + + // Note: If changing the logic here, also make necessary changes to // isAllowedRedirect). diff --git a/src/modules/Util.jsm b/src/modules/Util.jsm index 810fcd9f..50d019fd 100644 --- a/src/modules/Util.jsm +++ b/src/modules/Util.jsm @@ -53,5 +53,14 @@ var Util = { isFirefox : function() { return this.appInfo.ID == FIREFOX_ID; + }, + + getChromeWindow : function(aContentWindow) { + return aContentWindow.QueryInterface(CI.nsIInterfaceRequestor) + .getInterface(CI.nsIWebNavigation) + .QueryInterface(CI.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(CI.nsIInterfaceRequestor) + .getInterface(CI.nsIDOMWindow); } }