Commit 32f9cf56 authored by Kathleen Brade's avatar Kathleen Brade
Browse files

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.
parent b917b202
......@@ -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}
......
/*************************************************************************
* 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);
<?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"/>
......
......@@ -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;