[tor-commits] [torbutton/master] Bug 18913: about:tor should not have chrome privileges
gk at torproject.org
gk at torproject.org
Wed Jul 5 15:38:11 UTC 2017
commit 32f9cf56c89ccd2e24924975dc5515e4198d28c3
Author: Kathy Brade <brade at pearlcrescent.com>
Date: Sat Jun 24 08:52:19 2017 -0400
Bug 18913: about:tor should not have chrome privileges
Rearchitect our implementation so that about:tor pages are always
loaded in a content process. This also fixes:
Bug 22535: Searching brings me to duckduckgo but my query is discarded.
Bug 21948: Going back to about:tor page gives "Address isn't valid" error.
Most of the code that initializes and updates about:tor content has
been moved to a content script. When necessary, IPC is used to pass
data from the chrome process to the content script.
Removed old, no-longer-used m_tb_orig_BrowserOnAboutPageLoad variable
from torbutton.js.
Also, update the about:tor newChannel() implementation to accept an
nsILoadInfo parameter.
---
src/chrome.manifest | 3 -
src/chrome/content/aboutTor/aboutTor-content.js | 328 ++++++++++++++++++++++++
src/chrome/content/aboutTor/aboutTor.xhtml | 143 +----------
src/chrome/content/torbutton.js | 257 ++++++-------------
src/chrome/skin/aboutTor.css | 11 +-
src/components/aboutTor.js | 21 +-
src/components/startup-observer.js | 7 +-
7 files changed, 441 insertions(+), 329 deletions(-)
diff --git a/src/chrome.manifest b/src/chrome.manifest
index 75bef4e..272401b 100644
--- a/src/chrome.manifest
+++ b/src/chrome.manifest
@@ -152,9 +152,6 @@ contract @torproject.org/startup-observer;1 {06322def-6fde-4c06-aef6-47ae8e79962
component {e6204253-b690-4159-bfe8-d4eedab6b3be} components/cookie-jar-selector.js
contract @torproject.org/cookie-jar-selector;1 {e6204253-b690-4159-bfe8-d4eedab6b3be}
-component {84d47da6-79c3-4661-aa9f-8049476f7bf5} components/aboutTor.js
-contract @mozilla.org/network/protocol/about;1?what=tor {84d47da6-79c3-4661-aa9f-8049476f7bf5}
-
component {5d57312b-5d8c-4169-b4af-e80d6a28a72e} components/torCheckService.js
contract @torproject.org/torbutton-torCheckService;1 {5d57312b-5d8c-4169-b4af-e80d6a28a72e}
diff --git a/src/chrome/content/aboutTor/aboutTor-content.js b/src/chrome/content/aboutTor/aboutTor-content.js
new file mode 100644
index 0000000..ec515bb
--- /dev/null
+++ b/src/chrome/content/aboutTor/aboutTor-content.js
@@ -0,0 +1,328 @@
+/*************************************************************************
+ * Copyright (c) 2017, The Tor Project, Inc.
+ * See LICENSE for licensing information.
+ *
+ * vim: set sw=2 sts=2 ts=8 et syntax=javascript:
+ *
+ * about:tor content script
+ *************************************************************************/
+
+/*
+ * The following about:tor IPC messages are exchanged by this code and
+ * the code in torbutton.js:
+ * AboutTor:Loaded page loaded content -> chrome
+ * AboutTor:ChromeData privileged data chrome -> content
+ * AboutTor:GetToolbarData request toolbar info content -> chrome
+ * AboutTor:ToolbarData toolbar info chrome -> content
+ */
+
+var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+
+Cu.import("resource://gre/modules/Services.jsm");
+let { bindPrefAndInit } = Cu.import("resource://torbutton/modules/utils.js", {});
+
+
+var AboutTorListener = {
+ kAboutTorMessages: [ "AboutTor:ChromeData", "AboutTor:ToolbarData" ],
+
+ get isAboutTor() {
+ return content.document.documentURI.toLowerCase() == "about:tor";
+ },
+
+ init: function(aChromeGlobal) {
+ aChromeGlobal.addEventListener("AboutTorLoad", this, false, true);
+ },
+
+ handleEvent: function(aEvent) {
+ if (!this.isAboutTor)
+ return;
+
+ switch (aEvent.type) {
+ case "AboutTorLoad":
+ this.onPageLoad();
+ break;
+ case "pagehide":
+ this.onPageHide();
+ break;
+ case "resize":
+ sendAsyncMessage("AboutTor:GetToolbarData");
+ break;
+ }
+ },
+
+ receiveMessage: function(aMessage) {
+ if (!this.isAboutTor)
+ return;
+
+ switch (aMessage.name) {
+ case "AboutTor:ChromeData":
+ this.onChromeDataUpdate(aMessage.data);
+ break;
+ case "AboutTor:ToolbarData":
+ this.onToolbarDataUpdate(aMessage.data);
+ break;
+ }
+ },
+
+ onPageLoad: function() {
+ // Arrange to update localized text and links.
+ bindPrefAndInit("general.useragent.locale", aNewVal => {
+ this.onLocaleChange(aNewVal);
+ });
+
+ // Add message and event listeners.
+ this.kAboutTorMessages.forEach(aMsg => addMessageListener(aMsg, this));
+ addMessageListener("AboutTor:ChromeData", this);
+ addEventListener("pagehide", this, false);
+ addEventListener("resize", this, false);
+
+ sendAsyncMessage("AboutTor:Loaded");
+ },
+
+ onPageHide: function() {
+ removeEventListener("resize", this, false);
+ removeEventListener("pagehide", this, false);
+ this.kAboutTorMessages.forEach(aMsg => removeMessageListener(aMsg, this));
+ },
+
+ onChromeDataUpdate: function(aData) {
+ let body = content.document.body;
+
+ // Update status: tor on/off, update needed, Tor Browser manual shown.
+ if (aData.torOn)
+ body.setAttribute("toron", "yes");
+ else
+ body.removeAttribute("toron");
+
+ if (aData.updateNeeded)
+ body.setAttribute("torNeedsUpdate", "yes");
+ else
+ body.removeAttribute("torNeedsUpdate");
+
+ if (aData.showManual)
+ body.setAttribute("showmanual", "yes");
+ else
+ body.removeAttribute("showmanual");
+
+ // Setting body.initialized="yes" displays the body, which must be done
+ // at this point because our remaining initialization depends on elements
+ // being visible so that their size and position are accurate.
+ body.setAttribute("initialized", "yes");
+
+ let containerName = "torstatus-" + (aData.torOn ? "on" : "off") +
+ "-container";
+ this.adjustFontSizes(containerName);
+
+ this.onToolbarDataUpdate(aData);
+ },
+
+ onToolbarDataUpdate: function(aData) {
+ this.adjustArrow(aData.toolbarButtonXPos);
+ },
+
+ onLocaleChange: function(aLocale) {
+ this.insertPropertyStrings();
+
+ // Set Tor Browser manual link.
+ content.document.getElementById("manualLink").href =
+ "https://tb-manual.torproject.org/" + aLocale;
+
+ // Insert "Test Tor Network Settings" url.
+ let elem = content.document.getElementById("testTorSettings");
+ if (elem) {
+ let url = Services.prefs.getCharPref(
+ "extensions.torbutton.test_url_interactive");
+ elem.href = url.replace(/__LANG__/g, aLocale.replace(/-/g, '_'));
+ }
+
+ // Display the Tor Browser product name and version.
+ try {
+ const kBrandBundle = "chrome://branding/locale/brand.properties";
+ let brandBundle = Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(Ci.nsIStringBundleService)
+ .createBundle(kBrandBundle);
+ let productName = brandBundle.GetStringFromName("brandFullName");
+ let tbbVersion = Services.prefs.getCharPref("torbrowser.version");
+ elem = content.document.getElementById("torstatus-version");
+
+ while (elem.firstChild)
+ elem.removeChild(elem.firstChild);
+ elem.appendChild(content.document.createTextNode(productName + '\n'
+ + tbbVersion));
+ } catch (e) {}
+ },
+
+ insertPropertyStrings: function() {
+ try {
+ let kPropertiesURL = "chrome://torbutton/locale/aboutTor.properties";
+
+ let stringBundle = Services.strings.createBundle(kPropertiesURL);
+ let s1 = stringBundle.GetStringFromName("aboutTor.searchDDG.privacy.link");
+ let s2 = stringBundle.GetStringFromName("aboutTor.searchDDG.search.link");
+ let result = stringBundle.formatStringFromName(
+ "aboutTor.searchDDG.privacy", [s1, s2], 2);
+ if (result) {
+ let elem = content.document.getElementById("searchProviderInfo");
+ if (elem)
+ elem.innerHTML = result;
+ }
+ } catch(e) {}
+ },
+
+ // Ensure that text in top area does not overlap the tor on/off (onion) image.
+ // This is done by reducing the font sizes as necessary.
+ adjustFontSizes: function(aContainerName)
+ {
+ let imgElem = content.document.getElementById("torstatus-image");
+ let containerElem = content.document.getElementById(aContainerName);
+ if (!imgElem || !containerElem)
+ return;
+
+ try
+ {
+ let imgRect = imgElem.getBoundingClientRect();
+
+ for (let textElem = containerElem.firstChild; textElem;
+ textElem = textElem.nextSibling)
+ {
+ if ((textElem.nodeType != textElem.ELEMENT_NODE) ||
+ (textElem.nodeName.toLowerCase() == "br"))
+ {
+ continue;
+ }
+
+ let textRect = textElem.getBoundingClientRect();
+ if (0 == textRect.width)
+ continue;
+
+ // Reduce font to 90% of previous size, repeating the process up to 7
+ // times. This allows for a maximum reduction to just less than 50% of
+ // the original size.
+ let maxTries = 7;
+ while ((textRect.left < imgRect.right) && (--maxTries >= 0))
+ {
+ let style = content.document.defaultView
+ .getComputedStyle(textElem, null);
+ let fontSize = parseFloat(style.getPropertyValue("font-size"));
+ textElem.style.fontSize = (fontSize * 0.9) + "px";
+ textRect = textElem.getBoundingClientRect();
+ }
+ }
+
+ } catch (e) {}
+ },
+
+ adjustArrow: function(aToolbarButtonXPos)
+ {
+ let win = content;
+ let doc = content.document;
+ let textElem = doc.getElementById("updatePrompt");
+ let arrowHeadDiv = doc.getElementById("toolbarIconArrowHead");
+ let vertExtDiv = doc.getElementById("toolbarIconArrowVertExtension");
+ let bendDiv = doc.getElementById("toolbarIconArrowBend");
+ let horzExtDiv = doc.getElementById("toolbarIconArrowHorzExtension");
+ if (!textElem || !arrowHeadDiv || !vertExtDiv || !bendDiv || !horzExtDiv)
+ return;
+
+ let arrowTailElems = [ vertExtDiv, bendDiv, horzExtDiv ];
+ if (!aToolbarButtonXPos || isNaN(aToolbarButtonXPos) ||
+ (aToolbarButtonXPos < 0))
+ {
+ arrowHeadDiv.style.display = "none";
+ for (let elem of arrowTailElems)
+ elem.style.display = "none";
+ return;
+ }
+
+ const kArrowMargin = 6; // Horizontal margin between line and text.
+ const kArrowHeadExtraWidth = 9; // Horizontal margin to the line.
+ const kArrowLineThickness = 11;
+ const kBendWidth = 22;
+ const kBendHeight = 22;
+
+ try {
+ // Compensate for any content zoom that may be in effect on about:tor.
+ // Because window.devicePixelRatio always returns 1.0 for non-Chrome
+ // windows (see bug 13875), we use screenPixelsPerCSSPixel for the
+ // content window.
+ let pixRatio = content.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .screenPixelsPerCSSPixel;
+ let tbXpos = Math.round(aToolbarButtonXPos / pixRatio);
+
+ arrowHeadDiv.style.display = "block"; // Must be visible to get offsetWidth.
+ let arrowHalfWidth = Math.round(arrowHeadDiv.offsetWidth / 2);
+ let leftAnchor = textElem.offsetLeft - kArrowMargin
+ - kBendWidth + Math.round(kArrowLineThickness / 2);
+ let rightAnchor = textElem.offsetLeft + textElem.offsetWidth
+ + kArrowMargin + arrowHalfWidth;
+
+ let isArrowOnLeft = (tbXpos < leftAnchor);
+ let isArrowOnRight = (tbXpos > rightAnchor) &&
+ (tbXpos < (win.innerWidth - arrowHalfWidth));
+ let isArrowInMiddle = (tbXpos >= leftAnchor) && (tbXpos <= rightAnchor);
+
+ if (isArrowOnLeft || isArrowOnRight || isArrowInMiddle)
+ {
+ // Position the arrow head.
+ let arrowHeadLeft = tbXpos - arrowHalfWidth;
+ arrowHeadDiv.style.left = arrowHeadLeft + "px";
+ if (isArrowOnLeft || isArrowOnRight)
+ {
+ let horzExtBottom = textElem.offsetTop +
+ Math.round((textElem.offsetHeight + kArrowLineThickness) / 2);
+
+ // Position the vertical (extended) line.
+ let arrowHeadBottom = arrowHeadDiv.offsetTop +
+ arrowHeadDiv.offsetHeight;
+ vertExtDiv.style.top = arrowHeadBottom + "px";
+ vertExtDiv.style.left = (arrowHeadLeft + kArrowHeadExtraWidth) + "px";
+ let ht = horzExtBottom - kBendHeight - arrowHeadBottom;
+ vertExtDiv.style.height = ht + "px";
+
+ // Position the bend (elbow).
+ bendDiv.style.top = (horzExtBottom - kBendHeight) + "px";
+ let bendDivLeft;
+ if (isArrowOnLeft)
+ {
+ bendDiv.setAttribute("pos", "left");
+ bendDivLeft = arrowHeadLeft + kArrowHeadExtraWidth;
+ }
+ else if (isArrowOnRight)
+ {
+ bendDiv.setAttribute("pos", "right");
+ bendDivLeft = arrowHeadLeft + kArrowHeadExtraWidth
+ + kArrowLineThickness - kBendWidth;
+ }
+ bendDiv.style.left = bendDivLeft + "px";
+
+ // Position the horizontal (extended) line.
+ horzExtDiv.style.top = (horzExtBottom - kArrowLineThickness) + "px";
+ let horzExtLeft, w;
+ if (isArrowOnLeft)
+ {
+ horzExtLeft = bendDivLeft + kBendWidth;
+ w = (textElem.offsetLeft - horzExtLeft - kArrowMargin);
+ }
+ else
+ {
+ horzExtLeft = rightAnchor - arrowHalfWidth;
+ w = tbXpos - arrowHalfWidth - horzExtLeft;
+ }
+ horzExtDiv.style.left = horzExtLeft + "px";
+ horzExtDiv.style.width = w + "px";
+ }
+ }
+
+ let headDisplay = (isArrowOnLeft || isArrowInMiddle || isArrowOnRight)
+ ? "block" : "none";
+ arrowHeadDiv.style.display = headDisplay;
+ let tailDisplay = (isArrowOnLeft || isArrowOnRight) ? "block" : "none";
+ for (let elem of arrowTailElems)
+ elem.style.display = tailDisplay;
+ } catch (e) {}
+ }
+};
+
+AboutTorListener.init(this);
diff --git a/src/chrome/content/aboutTor/aboutTor.xhtml b/src/chrome/content/aboutTor/aboutTor.xhtml
index e4050fc..7ae4b8b 100644
--- a/src/chrome/content/aboutTor/aboutTor.xhtml
+++ b/src/chrome/content/aboutTor/aboutTor.xhtml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- - Copyright (c) 2016, The Tor Project, Inc.
+ - Copyright (c) 2017, The Tor Project, Inc.
- See LICENSE for licensing information.
- vim: set sw=2 sts=2 ts=8 et syntax=xml:
-->
@@ -20,154 +20,17 @@
<head>
<title>&aboutTor.title;</title>
<link rel="stylesheet" type="text/css" media="all"
- href="chrome://torbutton/skin/aboutTor.css"/>
+ href="resource://torbutton/chrome/skin/aboutTor.css"/>
<script type="text/javascript;version=1.7">
<![CDATA[
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-function onLoad()
-{
- insertPropertyStrings();
-
- let locale = Services.prefs.getCharPref("general.useragent.locale");
- document.getElementById("manualLink").href = "https://tb-manual.torproject.org/" + locale;
-
- document.addEventListener("AboutTorAdjustArrow", function() {
- adjustToolbarIconArrow();
- }, false);
-
- window.setTimeout( function() {
- adjustToolbarIconArrow();
- }, 0);
-}
-
-function adjustToolbarIconArrow()
-{
- let textElem = document.getElementById("updatePrompt");
- let arrowHeadDiv = document.getElementById("toolbarIconArrowHead");
- let vertExtDiv = document.getElementById("toolbarIconArrowVertExtension");
- let bendDiv = document.getElementById("toolbarIconArrowBend");
- let horzExtDiv = document.getElementById("toolbarIconArrowHorzExtension");
- if (!textElem || !arrowHeadDiv || !vertExtDiv || !bendDiv || !horzExtDiv)
- return;
-
- let arrowTailElems = [ vertExtDiv, bendDiv, horzExtDiv ];
- let tbXpos;
- if (document.body.hasAttribute("torbutton-xpos"))
- tbXpos = parseInt(document.body.getAttribute("torbutton-xpos"), 10);
-
- if (!tbXpos || isNaN(tbXpos) || (tbXpos < 0))
- {
- arrowHeadDiv.style.display = "none";
- for (let elem of arrowTailElems)
- elem.style.display = "none";
- return;
- }
-
- const kArrowMargin = 6; // Horizontal margin between line and text.
- const kArrowHeadExtraWidth = 9; // Horizontal margin to the line.
- const kArrowLineThickness = 11;
- const kBendWidth = 22;
- const kBendHeight = 22;
-
- arrowHeadDiv.style.display = "block"; // Must be visible to get offsetWidth.
- let arrowHalfWidth = Math.round(arrowHeadDiv.offsetWidth / 2);
- let leftAnchor = textElem.offsetLeft - kArrowMargin
- - kBendWidth + Math.round(kArrowLineThickness / 2);
- let rightAnchor = textElem.offsetLeft + textElem.offsetWidth
- + kArrowMargin + arrowHalfWidth;
-
- let isArrowOnLeft = (tbXpos < leftAnchor);
- let isArrowOnRight = (tbXpos > rightAnchor) &&
- (tbXpos < (window.innerWidth - arrowHalfWidth));
- let isArrowInMiddle = (tbXpos >= leftAnchor) && (tbXpos <= rightAnchor);
-
- if (isArrowOnLeft || isArrowOnRight || isArrowInMiddle)
- {
- // Position the arrow head.
- let arrowHeadLeft = tbXpos - arrowHalfWidth;
- arrowHeadDiv.style.left = arrowHeadLeft + "px";
- if (isArrowOnLeft || isArrowOnRight)
- {
- let horzExtBottom = textElem.offsetTop +
- Math.round((textElem.offsetHeight + kArrowLineThickness) / 2);
-
- // Position the vertical (extended) line.
- let arrowHeadBottom = arrowHeadDiv.offsetTop + arrowHeadDiv.offsetHeight;
- vertExtDiv.style.top = arrowHeadBottom + "px";
- vertExtDiv.style.left = (arrowHeadLeft + kArrowHeadExtraWidth) + "px";
- let ht = horzExtBottom - kBendHeight - arrowHeadBottom;
- vertExtDiv.style.height = ht + "px";
-
- // Position the bend (elbow).
- bendDiv.style.top = (horzExtBottom - kBendHeight) + "px";
- let bendDivLeft;
- if (isArrowOnLeft)
- {
- bendDiv.setAttribute("pos", "left");
- bendDivLeft = arrowHeadLeft + kArrowHeadExtraWidth;
- }
- else if (isArrowOnRight)
- {
- bendDiv.setAttribute("pos", "right");
- bendDivLeft = arrowHeadLeft + kArrowHeadExtraWidth
- + kArrowLineThickness - kBendWidth;
- }
- bendDiv.style.left = bendDivLeft + "px";
-
- // Position the horizontal (extended) line.
- horzExtDiv.style.top = (horzExtBottom - kArrowLineThickness) + "px";
- let horzExtLeft, w;
- if (isArrowOnLeft)
- {
- horzExtLeft = bendDivLeft + kBendWidth;
- w = (textElem.offsetLeft - horzExtLeft - kArrowMargin);
- }
- else
- {
- horzExtLeft = rightAnchor - arrowHalfWidth;
- w = tbXpos - arrowHalfWidth - horzExtLeft;
- }
- horzExtDiv.style.left = horzExtLeft + "px";
- horzExtDiv.style.width = w + "px";
- }
- }
-
- let headDisplay = (isArrowOnLeft || isArrowInMiddle || isArrowOnRight)
- ? "block" : "none";
- arrowHeadDiv.style.display = headDisplay;
- let tailDisplay = (isArrowOnLeft || isArrowOnRight) ? "block" : "none";
- for (let elem of arrowTailElems)
- elem.style.display = tailDisplay;
-}
-
-function insertPropertyStrings()
-{
- try {
- let kPropertiesURL = "chrome://torbutton/locale/aboutTor.properties";
-
- let gStringBundle = Services.strings.createBundle(kPropertiesURL);
- let s1 = gStringBundle.GetStringFromName("aboutTor.searchDDG.privacy.link");
- let s2 = gStringBundle.GetStringFromName("aboutTor.searchDDG.search.link");
- let result = gStringBundle.formatStringFromName("aboutTor.searchDDG.privacy",
- [s1, s2], 2);
- if (result) {
- let elem = document.getElementById("searchProviderInfo");
- if (elem)
- elem.innerHTML = result;
- }
- } catch(e) {};
-}
-
window.addEventListener("pageshow", function() {
let evt = new CustomEvent("AboutTorLoad", { bubbles: true });
document.dispatchEvent(evt);
});
-
]]>
</script>
</head>
-<body dir="&locale.dir;" onload="onLoad();">
+<body dir="&locale.dir;">
<div id="torstatus" class="top">
<div id="torstatus-version"/>
<div id="torstatus-image"/>
diff --git a/src/chrome/content/torbutton.js b/src/chrome/content/torbutton.js
index ae705a3..3999bd4 100644
--- a/src/chrome/content/torbutton.js
+++ b/src/chrome/content/torbutton.js
@@ -40,8 +40,6 @@ var m_tb_control_host = null; // Set if using TCP.
var m_tb_control_pass = null;
var m_tb_control_desc = null; // For logging.
-var m_tb_orig_BrowserOnAboutPageLoad = null;
-
var m_tb_domWindowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
@@ -203,15 +201,24 @@ var torbutton_tor_check_observer = {
// Update toolbar icon and tooltip.
torbutton_update_toolbutton();
- // Update all open about:tor pages. If the user does not have an
- // about:tor page open in the front most window, open one.
- if (torbutton_update_all_abouttor_pages(undefined, false) < 1) {
- var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+ // Update all open about:tor pages.
+ torbutton_abouttor_message_handler.updateAllOpenPages();
+
+ // If the user does not have an about:tor tab open in the front most
+ // window, open one.
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
- var win = wm.getMostRecentWindow("navigator:browser");
- if (win == window) {
- gBrowser.selectedTab = gBrowser.addTab("about:tor");
+ var win = wm.getMostRecentWindow("navigator:browser");
+ if (win == window) {
+ let foundTab = false;
+ let tabBrowser = top.getBrowser();
+ for (let i = 0; !foundTab && (i < tabBrowser.browsers.length); ++i) {
+ let b = tabBrowser.getBrowserAtIndex(i);
+ foundTab = (b.currentURI.spec.toLowerCase() == "about:tor");
}
+
+ if (!foundTab)
+ gBrowser.selectedTab = gBrowser.addTab("about:tor");
}
}
}
@@ -332,10 +339,10 @@ function torbutton_init() {
}
}
- // Add event listener for about:tor page loads.
- document.addEventListener("AboutTorLoad", function(aEvent) {
- torbutton_on_abouttor_load(aEvent.target);
- }, false, true);
+ // Add about:tor IPC message listeners.
+ let aboutTorMessages = [ "AboutTor:Loaded", "AboutTor:GetToolbarData" ];
+ aboutTorMessages.forEach(aMsg => window.messageManager.addMessageListener(
+ aMsg, torbutton_abouttor_message_handler));
// XXX: Get rid of the cached asmjs (or IndexedDB) files on disk in case we
// don't allow things saved to disk. This is an ad-hoc fix to work around
@@ -365,7 +372,7 @@ function torbutton_init() {
// Detect toolbar customization and update arrow on about:tor pages.
window.addEventListener("aftercustomization", function() {
- torbutton_update_all_abouttor_pages(undefined, undefined);
+ torbutton_abouttor_message_handler.updateAllOpenPages();
}, false);
//setting up context menu
@@ -404,9 +411,58 @@ function torbutton_init() {
torbutton_init_user_manual_links();
+ // Arrange for our about:tor content script to be loaded in each frame.
+ window.messageManager.loadFrameScript(
+ "chrome://torbutton/content/aboutTor/aboutTor-content.js", true);
+
torbutton_log(3, 'init completed');
}
+var torbutton_abouttor_message_handler = {
+ // Receive IPC messages from the about:tor content script.
+ receiveMessage: function(aMessage) {
+ switch(aMessage.name) {
+ case "AboutTor:Loaded":
+ torbutton_show_sec_slider_notification();
+ aMessage.target.messageManager.sendAsyncMessage("AboutTor:ChromeData",
+ this.chromeData);
+ break;
+ case "AboutTor:GetToolbarData":
+ aMessage.target.messageManager.sendAsyncMessage("AboutTor:ToolbarData",
+ this.toolbarData);
+ break;
+ }
+ },
+
+ // Send privileged data to all of the about:tor content scripts.
+ updateAllOpenPages: function() {
+ window.messageManager.broadcastAsyncMessage("AboutTor:ChromeData",
+ this.chromeData);
+ },
+
+ // The chrome data contains all of the data needed by the about:tor
+ // content process that is only available here (in the chrome process).
+ // It is sent to the content process when an about:tor window is opened
+ // and in response to events such as the browser noticing that an update
+ // is available.
+ get chromeData() {
+ return {
+ torOn: torbutton_tor_check_ok(),
+ updateNeeded: torbutton_update_is_needed(),
+ showManual: torbutton_show_torbrowser_manual(),
+ toolbarButtonXPos: torbutton_get_toolbarbutton_xpos()
+ };
+ },
+
+ // The toolbar data only contains the x coordinate of Torbutton's toolbar
+ // item; it is sent back to the content process as the about:tor window
+ // is resized.
+ get toolbarData() {
+ return {
+ toolbarButtonXPos: torbutton_get_toolbarbutton_xpos()
+ };
+ }
+};
function torbutton_should_prompt_for_language_preference() {
return torbutton_get_general_useragent_locale().substring(0, 2) != "en" &&
@@ -570,7 +626,7 @@ function torbutton_notify_if_update_needed() {
setOrClearAttribute(btn, "tbUpdateNeeded", updateNeeded);
// Update all open about:tor pages.
- torbutton_update_all_abouttor_pages(updateNeeded, undefined);
+ torbutton_abouttor_message_handler.updateAllOpenPages();
// Make the "check for update" menu item bold if an update is needed.
var item = document.getElementById("torbutton-checkForUpdate");
@@ -597,117 +653,11 @@ function torbutton_check_for_update() {
prompter.checkForUpdates();
}
-// Pass undefined for a parameter to have this function determine it.
-// Returns a count of open pages that were updated,
-function torbutton_update_all_abouttor_pages(aUpdateNeeded, aTorIsOn) {
- if (aUpdateNeeded === undefined)
- aUpdateNeeded = torbutton_update_is_needed();
- if (aTorIsOn === undefined)
- aTorIsOn = torbutton_tor_check_ok();
-
- var count = 0;
- var tabBrowser = top.getBrowser();
- var tabs = tabBrowser.mTabs;
- if (tabs && (tabs.length > 0)) {
- for (var tab = tabs[0]; tab != null; tab = tab.nextSibling) {
- try {
- let doc = tabBrowser.getBrowserForTab(tab).contentDocument;
- if (torbutton_update_abouttor_doc(doc, aTorIsOn, aUpdateNeeded))
- ++count;
- } catch(e) {}
- }
- }
-
- return count;
-}
-
-// Returns true if aDoc is an about:tor page.
-function torbutton_update_abouttor_doc(aDoc, aTorOn, aUpdateNeeded) {
- var isAboutTor = torbutton_is_abouttor_doc(aDoc);
- if (isAboutTor) {
- if (aTorOn)
- aDoc.body.setAttribute("toron", "yes");
- else
- aDoc.body.removeAttribute("toron");
-
- if (aUpdateNeeded)
- aDoc.body.setAttribute("torNeedsUpdate", "yes");
- else
- aDoc.body.removeAttribute("torNeedsUpdate");
-
- if (torbutton_show_torbrowser_manual())
- aDoc.body.setAttribute("showmanual", "yes");
- else
- aDoc.body.removeAttribute("showmanual");
-
- // Display product name and TBB version.
- try {
- const kBrandBundle = "chrome://branding/locale/brand.properties";
- let brandBundle = Cc["@mozilla.org/intl/stringbundle;1"]
- .getService(Ci.nsIStringBundleService)
- .createBundle(kBrandBundle);
- let productName = brandBundle.GetStringFromName("brandFullName");
- let tbbVersion = m_tb_prefs.getCharPref("torbrowser.version");
- let e = aDoc.getElementById("torstatus-version");
-
- while (e.firstChild)
- e.removeChild(e.firstChild);
- e.appendChild(aDoc.createTextNode(productName + '\n' + tbbVersion));
- } catch (e) {}
-
- let containerName = "torstatus-" + (aTorOn ? "on" : "off") + "-container";
- torbutton_adjust_abouttor_fontsizes(aDoc, containerName);
- torbutton_update_abouttor_arrow(aDoc);
- }
-
- return isAboutTor;
-}
-
-// Ensure that text in top area does not overlap the tor on/off (onion) image.
-// This is done by reducing the font sizes as necessary.
-function torbutton_adjust_abouttor_fontsizes(aDoc, aContainerName)
-{
- let imgElem = aDoc.getElementById("torstatus-image");
- let containerElem = aDoc.getElementById(aContainerName);
- if (!imgElem || !containerElem)
- return;
-
- try
- {
- let imgRect = imgElem.getBoundingClientRect();
-
- for (let textElem = containerElem.firstChild; textElem;
- textElem = textElem.nextSibling)
- {
- if ((textElem.nodeType != textElem.ELEMENT_NODE) ||
- (textElem.nodeName.toLowerCase() == "br"))
- {
- continue;
- }
-
- let textRect = textElem.getBoundingClientRect();
- if (0 == textRect.width)
- continue;
-
- // Reduce font to 90% of previous size, repeating the process up to 7
- // times. This allows for a maximum reduction to just less than 50% of
- // the original size.
- let maxTries = 7;
- while ((textRect.left < imgRect.right) && (--maxTries >= 0))
- {
- let style = aDoc.defaultView.getComputedStyle(textElem, null);
- let fontSize = parseFloat(style.getPropertyValue("font-size"));
- textElem.style.fontSize = (fontSize * 0.9) + "px";
- textRect = textElem.getBoundingClientRect();
- }
- }
- } catch (e) {}
-}
-
-// Determine X position of torbutton toolbar item and pass it through
-// to the xhtml document by setting a torbutton-xpos attribute on the body.
-// The value that is set takes retina displays and content zoom into account.
-function torbutton_update_abouttor_arrow(aDoc) {
+// Determine X position of Torbutton toolbar item. The value returned
+// accounts for retina but not content zoom.
+// undefined is returned if the value cannot be determined (e.g., if the
+// toolbar item is not on the toolbar).
+function torbutton_get_toolbarbutton_xpos() {
try {
let tbXpos = -1;
let tbItem = torbutton_get_toolbutton();
@@ -721,55 +671,16 @@ function torbutton_update_abouttor_arrow(aDoc) {
}
if (tbXpos >= 0) {
- // Convert to device-independent units, compensating for retina display
- // and content zoom that may be in effect on the about:tor page.
- // Because window.devicePixelRatio always returns 1.0 for non-Chrome
- // windows (see bug 13875), we use screenPixelsPerCSSPixel for the
- // content window.
+ // Convert to device-independent units, compensating for retina display.
tbXpos *= window.devicePixelRatio;
- let pixRatio = gBrowser.contentWindow
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .screenPixelsPerCSSPixel;
- tbXpos = Math.round(tbXpos / pixRatio);
- aDoc.body.setAttribute("torbutton-xpos", tbXpos);
- } else {
- aDoc.body.removeAttribute("torbutton-xpos");
+ return tbXpos;
}
-
- let evt = new Event("AboutTorAdjustArrow");
- aDoc.dispatchEvent(evt);
} catch(e) {}
-}
-
-function torbutton_on_abouttor_load(aDoc) {
- if (torbutton_is_abouttor_doc(aDoc) &&
- !aDoc.documentElement.hasAttribute("aboutTorLoaded")) {
- aDoc.documentElement.setAttribute("aboutTorLoaded", true);
-
- // Show correct Tor on/off and "update needed" status.
- let torOn = torbutton_tor_check_ok();
- let needsUpdate = torbutton_update_is_needed();
- torbutton_update_abouttor_doc(aDoc, torOn, needsUpdate);
-
- aDoc.defaultView.addEventListener("resize",
- function() { torbutton_update_abouttor_arrow(aDoc); },
- false);
-
- // Insert "Test Tor Network Settings" url.
- let elem = aDoc.getElementById("testTorSettings");
- if (elem) {
- let locale = m_tb_prefs.getCharPref("general.useragent.locale");
- locale = locale.replace(/-/g, '_');
- let url = m_tb_prefs.getCharPref(
- "extensions.torbutton.test_url_interactive");
- elem.href = url.replace(/__LANG__/g, locale);
- }
- }
- if (m_tb_orig_BrowserOnAboutPageLoad)
- m_tb_orig_BrowserOnAboutPageLoad(aDoc);
+ return undefined;
+}
+function torbutton_show_sec_slider_notification() {
// Show the notification about the new security slider.
if (m_tb_prefs.
getBoolPref("extensions.torbutton.show_slider_notification")) {
@@ -797,10 +708,6 @@ function torbutton_on_abouttor_load(aDoc) {
}
}
-function torbutton_is_abouttor_doc(aDoc) {
- return (aDoc && /^about:tor$/i.test(aDoc.documentURI.toLowerCase()));
-}
-
// Bug 1506 P4: Checking for Tor Browser updates is pretty important,
// probably even as a fallback if we ever do get a working updater.
function torbutton_do_async_versioncheck() {
@@ -2449,7 +2356,7 @@ function torbutton_init_user_manual_links() {
let menuitem = document.getElementById("torBrowserUserManual");
bindPrefAndInit("general.useragent.locale", val => {
menuitem.hidden = !torbutton_show_torbrowser_manual();
- torbutton_update_all_abouttor_pages(undefined, undefined);
+ torbutton_abouttor_message_handler.updateAllOpenPages();
});
}
diff --git a/src/chrome/skin/aboutTor.css b/src/chrome/skin/aboutTor.css
index 3f747a9..c0d2ebc 100644
--- a/src/chrome/skin/aboutTor.css
+++ b/src/chrome/skin/aboutTor.css
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Tor Project, Inc.
+ * Copyright (c) 2017, The Tor Project, Inc.
* See LICENSE for licensing information.
*
* vim: set sw=2 sts=2 ts=8 et syntax=css:
@@ -34,6 +34,15 @@ body[toron] {
background-image: -moz-linear-gradient(top, #ffffff, #ffffff 10%, #d5ffd5 50%, #d5ffd5);
}
+/* Hide the entire document by default to avoid showing the incorrect
+ * Tor on / off status (that info must be retrieved from the chrome
+ * process, which involves IPC when multiprocess mode is enabled). An
+ * initialized attribute will be added as soon as the status is known.
+ */
+body:not([initialized]) {
+ display: none;
+}
+
#torstatus-version {
position: fixed;
top: 6px;
diff --git a/src/components/aboutTor.js b/src/components/aboutTor.js
index 2a3431f..e3ee03d 100644
--- a/src/components/aboutTor.js
+++ b/src/components/aboutTor.js
@@ -1,9 +1,9 @@
/*************************************************************************
- * Copyright (c) 2013, The Tor Project, Inc.
+ * Copyright (c) 2017, The Tor Project, Inc.
* See LICENSE for licensing information.
*
* vim: set sw=2 sts=2 ts=8 et syntax=javascript:
- *
+ *
* about:tor component
*************************************************************************/
@@ -17,9 +17,9 @@ const kAboutTorURL = "chrome://torbutton/content/aboutTor/aboutTor.xhtml";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
-
+
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
+
function AboutTor()
{
}
@@ -35,11 +35,12 @@ AboutTor.prototype =
contractID: kMODULE_CONTRACTID,
// nsIAboutModule implementation:
- newChannel: function(aURI)
+ newChannel: function(aURI, aLoadInfo)
{
let ioSvc = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
- let channel = ioSvc.newChannel(kAboutTorURL, null, null);
+ let uri = ioSvc.newURI(kAboutTorURL, null, null);
+ let channel = ioSvc.newChannelFromURIWithLoadInfo(uri, aLoadInfo);
channel.originalURI = aURI;
return channel;
@@ -47,9 +48,13 @@ AboutTor.prototype =
getURIFlags: function(aURI)
{
- return Ci.nsIAboutModule.ALLOW_SCRIPT;
+ return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
+ Ci.nsIAboutModule.ALLOW_SCRIPT;
}
};
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutTor]);
+let factory = XPCOMUtils._getFactory(AboutTor);
+let reg = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+reg.registerFactory(kMODULE_CID, "", kMODULE_CONTRACTID, factory);
diff --git a/src/components/startup-observer.js b/src/components/startup-observer.js
index 65ca659..dac7aff 100644
--- a/src/components/startup-observer.js
+++ b/src/components/startup-observer.js
@@ -61,12 +61,15 @@ function StartupObserver() {
this.logger.log(4, "Early proxy change failed. Will try again at profile load. Error: "+e);
}
- // Arrange for our nsIContentPolicy filter to be loaded in the
- // default (chrome) process as well as in each content process.
+ // Arrange for our nsIContentPolicy filter and about:tor handler to be
+ // loaded in the default (chrome) process as well as in each content
+ // process.
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIProcessScriptLoader);
ppmm.loadProcessScript("resource://torbutton/components/content-policy.js",
true);
+ ppmm.loadProcessScript("resource://torbutton/components/aboutTor.js",
+ true);
}
StartupObserver.prototype = {
More information about the tor-commits
mailing list