richard pushed to branch tor-browser-115.2.1esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits: de6b3303 by Henry Wilkes at 2023-09-19T01:24:50+00:00 fixup! Bug 30237: Add v3 onion services client authentication prompt
Bug 42091: Tidy up authPrompt.jsm.
Stop importing modules to the global scope and remove authUtil.jsm.
Refactor the description string handling.
- - - - - 1a422b66 by Henry Wilkes at 2023-09-19T01:24:50+00:00 fixup! Add TorStrings module for localization
Bug 42091: Remove authPrompt "Learn More" href from TorStrings.
- - - - - 7c864096 by Henry Wilkes at 2023-09-19T01:24:50+00:00 Bug 42110: Add TorUIUtils module for common tor component methods.
- - - - - 6662e2dd by Henry Wilkes at 2023-09-19T01:24:50+00:00 fixup! Bug 41600: Add a tor circuit display panel.
Bug 42091: Use TorUIUtils to shorten the onion address.
- - - - - d66b44eb by Henry Wilkes at 2023-09-19T01:24:50+00:00 fixup! Bug 30237: Add v3 onion services client authentication prompt
Bug 42091: Shorten the shown onion address in the auth prompt.
- - - - - 6f0199ab by Henry Wilkes at 2023-09-19T01:24:50+00:00 fixup! Bug 23247: Communicating security expectations for .onion
Bug 42091: Shorten onion address in site identity panel to be consistent with the circuit display.
- - - - -
10 changed files:
- browser/base/content/browser-siteIdentity.js - browser/base/content/browser.js - browser/components/onionservices/content/authPreferences.js - browser/components/onionservices/content/authPrompt.js - − browser/components/onionservices/content/authUtil.jsm - browser/components/onionservices/jar.mn - browser/components/torcircuit/content/torCircuitPanel.js - browser/modules/TorStrings.jsm - + browser/modules/TorUIUtils.sys.mjs - browser/modules/moz.build
Changes:
===================================== browser/base/content/browser-siteIdentity.js ===================================== @@ -729,7 +729,15 @@ var gIdentityHandler = { host = this._uri.specIgnoringRef; }
- return host; + // For tor browser we want to shorten onion addresses for the site identity + // panel (gIdentityHandler) to match the circuit display and the onion + // authorization panel. + // See tor-browser#42091 and tor-browser#41600. + // This will also shorten addresses for other consumers of this method, + // which includes the permissions panel (gPermissionPanel) and the + // protections panel (gProtectionsHandler), although the latter is hidden in + // tor browser. + return TorUIUtils.shortenOnionAddress(host); },
/**
===================================== browser/base/content/browser.js ===================================== @@ -67,6 +67,7 @@ ChromeUtils.defineESModuleGetters(this, { "resource:///modules/firefox-view-tabs-setup-manager.sys.mjs", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs", TorDomainIsolator: "resource://gre/modules/TorDomainIsolator.sys.mjs", + TorUIUtils: "resource:///modules/TorUIUtils.sys.mjs", TranslationsParent: "resource://gre/actors/TranslationsParent.sys.mjs", UITour: "resource:///modules/UITour.sys.mjs", UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs",
===================================== browser/components/onionservices/content/authPreferences.js ===================================== @@ -42,10 +42,11 @@ const OnionServicesAuthPreferences = {
elem = groupbox.querySelector(this.selector.learnMore); elem.setAttribute("value", TorStrings.onionServices.learnMore); - elem.setAttribute("href", TorStrings.onionServices.learnMoreURL); - if (TorStrings.onionServices.learnMoreURL.startsWith("about:")) { - elem.setAttribute("useoriginprincipal", "true"); - } + elem.setAttribute( + "href", + "about:manual#onion-services_onion-service-authentication" + ); + elem.setAttribute("useoriginprincipal", "true");
elem = groupbox.querySelector(this.selector.savedKeysButton); elem.setAttribute(
===================================== browser/components/onionservices/content/authPrompt.js ===================================== @@ -1,20 +1,19 @@ -// Copyright (c) 2020, The Tor Project, Inc. +/* eslint-env mozilla/browser-window */
"use strict";
-/* globals gBrowser, PopupNotifications, Services, XPCOMUtils */ - -ChromeUtils.defineESModuleGetters(this, { - TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", -}); - -XPCOMUtils.defineLazyModuleGetters(this, { - OnionAuthUtil: "chrome://browser/content/onionservices/authUtil.jsm", - CommonUtils: "resource://services-common/utils.js", - TorStrings: "resource:///modules/TorStrings.jsm", -}); - const OnionAuthPrompt = (function () { + // Only import to our internal scope, rather than the global scope of + // browser.xhtml. + const lazy = {}; + ChromeUtils.defineESModuleGetters(lazy, { + TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", + CommonUtils: "resource://services-common/utils.sys.mjs", + }); + XPCOMUtils.defineLazyModuleGetters(lazy, { + TorStrings: "resource:///modules/TorStrings.jsm", + }); + // OnionServicesAuthPrompt objects run within the main/chrome process. // aReason is the topic passed within the observer notification that is // causing this auth prompt to be displayed. @@ -25,11 +24,16 @@ const OnionAuthPrompt = (function () { this._onionHostname = aOnionName; }
+ const topics = { + clientAuthMissing: "tor-onion-services-clientauth-missing", + clientAuthIncorrect: "tor-onion-services-clientauth-incorrect", + }; + OnionServicesAuthPrompt.prototype = { show(aWarningMessage) { let mainAction = { - label: TorStrings.onionServices.authPrompt.done, - accessKey: TorStrings.onionServices.authPrompt.doneAccessKey, + label: lazy.TorStrings.onionServices.authPrompt.done, + accessKey: lazy.TorStrings.onionServices.authPrompt.doneAccessKey, leaveOpen: true, // Callback is responsible for closing the notification. callback: this._onDone.bind(this), }; @@ -68,9 +72,9 @@ const OnionAuthPrompt = (function () {
this._prompt = PopupNotifications.show( this._browser, - OnionAuthUtil.domid.notification, + "tor-clientauth", "", - OnionAuthUtil.domid.anchor, + "tor-clientauth-notification-icon", mainAction, [cancelAction], options @@ -79,52 +83,38 @@ const OnionAuthPrompt = (function () {
_onPromptShowing(aWarningMessage) { let xulDoc = this._browser.ownerDocument; - let descElem = xulDoc.getElementById(OnionAuthUtil.domid.description); + let descElem = xulDoc.getElementById("tor-clientauth-notification-desc"); if (descElem) { // Handle replacement of the onion name within the localized // string ourselves so we can show the onion name as bold text. // We do this by splitting the localized string and creating // several HTML <span> elements. - while (descElem.firstChild) { - descElem.firstChild.remove(); - } + const fmtString = lazy.TorStrings.onionServices.authPrompt.description; + const [prefix, suffix] = fmtString.split("%S");
- let fmtString = TorStrings.onionServices.authPrompt.description; - let prefix = ""; - let suffix = ""; - const kToReplace = "%S"; - let idx = fmtString.indexOf(kToReplace); - if (idx < 0) { - prefix = fmtString; - } else { - prefix = fmtString.substring(0, idx); - suffix = fmtString.substring(idx + kToReplace.length); - } + const domainEl = xulDoc.createElement("span"); + domainEl.id = "tor-clientauth-notification-onionname"; + domainEl.textContent = TorUIUtils.shortenOnionAddress( + this._onionHostname + );
- const kHTMLNS = "http://www.w3.org/1999/xhtml"; - let span = xulDoc.createElementNS(kHTMLNS, "span"); - span.textContent = prefix; - descElem.appendChild(span); - span = xulDoc.createElementNS(kHTMLNS, "span"); - span.id = OnionAuthUtil.domid.onionNameSpan; - span.textContent = this._onionHostname; - descElem.appendChild(span); - span = xulDoc.createElementNS(kHTMLNS, "span"); - span.textContent = suffix; - descElem.appendChild(span); + descElem.replaceChildren(prefix, domainEl, suffix); }
// Set "Learn More" label and href. - let learnMoreElem = xulDoc.getElementById(OnionAuthUtil.domid.learnMore); + let learnMoreElem = xulDoc.getElementById( + "tor-clientauth-notification-learnmore" + ); if (learnMoreElem) { - learnMoreElem.setAttribute("value", TorStrings.onionServices.learnMore); + learnMoreElem.setAttribute( + "value", + lazy.TorStrings.onionServices.learnMore + ); learnMoreElem.setAttribute( "href", - TorStrings.onionServices.learnMoreURL + "about:manual#onion-services_onion-service-authentication" ); - if (TorStrings.onionServices.learnMoreURL.startsWith("about:")) { - learnMoreElem.setAttribute("useoriginprincipal", "true"); - } + learnMoreElem.setAttribute("useoriginprincipal", "true"); }
this._showWarning(aWarningMessage); @@ -139,7 +129,7 @@ const OnionAuthPrompt = (function () { if (keyElem) { keyElem.setAttribute( "placeholder", - TorStrings.onionServices.authPrompt.keyPlaceholder + lazy.TorStrings.onionServices.authPrompt.keyPlaceholder ); this._boundOnKeyFieldKeyPress = this._onKeyFieldKeyPress.bind(this); this._boundOnKeyFieldInput = this._onKeyFieldInput.bind(this); @@ -186,14 +176,14 @@ const OnionAuthPrompt = (function () {
const base64key = this._keyToBase64(keyElem.value); if (!base64key) { - this._showWarning(TorStrings.onionServices.authPrompt.invalidKey); + this._showWarning(lazy.TorStrings.onionServices.authPrompt.invalidKey); return; }
this._prompt.remove();
const controllerFailureMsg = - TorStrings.onionServices.authPrompt.failedToSetKey; + lazy.TorStrings.onionServices.authPrompt.failedToSetKey; try { // ^(subdomain.)*onionserviceid.onion$ (case-insensitive) const onionServiceIdRegExp = @@ -205,7 +195,7 @@ const OnionAuthPrompt = (function () {
const checkboxElem = this._getCheckboxElement(); const isPermanent = checkboxElem && checkboxElem.checked; - const provider = await TorProviderBuilder.build(); + const provider = await lazy.TorProviderBuilder.build(); await provider.onionAuthAdd(onionServiceId, base64key, isPermanent); // Success! Reload the page. this._browser.sendMessageToActor("Browser:Reload", {}, "BrowserTab"); @@ -227,7 +217,7 @@ const OnionAuthPrompt = (function () { // this authentication prompt. const failedURI = this._failedURI.spec; const errorCode = - this._reasonForPrompt === OnionAuthUtil.topic.clientAuthMissing + this._reasonForPrompt === topics.clientAuthMissing ? Cr.NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH : Cr.NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH; const io = @@ -245,19 +235,17 @@ const OnionAuthPrompt = (function () {
_getKeyElement() { let xulDoc = this._browser.ownerDocument; - return xulDoc.getElementById(OnionAuthUtil.domid.keyElement); + return xulDoc.getElementById("tor-clientauth-notification-key"); },
_getCheckboxElement() { let xulDoc = this._browser.ownerDocument; - return xulDoc.getElementById(OnionAuthUtil.domid.checkboxElement); + return xulDoc.getElementById("tor-clientauth-persistkey-checkbox"); },
_showWarning(aWarningMessage) { let xulDoc = this._browser.ownerDocument; - let warningElem = xulDoc.getElementById( - OnionAuthUtil.domid.warningElement - ); + let warningElem = xulDoc.getElementById("tor-clientauth-warning"); let keyElem = this._getKeyElement(); if (warningElem) { if (aWarningMessage) { @@ -289,7 +277,7 @@ const OnionAuthPrompt = (function () { // a tor onion-auth file (which uses lowercase). let rawKey; try { - rawKey = CommonUtils.decodeBase32(aKeyString.toUpperCase()); + rawKey = lazy.CommonUtils.decodeBase32(aKeyString.toUpperCase()); } catch (e) {}
if (rawKey) { @@ -313,24 +301,21 @@ const OnionAuthPrompt = (function () {
let retval = { init() { - Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthMissing); - Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthIncorrect); + Services.obs.addObserver(this, topics.clientAuthMissing); + Services.obs.addObserver(this, topics.clientAuthIncorrect); },
uninit() { - Services.obs.removeObserver(this, OnionAuthUtil.topic.clientAuthMissing); - Services.obs.removeObserver( - this, - OnionAuthUtil.topic.clientAuthIncorrect - ); + Services.obs.removeObserver(this, topics.clientAuthMissing); + Services.obs.removeObserver(this, topics.clientAuthIncorrect); },
// aSubject is the DOM Window or browser where the prompt should be shown. // aData contains the .onion name. observe(aSubject, aTopic, aData) { if ( - aTopic != OnionAuthUtil.topic.clientAuthMissing && - aTopic != OnionAuthUtil.topic.clientAuthIncorrect + aTopic != topics.clientAuthMissing && + aTopic != topics.clientAuthIncorrect ) { return; }
===================================== browser/components/onionservices/content/authUtil.jsm deleted ===================================== @@ -1,25 +0,0 @@ -// Copyright (c) 2020, The Tor Project, Inc. - -"use strict"; - -var EXPORTED_SYMBOLS = ["OnionAuthUtil"]; - -const OnionAuthUtil = { - topic: { - clientAuthMissing: "tor-onion-services-clientauth-missing", - clientAuthIncorrect: "tor-onion-services-clientauth-incorrect", - }, - message: { - authPromptCanceled: "Tor:OnionServicesAuthPromptCanceled", - }, - domid: { - anchor: "tor-clientauth-notification-icon", - notification: "tor-clientauth", - description: "tor-clientauth-notification-desc", - learnMore: "tor-clientauth-notification-learnmore", - onionNameSpan: "tor-clientauth-notification-onionname", - keyElement: "tor-clientauth-notification-key", - warningElement: "tor-clientauth-warning", - checkboxElement: "tor-clientauth-persistkey-checkbox", - }, -};
===================================== browser/components/onionservices/jar.mn ===================================== @@ -2,7 +2,6 @@ browser.jar: content/browser/onionservices/authPreferences.css (content/authPreferences.css) content/browser/onionservices/authPreferences.js (content/authPreferences.js) content/browser/onionservices/authPrompt.js (content/authPrompt.js) - content/browser/onionservices/authUtil.jsm (content/authUtil.jsm) content/browser/onionservices/netError/ (content/netError/*) content/browser/onionservices/onionservices.css (content/onionservices.css) content/browser/onionservices/savedKeysDialog.js (content/savedKeysDialog.js)
===================================== browser/components/torcircuit/content/torCircuitPanel.js ===================================== @@ -408,21 +408,6 @@ var gTorCircuitPanel = { return this._fallbackStringBundle.formatStringFromName(name, args); },
- /** - * Shorten the given address if it is an onion address. - * - * @param {string} address - The address to shorten. - * - * @returns {string} The shortened form of the address, or the address itself - * if it was not shortened. - */ - _shortenOnionAddress(address) { - if (!address.endsWith(".onion") || address.length <= 22) { - return address; - } - return `${address.slice(0, 7)}…${address.slice(-12)}`; - }, - /** * Updates the circuit display in the panel to show the current browser data. */ @@ -465,12 +450,12 @@ var gTorCircuitPanel = { this._panelElements.heading.textContent = this._getString( "torbutton.circuit_display.heading", // Only shorten the onion domain if it has no alias. - [onionAlias ? domain : this._shortenOnionAddress(domain)] + [TorUIUtils.shortenOnionAddress(domain)] );
if (onionAlias) { this._panelElements.aliasLink.textContent = - this._shortenOnionAddress(onionAlias); + TorUIUtils.shortenOnionAddress(onionAlias); if (scheme === "http" || scheme === "https") { // We assume the same scheme as the current page for the alias, which we // expect to be either http or https. @@ -521,7 +506,8 @@ var gTorCircuitPanel = { );
// Set the address that we want to copy. - this._panelElements.endItem.textContent = this._shortenOnionAddress(domain); + this._panelElements.endItem.textContent = + TorUIUtils.shortenOnionAddress(domain);
// Button description text, depending on whether our first node was a // bridge, or otherwise a guard.
===================================== browser/modules/TorStrings.jsm ===================================== @@ -300,7 +300,6 @@ const Loader = {
const retval = { learnMore: getString("learnMore", "Learn more"), - learnMoreURL: "about:manual#onion-services_onion-service-authentication", errorPage: { browser: getString("errorPage.browser", "Browser"), network: getString("errorPage.network", "Network"),
===================================== browser/modules/TorUIUtils.sys.mjs ===================================== @@ -0,0 +1,26 @@ +/** + * Common methods for tor UI components. + */ +export const TorUIUtils = { + /** + * Shorten the given address if it is an onion address. + * + * @param {string} address - The address to shorten. + * + * @returns {string} The shortened form of the address, or the address itself + * if it was not shortened. + */ + shortenOnionAddress(address) { + if ( + // Only shorten ".onion" addresses. + !address.endsWith(".onion") || + // That are not "onion" aliases. + address.endsWith(".tor.onion") || + // And are long. + address.length <= 21 + ) { + return address; + } + return `${address.slice(0, 6)}…${address.slice(-12)}`; + }, +};
===================================== browser/modules/moz.build ===================================== @@ -152,6 +152,7 @@ EXTRA_JS_MODULES += [ "TorConnect.sys.mjs", "TorSettings.sys.mjs", "TorStrings.jsm", + "TorUIUtils.sys.mjs", "TransientPrefs.jsm", "URILoadingHelper.sys.mjs", "webrtcUI.jsm",
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/2760a7b...