lists.torproject.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

tbb-commits

Thread Start a new thread
Download
Threads by month
  • ----- 2025 -----
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2018 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2017 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2016 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2015 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2014 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
tbb-commits@lists.torproject.org

  • 1 participants
  • 18631 discussions
[tor-browser/tor-browser-90.0-11.0-1] Bug 21830: Copying large text from web console leaks to /tmp
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit f3a87a725f0d78f24b72ba7f889cdbb2b6d3c326 Author: Georg Koppen <gk(a)torproject.org> Date: Fri Aug 4 05:55:49 2017 +0000 Bug 21830: Copying large text from web console leaks to /tmp Patch written by Neill Miller --- widget/nsTransferable.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/widget/nsTransferable.cpp b/widget/nsTransferable.cpp index c82549a4d1d1..f8ecfbff0983 100644 --- a/widget/nsTransferable.cpp +++ b/widget/nsTransferable.cpp @@ -33,6 +33,7 @@ Notes to self: #include "nsILoadContext.h" #include "nsXULAppAPI.h" #include "mozilla/UniquePtr.h" +#include "mozilla/Preferences.h" using namespace mozilla; @@ -195,6 +196,11 @@ nsTransferable::Init(nsILoadContext* aContext) { if (aContext) { mPrivateData = aContext->UsePrivateBrowsing(); + } else { + // without aContext here to provide PrivateBrowsing information, + // we defer to the active configured setting + mPrivateData = + mozilla::Preferences::GetBool("browser.privatebrowsing.autostart"); } #ifdef DEBUG mInitialized = true;
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 23247: Communicating security expectations for .onion
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 3cc7ba9cde194c73e1dc6f558e50422de0f5a8c0 Author: Richard Pospesel <richard(a)torproject.org> Date: Fri Jun 8 13:38:40 2018 -0700 Bug 23247: Communicating security expectations for .onion Encrypting pages hosted on Onion Services with SSL/TLS is redundant (in terms of hiding content) as all traffic within the Tor network is already fully encrypted. Therefore, serving HTTP pages from an Onion Service is more or less fine. Prior to this patch, Tor Browser would mostly treat pages delivered via Onion Services as well as pages delivered in the ordinary fashion over the internet in the same way. This created some inconsistencies in behaviour and misinformation presented to the user relating to the security of pages delivered via Onion Services: - HTTP Onion Service pages did not have any 'lock' icon indicating the site was secure - HTTP Onion Service pages would be marked as unencrypted in the Page Info screen - Mixed-mode content restrictions did not apply to HTTP Onion Service pages embedding Non-Onion HTTP content This patch fixes the above issues, and also adds several new 'Onion' icons to the mix to indicate all of the various permutations of Onion Services hosted HTTP or HTTPS pages with HTTP or HTTPS content. Strings for Onion Service Page Info page are pulled from Torbutton's localization strings. --- browser/base/content/browser-siteIdentity.js | 39 ++++++++----- browser/base/content/pageinfo/security.js | 64 ++++++++++++++++++---- .../shared/identity-block/identity-block.inc.css | 19 +++++++ .../themes/shared/identity-block/onion-slash.svg | 5 ++ .../themes/shared/identity-block/onion-warning.svg | 6 ++ browser/themes/shared/identity-block/onion.svg | 3 + browser/themes/shared/jar.inc.mn | 3 + dom/base/nsContentUtils.cpp | 19 +++++++ dom/base/nsContentUtils.h | 5 ++ dom/base/nsGlobalWindowOuter.cpp | 3 +- dom/ipc/WindowGlobalActor.cpp | 4 +- dom/ipc/WindowGlobalChild.cpp | 6 +- dom/security/nsMixedContentBlocker.cpp | 16 +++++- .../modules/geckoview/GeckoViewProgress.jsm | 4 ++ security/manager/ssl/nsSecureBrowserUI.cpp | 12 ++++ 15 files changed, 177 insertions(+), 31 deletions(-) diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 9483b1e25bd1..ca880a5a29dd 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -140,6 +140,10 @@ var gIdentityHandler = { ); }, + get _uriIsOnionHost() { + return this._uriHasHost ? this._uri.host.toLowerCase().endsWith(".onion") : false; + }, + get _isAboutNetErrorPage() { return ( gBrowser.selectedBrowser.documentURI && @@ -745,9 +749,9 @@ var gIdentityHandler = { get pointerlockFsWarningClassName() { // Note that the fullscreen warning does not handle _isSecureInternalUI. if (this._uriHasHost && this._isSecureConnection) { - return "verifiedDomain"; + return this._uriIsOnionHost ? "onionVerifiedDomain" : "verifiedDomain"; } - return "unknownIdentity"; + return this._uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity"; }, /** @@ -755,6 +759,10 @@ var gIdentityHandler = { * built-in (returns false) or imported (returns true). */ _hasCustomRoot() { + if (!this._secInfo) { + return false; + } + let issuerCert = null; issuerCert = this._secInfo.succeededCertChain[ this._secInfo.succeededCertChain.length - 1 @@ -797,11 +805,13 @@ var gIdentityHandler = { "identity.extension.label", [extensionName] ); - } else if (this._uriHasHost && this._isSecureConnection) { + } else if (this._uriHasHost && this._isSecureConnection && this._secInfo) { // This is a secure connection. - this._identityBox.className = "verifiedDomain"; + // _isSecureConnection implicitly includes onion services, which may not have an SSL certificate + const uriIsOnionHost = this._uriIsOnionHost; + this._identityBox.className = uriIsOnionHost ? "onionVerifiedDomain" : "verifiedDomain"; if (this._isMixedActiveContentBlocked) { - this._identityBox.classList.add("mixedActiveBlocked"); + this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveBlocked" : "mixedActiveBlocked"); } if (!this._isCertUserOverridden) { // It's a normal cert, verifier is the CA Org. @@ -812,17 +822,17 @@ var gIdentityHandler = { } } else if (this._isBrokenConnection) { // This is a secure connection, but something is wrong. - this._identityBox.className = "unknownIdentity"; + const uriIsOnionHost = this._uriIsOnionHost; + this._identityBox.className = uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity"; if (this._isMixedActiveContentLoaded) { - this._identityBox.classList.add("mixedActiveContent"); + this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveContent" : "mixedActiveContent"); } else if (this._isMixedActiveContentBlocked) { - this._identityBox.classList.add( - "mixedDisplayContentLoadedActiveBlocked" - ); + this._identityBox.classList.add(uriIsOnionHost ? "onionMixedDisplayContentLoadedActiveBlocked" : "mixedDisplayContentLoadedActiveBlocked"); } else if (this._isMixedPassiveContentLoaded) { - this._identityBox.classList.add("mixedDisplayContent"); + this._identityBox.classList.add(uriIsOnionHost ? "onionMixedDisplayContent" : "mixedDisplayContent"); } else { + // TODO: ignore weak https cipher for onionsites? this._identityBox.classList.add("weakCipher"); } } else if (this._isAboutCertErrorPage) { @@ -835,8 +845,8 @@ var gIdentityHandler = { // Network errors and blocked pages get a more neutral icon this._identityBox.className = "unknownIdentity"; } else if (this._isPotentiallyTrustworthy) { - // This is a local resource (and shouldn't be marked insecure). - this._identityBox.className = "localResource"; + // This is a local resource or an onion site (and shouldn't be marked insecure). + this._identityBox.className = this._uriIsOnionHost ? "onionUnknownIdentity" : "localResource"; } else { // This is an insecure connection. let warnOnInsecure = @@ -860,7 +870,8 @@ var gIdentityHandler = { } if (this._isCertUserOverridden) { - this._identityBox.classList.add("certUserOverridden"); + const uriIsOnionHost = this._uriIsOnionHost; + this._identityBox.classList.add(uriIsOnionHost ? "onionCertUserOverridden" : "certUserOverridden"); // Cert is trusted because of a security exception, verifier is a special string. tooltip = gNavigatorBundle.getString( "identity.identified.verified_by_you" diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js index 6a2d09ec8442..192e9f763700 100644 --- a/browser/base/content/pageinfo/security.js +++ b/browser/base/content/pageinfo/security.js @@ -22,6 +22,13 @@ ChromeUtils.defineModuleGetter( "PluralForm", "resource://gre/modules/PluralForm.jsm" ); +XPCOMUtils.defineLazyGetter( + this, + "gTorButtonBundle", + function() { + return Services.strings.createBundle("chrome://torbutton/locale/torbutton.properties"); + } +); var security = { async init(uri, windowInfo) { @@ -60,6 +67,11 @@ var security = { (Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT | Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT); var isEV = ui.state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL; + var isOnion = false; + const hostName = this.windowInfo.hostName; + if (hostName && hostName.endsWith(".onion")) { + isOnion = true; + } let retval = { cAName: "", @@ -69,6 +81,7 @@ var security = { isBroken, isMixed, isEV, + isOnion, cert: null, certificateTransparency: null, }; @@ -107,6 +120,7 @@ var security = { isBroken, isMixed, isEV, + isOnion, cert, certChain: certChainArray, certificateTransparency: undefined, @@ -349,22 +363,50 @@ async function securityOnLoad(uri, windowInfo) { } msg2 = pkiBundle.getString("pageInfo_Privacy_None2"); } else if (info.encryptionStrength > 0) { - hdr = pkiBundle.getFormattedString( - "pageInfo_EncryptionWithBitsAndProtocol", - [info.encryptionAlgorithm, info.encryptionStrength + "", info.version] - ); + if (!info.isOnion) { + hdr = pkiBundle.getFormattedString( + "pageInfo_EncryptionWithBitsAndProtocol", + [info.encryptionAlgorithm, info.encryptionStrength + "", info.version] + ); + } else { + try { + hdr = gTorButtonBundle.formatStringFromName( + "pageInfo_OnionEncryptionWithBitsAndProtocol", + [info.encryptionAlgorithm, info.encryptionStrength + "", info.version] + ); + } catch(err) { + hdr = "Connection Encrypted (Onion Service, " + + info.encryptionAlgorithm + + ", " + + info.encryptionStrength + + " bit keys, " + + info.version + + ")"; + } + } msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1"); msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2"); } else { - hdr = pkiBundle.getString("pageInfo_NoEncryption"); - if (windowInfo.hostName != null) { - msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [ - windowInfo.hostName, - ]); + if (!info.isOnion) { + hdr = pkiBundle.getString("pageInfo_NoEncryption"); + if (windowInfo.hostName != null) { + msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [ + windowInfo.hostName, + ]); + } else { + msg1 = pkiBundle.getString("pageInfo_Privacy_None4"); + } + msg2 = pkiBundle.getString("pageInfo_Privacy_None2"); } else { - msg1 = pkiBundle.getString("pageInfo_Privacy_None4"); + try { + hdr = gTorButtonBundle.GetStringFromName("pageInfo_OnionEncryption"); + } catch (err) { + hdr = "Connection Encrypted (Onion Service)"; + } + + msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1"); + msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2"); } - msg2 = pkiBundle.getString("pageInfo_Privacy_None2"); } setText("security-technical-shortform", hdr); setText("security-technical-longform1", msg1); diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css index 826e3eab8808..f36936dffb9d 100644 --- a/browser/themes/shared/identity-block/identity-block.inc.css +++ b/browser/themes/shared/identity-block/identity-block.inc.css @@ -296,6 +296,25 @@ toolbar[brighttext] #identity-box[pageproxystate="valid"].chromeUI #identity-ico list-style-image: url(chrome://global/skin/icons/security-broken.svg); } +#identity-box[pageproxystate="valid"].onionUnknownIdentity > #identity-icon, +#identity-box[pageproxystate="valid"].onionVerifiedDomain > #identity-icon, +#identity-box[pageproxystate="valid"].onionMixedActiveBlocked > #identity-icon { + list-style-image: url(chrome://browser/skin/onion.svg); + visibility: visible; +} + +#identity-box[pageproxystate="valid"].onionMixedDisplayContent > #identity-icon, +#identity-box[pageproxystate="valid"].onionMixedDisplayContentLoadedActiveBlocked > #identity-icon, +#identity-box[pageproxystate="valid"].onionCertUserOverridden > #identity-icon { + list-style-image: url(chrome://browser/skin/onion-warning.svg); + visibility: visible; +} + +#identity-box[pageproxystate="valid"].onionMixedActiveContent > #identity-icon { + list-style-image: url(chrome://browser/skin/onion-slash.svg); + visibility: visible; +} + #permissions-granted-icon { list-style-image: url(chrome://browser/skin/permissions.svg); } diff --git a/browser/themes/shared/identity-block/onion-slash.svg b/browser/themes/shared/identity-block/onion-slash.svg new file mode 100644 index 000000000000..e7c98b769482 --- /dev/null +++ b/browser/themes/shared/identity-block/onion-slash.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <path d="M3.409559 13.112147C3.409559 13.112147 8.200807 8.103115 8.200807 8.103115C8.200807 8.103115 8.200807 6.516403 8.200807 6.516403C8.620819 6.516403 9.009719 6.703075 9.274171 6.998639C9.274171 6.998639 10.160863 6.080835 10.160863 6.080835C9.663071 5.567487 8.978607 5.256367 8.200807 5.256367C8.200807 5.256367 8.200807 4.400787 8.200807 4.400787C9.196391 4.400787 10.098639 4.805243 10.736435 5.458595C10.736435 5.458595 11.623127 4.540791 11.623127 4.540791C10.751991 3.669655 9.538623 3.125195 8.200807 3.125195C8.200807 3.125195 8.200807 2.269615 8.200807 2.269615C9.756407 2.269615 11.172003 2.907411 12.214255 3.918551C12.214255 3.918551 13.100947 3.000747 13.100947 3.000747C11.825355 1.756267 10.098639 0.994023 8.185251 0.994023C4.311807 0.994023 1.185051 4.120779 1.185051 7.994223C1.185051 10.016503 2.040631 11.836555 3.409559 13.112147C3.409559 13.112147 3.409559 13.112147 3.409559 13.112147" fill-opacity="context-fill-opacity" fill="context-fill" /> + <path d="M14.205423 4.416343C14.205423 4.416343 13.287619 5.380815 13.287619 5.380815C13.692075 6.158615 13.909859 7.045307 13.909859 7.994223C13.909859 11.152091 11.358675 13.718831 8.200807 13.718831C8.200807 13.718831 8.200807 12.863251 8.200807 12.863251C10.891995 12.863251 13.069835 10.669855 13.069835 7.978667C13.069835 7.278647 12.929831 6.625295 12.665379 6.018611C12.665379 6.018611 11.685351 7.045307 11.685351 7.045307C11.763131 7.340871 11.809799 7.651991 11.809799 7.963111C11.809799 9.954279 10.207531 11.556547 8.216363 11.572103C8.216363 11.572103 8.216363 10.716523 8.216363 10.716523C9.725295 10.700967 10.954219 9.472043 10.954219 7.963111C10.954219 7.916443 10.954219 7.854219 10.954219 7.807551C10.954219 7.807551 4.887379 14.169955 4.887379 14.169955C5.867407 14.698859 6.987439 14.994423 8.185251 14.994423C12.058695 14.994423 15.185451 11.867667 15.185451 7.994223C15.185451 6.687519 14.827663 5.474151 14.205423 4.416343C14.205423 4.416343 14.205423 4.416343 14.205423 4.416343" fill-opacity="context-fill-opacity" fill="context-fill" /> + <path d="M1.791735 15.461103C1.402835 15.461103 1.045047 15.212207 0.889487 14.838863C0.733927 14.465519 0.827267 14.014395 1.107271 13.734387C1.107271 13.734387 13.458735 0.822907 13.458735 0.822907C13.847635 0.434007 14.454319 0.449563 14.827663 0.838467C15.201007 1.227367 15.216563 1.865163 14.843223 2.269619C14.843223 2.269619 2.491759 15.181099 2.491759 15.181099C2.289531 15.352215 2.040635 15.461107 1.791739 15.461107C1.791739 15.461107 1.791735 15.461103 1.791735 15.461103" fill="#ff0039" /> +</svg> diff --git a/browser/themes/shared/identity-block/onion-warning.svg b/browser/themes/shared/identity-block/onion-warning.svg new file mode 100644 index 000000000000..d42a7dab7246 --- /dev/null +++ b/browser/themes/shared/identity-block/onion-warning.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <path d="M15.8630401732 14.127C15.8630401732 14.127 12.6649598146 7.716 12.6649598146 7.716C12.4469357756 7.279935 12.0003277145 7.0043454 11.5116853046 7.0043454C11.0230428947 7.0043454 10.5764348336 7.279935 10.3584107946 7.716C10.3584107946 7.716 7.1573218938 14.127 7.1573218938 14.127C6.95646770542 14.527294 6.97733695982 15.002669 7.21250176686 15.38393C7.4476665739 15.765191 7.86372750208 15.998191 8.3126020986 16.0C8.3126020986 16.0 14.7077599684 16.0 14.7077599684 16.0C15.1566344646 15.9982 15.572695794 15.765191 15.8078605007 15.38393C16.0430252075 15.002669 16.0638944619 14.527294 15.8630371647 14.127C15.8630371647 14.127 15.8630401732 14.127 15.8630401732 14.127" fill="#ffbf00" /> + <path d="M11.5106824572 8.0C11.6210488221 7.99691 11.7223975832 8.060469 11.7674113916 8.161C11.7674113916 8.161 14.9644889028 14.573 14.9644889028 14.573C15.0126456349 14.66534 15.0076715118 14.776305 14.9514518866 14.864C14.9011992034 14.95041 14.8079143382 15.002854 14.7077599684 15.001048C14.7077599684 15.001048 8.3126020986 15.001048 8.3126020986 15.001048C8.2124480296 15.002854 8.1191607576 14.950409 8.0689101804 14.864C8.0124814615 14.77637 8.0075053327 14.665298 8.0558731642 14.573C8.0558731642 14.573 11.2529506754 8.161 11.2529506754 8.161C11.2981038796 8.0601247 11.3999560701 7.9964997 11.5106824572 8.0M11.5106824572 6.9999751C11.0194557096 6.9969427 10.5701148893 7.2754275 10.3554022524 7.716C10.3554022524 7.716 7.1573218938 14.127 7.1573218938 14.127C6.95646770542 14.527294 6.97733695982 15.002669 7.21250176686 15.38393C7.4476665739 15.765191 7.86372750208 15.998191 8.3126020986 16.0C8.3126020986 16.0 14.7077599684 16.0 14.7077599684 16.0C15.1566344646 15.9982 15.57269 5794 15.765191 15.8078605007 15.38393C16.0430252075 15.002669 16.0638944619 14.527294 15.8630371647 14.127C15.8630371647 14.127 12.6649598146 7.716 12.6649598146 7.716C12.4504036219 7.2757546 12.0015481798 6.9973287 11.5106824572 6.9999751C11.5106824572 6.9999751 11.5106824572 6.9999751 11.5106824572 6.9999751" opacity="0.35" fill="#d76e00" /> + <path d="M11.5327451 12.0C11.8096733867 12.0 12.0341688 11.776142 12.0341688 11.5C12.0341688 11.5 12.0341688 9.5 12.0341688 9.5C12.0341688 9.2238576 11.8096733867 9.0 11.5327451 9.0C11.2558168133 9.0 11.0313214 9.2238576 11.0313214 9.5C11.0313214 9.5 11.0313214 11.5 11.0313214 11.5C11.0313214 11.776142 11.2558168133 12.0 11.5327451 12.0C11.5327451 12.0 11.5327451 12.0 11.5327451 12.0M11.5327451 12.809C11.1500294496 12.809 10.8397775466 13.118371 10.8397775466 13.5C10.8397775466 13.881629 11.1500294496 14.191 11.5327451 14.191C11.9154607504 14.191 12.2257126534 13.881629 12.2257126534 13.5C12.2257126534 13.118371 11.9154607504 12.809 11.5327451 12.809C11.5327451 12.809 11.5327451 12.809 11.5327451 12.809" fill="#ffffff" /> + <path d="M7.08030321348 6.552C7.90163523408 6.56 8.5645173655 7.225 8.5645173655 8.046C8.5645173655 8.866 7.90163523408 9.532 7.08030321348 9.54C7.08030321348 9.54 7.08030321348 6.552 7.08030321348 6.552M6.30610502068 13.756C6.30610502068 13.756 9.4991711423 7.353 9.4991711423 7.353C9.5453021227 7.259 9.6144985933 7.184 9.6716608951 7.098C9.2845617987 6.039 8.2756973143 5.277 7.08030321348 5.271C7.08030321348 5.271 7.08030321348 4.417 7.08030321348 4.417C8.5043465215 4.423 9.7238089599 5.251 10.3164917733 6.443C10.6795225321 6.21 11.1067355245 6.074 11.5519997701 6.074C11.5519997701 6.074 11.5620282441 6.074 11.5620282441 6.074C11.5620282441 6.074 11.5640339389 6.074 11.5640339389 6.074C11.5660396337 6.074 11.5690481759 6.075 11.5710538707 6.075C10.8108955415 4.35 9.0900094031 3.141 7.08030321348 3.135C7.08030321348 3.135 7.08030321348 2.281 7.08030321348 2.281C9.6716608951 2.288 11.8618796167 3.993 12.5889439817 6.34C13.0231769059 6.561 13.3922247491 6.9 13.6088397875 7.344C13.60 88397875 7.344 14.1162805719 8.361 14.1162805719 8.361C14.1202919615 8.256 14.1313232829 8.152 14.1313232829 8.046C14.1313232829 4.155 10.9683425833 1.0 7.06626334988 1.0C3.16318126908 1.0 0.00020056948 4.155 0.00020056948 8.046C0.00020056948 11.603 2.64571201068 14.536 6.08046435568 15.015C6.03633907008 14.595 6.10252699848 14.16 6.30610502068 13.756C6.30610502068 13.756 6.30610502068 13.756 6.30610502068 13.756" fill-opacity="context-fill-opacity" fill="context-fill" /> +</svg> diff --git a/browser/themes/shared/identity-block/onion.svg b/browser/themes/shared/identity-block/onion.svg new file mode 100644 index 000000000000..b123a9786acc --- /dev/null +++ b/browser/themes/shared/identity-block/onion.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <path d="M8.01435945 13.726867125C8.01435945 13.726867125 8.01435945 12.87830525 8.01435945 12.87830525C10.70227825 12.87051775 12.87869375 10.689666 12.87869375 7.9998060125C12.87869375 5.310140275 10.70227825 3.1292621 8.01435945 3.121500325C8.01435945 3.121500325 8.01435945 2.272938975 8.01435945 2.272938975C11.170899375 2.280892725 13.727061375 4.8415202875 13.727061375 7.9998060125C13.727061375 11.158285375 11.170899375 13.719105 8.01435945 13.726867125C8.01435945 13.726867125 8.01435945 13.726867125 8.01435945 13.726867125M8.01435945 10.756805625C9.5304373 10.74884925 10.75758175 9.5180185125 10.75758175 7.9998060125C10.75758175 6.4817875 9.5304373 5.2509564125 8.01435945 5.2430005625C8.01435945 5.2430005625 8.01435945 4.3946332875 8.01435945 4.3946332875C9.999251625 4.4023945375 11.60614275 6.013167425 11.60614275 7.9998060125C11.60614275 9.986639375 9.999251625 11.597411125 8.01435945 11.605172375C8.01435945 11.605172375 8.01435945 10.756805625 8.01435945 10.756805625M8.01 435945 6.5157454625C8.8276046625 6.5235067125 9.484837025 7.184620575 9.484837025 7.9998060125C9.484837025 8.815185875 8.8276046625 9.4762985125 8.01435945 9.4840608125C8.01435945 9.4840608125 8.01435945 6.5157454625 8.01435945 6.5157454625M1.0 7.9998060125C1.0 11.8659705 4.1338360375 15.0 8.0000000875 15.0C11.8659705 15.0 15.0 11.8659705 15.0 7.9998060125C15.0 4.1338360375 11.8659705 1.0 8.0000000875 1.0C4.1338360375 1.0 1.0 4.1338360375 1.0 7.9998060125C1.0 7.9998060125 1.0 7.9998060125 1.0 7.9998060125" fill-rule="even-odd" fill-opacity="context-fill-opacity" fill="context-fill" /> +</svg> diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn index 3ef32993dee3..a33b1dcd5c81 100644 --- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -53,6 +53,9 @@ skin/classic/browser/downloads/notification-start-animation.svg (../shared/downloads/notification-start-animation.svg) skin/classic/browser/drm-icon.svg (../shared/drm-icon.svg) skin/classic/browser/permissions.svg (../shared/identity-block/permissions.svg) + skin/classic/browser/onion.svg (../shared/identity-block/onion.svg) + skin/classic/browser/onion-slash.svg (../shared/identity-block/onion-slash.svg) + skin/classic/browser/onion-warning.svg (../shared/identity-block/onion-warning.svg) skin/classic/browser/illustrations/blue-berror.svg (../shared/illustrations/blue-berror.svg) skin/classic/browser/illustrations/error-connection-failure.svg (../shared/illustrations/error-connection-failure.svg) skin/classic/browser/illustrations/error-malformed-url.svg (../shared/illustrations/error-malformed-url.svg) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index c5b224dee6a7..253735c56446 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9312,6 +9312,25 @@ bool nsContentUtils::ComputeIsSecureContext(nsIChannel* aChannel) { return principal->GetIsOriginPotentiallyTrustworthy(); } +/* static */ bool nsContentUtils::DocumentHasOnionURI(Document* aDocument) { + if (!aDocument) { + return false; + } + + nsIURI* uri = aDocument->GetDocumentURI(); + if (!uri) { + return false; + } + + nsAutoCString host; + if (NS_SUCCEEDED(uri->GetHost(host))) { + bool hasOnionURI = StringEndsWith(host, ".onion"_ns); + return hasOnionURI; + } + + return false; +} + /* static */ void nsContentUtils::TryToUpgradeElement(Element* aElement) { NodeInfo* nodeInfo = aElement->NodeInfo(); diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index e97347037c37..e6b6125e9159 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2994,6 +2994,11 @@ class nsContentUtils { */ static bool HttpsStateIsModern(Document* aDocument); + /** + * Returns true of the document's URI is a .onion + */ + static bool DocumentHasOnionURI(Document* aDocument); + /** * Returns true if the channel is for top-level window and is over secure * context. diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 81d3a81aaa9e..a254466e07cb 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -1884,7 +1884,8 @@ bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument, return false; } - if (nsContentUtils::HttpsStateIsModern(aDocument)) { + if (nsContentUtils::HttpsStateIsModern(aDocument) || + nsContentUtils::DocumentHasOnionURI(aDocument)) { return true; } diff --git a/dom/ipc/WindowGlobalActor.cpp b/dom/ipc/WindowGlobalActor.cpp index 5946de1d8ab4..afeb71e5ddfa 100644 --- a/dom/ipc/WindowGlobalActor.cpp +++ b/dom/ipc/WindowGlobalActor.cpp @@ -21,6 +21,7 @@ #include "mozilla/net/CookieJarSettings.h" #include "mozilla/dom/WindowGlobalChild.h" #include "mozilla/dom/WindowGlobalParent.h" +#include "mozilla/dom/nsMixedContentBlocker.h" #include "nsGlobalWindowInner.h" #include "nsNetUtil.h" @@ -130,7 +131,8 @@ WindowGlobalInit WindowGlobalActor::WindowInitializer( // Init Mixed Content Fields nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(doc->GetDocumentURI()); - fields.mIsSecure = innerDocURI && innerDocURI->SchemeIs("https"); + fields.mIsSecure = innerDocURI && (innerDocURI->SchemeIs("https") || + nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI)); nsCOMPtr<nsITransportSecurityInfo> securityInfo; if (nsCOMPtr<nsIChannel> channel = doc->GetChannel()) { diff --git a/dom/ipc/WindowGlobalChild.cpp b/dom/ipc/WindowGlobalChild.cpp index 84c060c41534..73ac6a0cf96d 100644 --- a/dom/ipc/WindowGlobalChild.cpp +++ b/dom/ipc/WindowGlobalChild.cpp @@ -48,6 +48,8 @@ # include "GeckoProfiler.h" #endif +#include "mozilla/dom/nsMixedContentBlocker.h" + using namespace mozilla::ipc; using namespace mozilla::dom::ipc; @@ -234,7 +236,9 @@ void WindowGlobalChild::OnNewDocument(Document* aDocument) { nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(aDocument->GetDocumentURI()); if (innerDocURI) { - txn.SetIsSecure(innerDocURI->SchemeIs("https")); + txn.SetIsSecure( + innerDocURI->SchemeIs("https") || + nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI)); } MOZ_DIAGNOSTIC_ASSERT(mDocumentPrincipal->GetIsLocalIpAddress() == diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp index f7d722d3f5cd..9a82414068bf 100644 --- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -633,8 +633,8 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, return NS_OK; } - // Check the parent scheme. If it is not an HTTPS page then mixed content - // restrictions do not apply. + // Check the parent scheme. If it is not an HTTPS or .onion page then mixed + // content restrictions do not apply. nsCOMPtr<nsIURI> innerRequestingLocation = NS_GetInnermostURI(requestingLocation); if (!innerRequestingLocation) { @@ -649,6 +649,17 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, bool parentIsHttps = innerRequestingLocation->SchemeIs("https"); if (!parentIsHttps) { + bool parentIsOnion = IsPotentiallyTrustworthyOnion(innerRequestingLocation); + if (!parentIsOnion) { + *aDecision = ACCEPT; + return NS_OK; + } + } + + bool isHttpScheme = innerContentLocation->SchemeIs("http"); + // .onion URLs are encrypted and authenticated. Don't treat them as mixed + // content if potentially trustworthy (i.e. whitelisted). + if (isHttpScheme && IsPotentiallyTrustworthyOnion(innerContentLocation)) { *aDecision = ACCEPT; MOZ_LOG(sMCBLog, LogLevel::Verbose, (" -> decision: Request will be allowed because the requesting " @@ -675,7 +686,6 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, return NS_OK; } - bool isHttpScheme = innerContentLocation->SchemeIs("http"); if (isHttpScheme && IsPotentiallyTrustworthyOrigin(innerContentLocation)) { *aDecision = ACCEPT; return NS_OK; diff --git a/mobile/android/modules/geckoview/GeckoViewProgress.jsm b/mobile/android/modules/geckoview/GeckoViewProgress.jsm index 17069dbe657f..c1346b1858cf 100644 --- a/mobile/android/modules/geckoview/GeckoViewProgress.jsm +++ b/mobile/android/modules/geckoview/GeckoViewProgress.jsm @@ -145,6 +145,10 @@ var IdentityHandler = { result.host = uri.host; } + if (!aBrowser.securityUI.secInfo) { + return result; + } + const cert = aBrowser.securityUI.secInfo.serverCert; result.certificate = aBrowser.securityUI.secInfo.serverCert.getBase64DERString(); diff --git a/security/manager/ssl/nsSecureBrowserUI.cpp b/security/manager/ssl/nsSecureBrowserUI.cpp index b4de1a331ffc..f1ce39582854 100644 --- a/security/manager/ssl/nsSecureBrowserUI.cpp +++ b/security/manager/ssl/nsSecureBrowserUI.cpp @@ -9,6 +9,7 @@ #include "mozilla/Logging.h" #include "mozilla/Unused.h" #include "mozilla/dom/Document.h" +#include "mozilla/dom/nsMixedContentBlocker.h" #include "nsContentUtils.h" #include "nsIChannel.h" #include "nsDocShell.h" @@ -85,6 +86,17 @@ void nsSecureBrowserUI::RecomputeSecurityFlags() { } } } + + // any protocol routed over tor is secure + if (!(mState & nsIWebProgressListener::STATE_IS_SECURE)) { + nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(win->GetDocumentURI()); + if (innerDocURI && + nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI)) { + MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, (" is onion")); + mState = (mState & ~nsIWebProgressListener::STATE_IS_INSECURE) | + nsIWebProgressListener::STATE_IS_SECURE; + } + } } // Add upgraded-state flags when request has been
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 28369: Stop shipping pingsender executable
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit cefd6f0089a832b9822271d55a4033c04e985808 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Apr 10 17:52:51 2019 +0200 Bug 28369: Stop shipping pingsender executable --- browser/app/macbuild/Contents/MacOS-files.in | 1 - browser/installer/package-manifest.in | 4 ---- browser/installer/windows/nsis/shared.nsh | 1 - python/mozbuild/mozbuild/artifacts.py | 2 -- toolkit/components/telemetry/app/TelemetrySend.jsm | 19 +------------------ toolkit/components/telemetry/moz.build | 4 ---- 6 files changed, 1 insertion(+), 30 deletions(-) diff --git a/browser/app/macbuild/Contents/MacOS-files.in b/browser/app/macbuild/Contents/MacOS-files.in index 6f0b4481473b..6e8a1689ea19 100644 --- a/browser/app/macbuild/Contents/MacOS-files.in +++ b/browser/app/macbuild/Contents/MacOS-files.in @@ -17,7 +17,6 @@ #if defined(MOZ_CRASHREPORTER) /minidump-analyzer #endif -/pingsender /pk12util /ssltunnel /xpcshell diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index b3842ae863c6..308a595590f2 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -446,10 +446,6 @@ bin/libfreebl_64int_3.so @BINPATH@/minidump-analyzer@BIN_SUFFIX@ #endif -; [ Ping Sender ] -; -@BINPATH@/pingsender@BIN_SUFFIX@ - ; Shutdown Terminator @RESPATH@/components/terminator.manifest diff --git a/browser/installer/windows/nsis/shared.nsh b/browser/installer/windows/nsis/shared.nsh index beeb67211e47..7439ffd33e3e 100755 --- a/browser/installer/windows/nsis/shared.nsh +++ b/browser/installer/windows/nsis/shared.nsh @@ -1478,7 +1478,6 @@ ${RemoveDefaultBrowserAgentShortcut} Push "crashreporter.exe" Push "default-browser-agent.exe" Push "minidump-analyzer.exe" - Push "pingsender.exe" Push "updater.exe" Push "mozwer.dll" Push "${FileMainEXE}" diff --git a/python/mozbuild/mozbuild/artifacts.py b/python/mozbuild/mozbuild/artifacts.py index 50ca81a4aaf5..3f3454b4b7b5 100644 --- a/python/mozbuild/mozbuild/artifacts.py +++ b/python/mozbuild/mozbuild/artifacts.py @@ -495,7 +495,6 @@ class LinuxArtifactJob(ArtifactJob): "{product}/{product}", "{product}/{product}-bin", "{product}/minidump-analyzer", - "{product}/pingsender", "{product}/plugin-container", "{product}/updater", "{product}/**/*.so", @@ -550,7 +549,6 @@ class MacArtifactJob(ArtifactJob): "{product}-bin", "*.dylib", "minidump-analyzer", - "pingsender", "plugin-container.app/Contents/MacOS/plugin-container", "updater.app/Contents/MacOS/org.mozilla.updater", # 'xpcshell', diff --git a/toolkit/components/telemetry/app/TelemetrySend.jsm b/toolkit/components/telemetry/app/TelemetrySend.jsm index d64da6858124..ba125ea6a459 100644 --- a/toolkit/components/telemetry/app/TelemetrySend.jsm +++ b/toolkit/components/telemetry/app/TelemetrySend.jsm @@ -1588,23 +1588,6 @@ var TelemetrySendImpl = { }, runPingSender(pings, observer) { - if (AppConstants.platform === "android") { - throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); - } - - const exeName = - AppConstants.platform === "win" ? "pingsender.exe" : "pingsender"; - - let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile); - exe.append(exeName); - - let params = pings.flatMap(ping => [ping.url, ping.path]); - let process = Cc["@mozilla.org/process/util;1"].createInstance( - Ci.nsIProcess - ); - process.init(exe); - process.startHidden = true; - process.noShell = true; - process.runAsync(params, params.length, observer); + throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); }, }; diff --git a/toolkit/components/telemetry/moz.build b/toolkit/components/telemetry/moz.build index 3eee4e938c4e..cedf9b313d9c 100644 --- a/toolkit/components/telemetry/moz.build +++ b/toolkit/components/telemetry/moz.build @@ -8,10 +8,6 @@ include("/ipc/chromium/chromium-config.mozbuild") FINAL_LIBRARY = "xul" -DIRS = [ - "pingsender", -] - DEFINES["MOZ_APP_VERSION"] = '"%s"' % CONFIG["MOZ_APP_VERSION"] LOCAL_INCLUDES += [
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 26345: Hide tracking protection UI
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit df87f8c8c13f444eba8889d274a1eb7bbf0f2a07 Author: Alex Catarineu <acat(a)torproject.org> Date: Tue Sep 10 16:29:31 2019 +0200 Bug 26345: Hide tracking protection UI --- browser/base/content/browser-siteIdentity.js | 4 ++-- browser/base/content/browser.xhtml | 4 ++-- browser/components/about/AboutRedirector.cpp | 4 ---- browser/components/about/components.conf | 1 - browser/components/moz.build | 1 - browser/themes/shared/preferences/privacy.css | 4 ++++ 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index ca880a5a29dd..7c9a91ed5af1 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -921,10 +921,10 @@ var gIdentityHandler = { gPermissionPanel.refreshPermissionIcons(); } - // Hide the shield icon if it is a chrome page. + // Bug 26345: Hide tracking protection UI. gProtectionsHandler._trackingProtectionIconContainer.classList.toggle( "chromeUI", - this._isSecureInternalUI + true ); }, diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 33af225f739b..eebb21d08a3d 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -771,7 +771,7 @@ oncommand="gSync.toggleAccountPanel(this, event)"/> </toolbaritem> <toolbarseparator class="sync-ui-item"/> - <toolbaritem> + <toolbaritem hidden="true"> <toolbarbutton id="appMenu-protection-report-button" class="subviewbutton subviewbutton-iconic" oncommand="gProtectionsHandler.openProtections(); gProtectionsHandler.recordClick('open_full_report', null, 'app_menu');"> @@ -782,7 +782,7 @@ </label> </toolbarbutton> </toolbaritem> - <toolbarseparator id="appMenu-tp-separator"/> + <toolbarseparator hidden="true" id="appMenu-tp-separator"/> <toolbarbutton id="appMenu-new-window-button" class="subviewbutton subviewbutton-iconic" label="&newNavigatorCmd.label;" diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index 956e25c818e1..e6cf3fe0ef9f 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -122,10 +122,6 @@ static const RedirEntry kRedirMap[] = { nsIAboutModule::HIDE_FROM_ABOUTABOUT}, {"restartrequired", "chrome://browser/content/aboutRestartRequired.xhtml", nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, - {"protections", "chrome://browser/content/protections.html", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS}, {"ion", "chrome://browser/content/ion.html", nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, #ifdef TOR_BROWSER_UPDATE diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf index a880a161a0f2..faf6107d6fa6 100644 --- a/browser/components/about/components.conf +++ b/browser/components/about/components.conf @@ -20,7 +20,6 @@ pages = [ 'policies', 'preferences', 'privatebrowsing', - 'protections', 'profiling', 'reader', 'restartrequired', diff --git a/browser/components/moz.build b/browser/components/moz.build index 1c421b761888..ef09055b990a 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -46,7 +46,6 @@ DIRS += [ "preferences", "privatebrowsing", "prompts", - "protections", "protocolhandler", "resistfingerprinting", "search", diff --git a/browser/themes/shared/preferences/privacy.css b/browser/themes/shared/preferences/privacy.css index 5e830c19af2b..c0a8a108819c 100644 --- a/browser/themes/shared/preferences/privacy.css +++ b/browser/themes/shared/preferences/privacy.css @@ -77,6 +77,10 @@ /* Content Blocking */ +#trackingGroup { + display: none; +} + /* Override styling that sets descriptions as grey */ #trackingGroup description.indent, #trackingGroup .indent > description {
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 27511: Add new identity button to toolbar
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 6a692b49fcde9321904ab1d723f5af6c6f7889b2 Author: Alex Catarineu <acat(a)torproject.org> Date: Fri Oct 4 19:08:33 2019 +0200 Bug 27511: Add new identity button to toolbar Also added 'New circuit for this site' button to CustomizableUI, but not visible by default. --- browser/base/content/browser.xhtml | 10 ++++++++++ .../components/customizableui/CustomizableUI.jsm | 21 +++++++++++++++++++++ browser/themes/shared/icons/new_circuit.svg | 8 ++++++++ browser/themes/shared/icons/new_identity.svg | 9 +++++++++ browser/themes/shared/jar.inc.mn | 3 +++ browser/themes/shared/menupanel.inc.css | 8 ++++++++ browser/themes/shared/toolbarbutton-icons.inc.css | 8 ++++++++ 7 files changed, 67 insertions(+) diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index eebb21d08a3d..6b4120b34b4b 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -2251,6 +2251,16 @@ ondragenter="newWindowButtonObserver.onDragOver(event)" ondragexit="newWindowButtonObserver.onDragExit(event)"/> + <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&torbutton.context_menu.new_identity;" + oncommand="torbutton_new_identity();" + tooltiptext="&torbutton.context_menu.new_identity;"/> + + <toolbarbutton id="new-circuit-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&torbutton.context_menu.new_circuit;" + oncommand="torbutton_new_circuit();" + tooltiptext="&torbutton.context_menu.new_circuit;"/> + <toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional" observes="View:FullScreen" type="checkbox" diff --git a/browser/components/customizableui/CustomizableUI.jsm b/browser/components/customizableui/CustomizableUI.jsm index 1e01b321adae..b7138e525662 100644 --- a/browser/components/customizableui/CustomizableUI.jsm +++ b/browser/components/customizableui/CustomizableUI.jsm @@ -86,6 +86,8 @@ const kSubviewEvents = ["ViewShowing", "ViewHiding"]; */ var kVersion = 17; +var kTorVersion = 1; + /** * Buttons removed from built-ins by version they were removed. kVersion must be * bumped any time a new id is added to this. Use the button id as key, and @@ -629,6 +631,20 @@ var CustomizableUIInternal = { navbarPlacements.splice(newPosition, 0, "save-to-pocket-button"); } } + + let currentTorVersion = gSavedState.currentTorVersion; + if (currentTorVersion < 1 && gSavedState.placements) { + let navbarPlacements = gSavedState.placements[CustomizableUI.AREA_NAVBAR]; + if (navbarPlacements) { + let secLevelIndex = navbarPlacements.indexOf("security-level-button"); + if (secLevelIndex === -1) { + let urlbarIndex = navbarPlacements.indexOf("urlbar-container"); + secLevelIndex = urlbarIndex + 1; + navbarPlacements.splice(secLevelIndex, 0, "security-level-button"); + } + navbarPlacements.splice(secLevelIndex + 1, 0, "new-identity-button"); + } + } }, _updateForNewProtonVersion() { @@ -2535,6 +2551,10 @@ var CustomizableUIInternal = { gSavedState.currentVersion = 0; } + if (!("currentTorVersion" in gSavedState)) { + gSavedState.currentTorVersion = 0; + } + gSeenWidgets = new Set(gSavedState.seen || []); gDirtyAreaCache = new Set(gSavedState.dirtyAreaCache || []); gNewElementCount = gSavedState.newElementCount || 0; @@ -2613,6 +2633,7 @@ var CustomizableUIInternal = { seen: gSeenWidgets, dirtyAreaCache: gDirtyAreaCache, currentVersion: kVersion, + currentTorVersion: kTorVersion, newElementCount: gNewElementCount, }; diff --git a/browser/themes/shared/icons/new_circuit.svg b/browser/themes/shared/icons/new_circuit.svg new file mode 100644 index 000000000000..e0a93cc83502 --- /dev/null +++ b/browser/themes/shared/icons/new_circuit.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>Icon / New Circuit(a)1.5x</title> + <g id="Icon-/-New-Circuit" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <path d="M13.4411138,10.1446317 L9.5375349,10.1446317 C8.99786512,10.1446317 8.56164018,10.5818326 8.56164018,11.1205264 C8.56164018,11.6592203 8.99786512,12.0964212 9.5375349,12.0964212 L11.4571198,12.0964212 C10.7554515,13.0479185 9.73466563,13.692009 8.60067597,13.9359827 C8.41818366,13.9720908 8.23276366,14.0033194 8.04734366,14.0218614 C7.97219977,14.0277168 7.89803177,14.0306445 7.82288788,14.0335722 C6.07506044,14.137017 4.290149,13.4499871 3.38647049,11.857327 C2.52280367,10.3349312 2.77263271,8.15966189 3.93687511,6.87343267 C5.12453898,5.56183017 7.44814431,5.04363008 8.21226987,3.38558497 C9.01738301,4.92847451 9.60682342,5.02801577 10.853041,6.15029468 C11.2892659,6.54455615 11.9704404,7.55558307 12.1861132,8.10501179 C12.3051723,8.40949094 12.5013272,9.17947187 12.5013272,9.17947187 L14.2862386,9.17947187 C14.2091429,7.59754654 13.439162,5.96877827 12.2261248,4.93628166 C11.279507,4.13116853 10.5065984,3.84718317 9.77662911,2.8088312 C9.63219669,2.60194152 9.599 99216,2.4565332 9.56290816,2.21646311 C9.53851079,2.00762164 9.54143848,1.78511764 9.62048595,1.53919218 C9.65952174,1.41720534 9.59804037,1.28545955 9.47702943,1.23764071 L6.40296106,0.0167964277 C6.32391359,-0.0134563083 6.23413128,-0.00272146652 6.16679454,0.0480250584 L5.95502539,0.206120002 C5.85743592,0.280288 5.82815908,0.416913259 5.89159223,0.523285783 C6.70060895,1.92564648 6.36978064,2.82542141 5.8984235,3.20211676 C5.4914754,3.4900057 4.99084141,3.72226864 4.63366394,3.95453159 C3.82367132,4.47956294 3.03222071,5.02508808 2.40374451,5.76774396 C0.434388969,8.09427695 0.519291809,12.0046871 2.77165682,14.1077402 C3.65288975,14.9284676 4.70295247,15.4749686 5.81742423,15.7570022 C5.81742423,15.7570022 6.13556591,15.833122 6.21754107,15.8497122 C7.36616915,16.0829511 8.53529102,16.0146384 9.62243774,15.6672199 C9.67416016,15.6525815 9.77174963,15.620377 9.76784605,15.6154975 C10.7730176,15.2700308 11.7049971,14.7010841 12.4652191,13.90573 L12.4652191,15.0241053 C12.4652191, 15.5627992 12.901444,16 13.4411138,16 C13.9798077,16 14.4170085,15.5627992 14.4170085,15.0241053 L14.4170085,11.1205264 C14.4170085,10.5818326 13.9798077,10.1446317 13.4411138,10.1446317" id="Fill-3" fill="context-fill" fill-opacity="context-fill-opacity"></path> + <path d="M5.107,7.462 C4.405,8.078 4,8.946 4,9.839 C4,10.712 4.422,11.57 5.13,12.132 C5.724,12.607 6.627,12.898 7.642,12.949 L7.642,5.8 C7.39,6.029 7.103,6.227 6.791,6.387 C5.993,6.812 5.489,7.133 5.107,7.462" id="Fill-1" fill="context-fill" fill-opacity="context-fill-opacity"></path> + </g> +</svg> diff --git a/browser/themes/shared/icons/new_identity.svg b/browser/themes/shared/icons/new_identity.svg new file mode 100644 index 000000000000..91d5b35f7e80 --- /dev/null +++ b/browser/themes/shared/icons/new_identity.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>New Identity Icon</title> + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="New-Identity-Icon" fill="#000000" fill-rule="nonzero"> + <path d="M4.65687153,14.5532899 L5.79494313,12.0855326 C5.8689125,11.9251399 5.6620883,11.7793527 5.53742729,11.9040137 L3.77194352,13.6694975 L2.32342782,12.2228406 L4.089841,10.4564274 C4.21450201,10.3317664 4.06871482,10.1249422 3.90832206,10.1989116 L1.43773764,11.338287 L0.206601383,10.1087306 C0.0509544211,9.9532834 -0.0167994233,9.75447206 0.00351451705,9.53432844 C0.0238284574,9.31418483 0.154794797,9.13897939 0.330406365,9.0302193 L4.61213917,6.53066101 C4.98542292,6.31331572 5.42541251,6.16259067 5.8659261,6.07796117 C6.63682488,5.92985954 7.40999434,6.06817199 8.09666802,6.42610336 L12.618483,1.910278 C13.0562019,1.47313888 13.7399062,1.45652879 14.1403159,1.87828207 C14.5407256,2.30003536 14.523905,2.96081599 14.0861861,3.39795511 L9.56437119,7.91378047 C9.92258101,8.57753432 10.0391721,9.37155544 9.91292178,10.1416209 C9.85023328,10.5817332 9.67706706,10.9989392 9.45960494,11.3937636 L6.95651989,15.6478297 C6.84761416,15.82321 6.6720026,15.9319701 6.47398108 ,15.9964916 C6.25354962,16.0167745 6.0544801,15.9491049 5.89883314,15.7936577 L4.65687153,14.5532899 L4.65687153,14.5532899 Z M6.35600863,9.57888316 C6.35684236,9.57982492 6.35770616,9.58074275 6.35860024,9.58163642 L7.56801202,10.7899206 C7.78820303,11.010009 8.15567242,10.9533982 8.29166823,10.678253 C8.42766403,10.4031079 8.55818512,10.1511975 8.61427424,9.83946755 C8.73630873,9.14856819 8.51477165,8.45005355 8.01189873,7.92920397 C8.01085853,7.92816425 8.00979562,7.92715687 8.00871022,7.92618158 C8.00773493,7.92509618 8.00672754,7.92403327 8.00568783,7.92299307 C7.48483824,7.42012014 6.7863236,7.19858307 6.09542425,7.32061756 C5.78369428,7.37670668 5.53178393,7.50722777 5.25663877,7.64322357 C4.98149362,7.77921937 4.92488284,8.14668876 5.14497116,8.36687978 L6.35325537,9.57629155 C6.35414904,9.57718564 6.35506687,9.57804944 6.35600863,9.57888316 L6.35600863,9.57888316 Z M3.56503003,4.86094581 C3.44279837,4.85716019 3.33693302,4.76594656 3.31450832,4.6450962 C3.29259157,4.5009814 3 3.24425431,4.36089837 3.1719467,4.23194774 C3.04272848,4.15978087 2.90235166,4.11153221 2.75793184,4.08964745 C2.63678145,4.06729735 2.5453314,3.9616241 2.54155161,3.83961366 C2.53777182,3.71760322 2.62276629,3.61489221 2.74265726,3.59658884 C2.88757581,3.57942626 3.02687427,3.53584537 3.15371096,3.46798665 C3.21938702,3.3436261 3.26061987,3.20700605 3.27529255,3.0651408 C3.29205048,2.94466859 3.39451537,2.85825378 3.5172925,2.86104768 C3.6386065,2.86399065 3.74452528,2.95324633 3.76872081,3.07292141 C3.79288781,3.21715288 3.84342323,3.35694342 3.91777207,3.4852254 C4.04615548,3.55876237 4.18583906,3.60883869 4.32991405,3.63297757 C4.45015386,3.6576218 4.53936117,3.76418021 4.54139495,3.88559216 C4.54342874,4.00700411 4.45770065,4.10814717 4.33816215,4.12536877 C4.1960481,4.14067978 4.05931708,4.18249381 3.9349938,4.24866259 C3.86697751,4.37522253 3.82328954,4.51422019 3.80607564,4.65882867 C3.78847982,4.77811508 3.68677836,4.86339193 3.56503003,4.86094581 Z M14.4103464,14.3126948 C14.2513672,14.307719 14.1137716,14.188804 14.0849193,14.0314492 C14.045996,13.7585014 13.9510862,13.4938971 13.8061961,13.2543814 C13.5663773,13.109665 13.301434,13.0148623 13.0281329,12.9759728 C12.8707684,12.946921 12.75198,12.8095493 12.7470672,12.6509372 C12.7421545,12.492325 12.8525523,12.3587997 13.0082799,12.3350024 C13.2816632,12.3044807 13.5433622,12.2185794 13.7775725,12.0824861 C13.9099238,11.8524988 13.992337,11.5955854 14.0197279,11.3275956 C14.0417134,11.1717293 14.1740126,11.0598594 14.3327736,11.0628895 C14.4905572,11.0667732 14.6282205,11.1831391 14.6593783,11.3389665 C14.703143,11.6110771 14.8017156,11.8740418 14.9490566,12.1117486 C15.1872615,12.2578242 15.450159,12.3559923 15.7221615,12.4004323 C15.8783433,12.4324665 15.9942186,12.5709889 15.9968634,12.7288231 C15.9995083,12.8866572 15.8881575,13.0181443 15.7328877,13.0405352 C15.4641157,13.0669716 15.2064728,13.14931 14.9763475,13.2823129 C14.8406047,13.5164173 14.7548186,13.7777086 14.724105,14.0506041 C14.70 09285,14.2056508 14.5685348,14.3162427 14.4103464,14.3126948 Z M8.37194288,2.75251202 C8.23729358,2.7482977 8.12075529,2.6475812 8.09631849,2.5143077 C8.06335201,2.28313133 7.98296703,2.05902158 7.86025062,1.85616098 C7.65713325,1.73359169 7.43273641,1.65329741 7.2012608,1.62035947 C7.06797908,1.59575373 6.9673698,1.47940513 6.96320889,1.34506671 C6.95904797,1.21072829 7.05255074,1.09763741 7.18444606,1.07748204 C7.41599123,1.0516313 7.6376403,0.978876138 7.83600755,0.863610339 C7.94810399,0.668819911 8.01790485,0.45122403 8.04110388,0.224246882 C8.05972477,0.0922341146 8.17177714,-0.00251545243 8.30624168,5.089704e-05 C8.43987839,0.00334026838 8.55647391,0.101897787 8.58286336,0.233877601 C8.61993042,0.464344927 8.70341768,0.687066016 8.82820981,0.888394549 C9.02996027,1.012115 9.25262444,1.09525963 9.4830002,1.13289867 C9.6152802,1.16003037 9.71342219,1.27735361 9.71566226,1.41103311 C9.71790232,1.5447126 9.62359245,1.65607713 9.49208487,1.67504141 C9.26444525,1.69743199 9.0462315 3,1.76716948 8.85132417,1.87981789 C8.73635526,2.07809534 8.66369764,2.2993991 8.63768445,2.53053117 C8.61805481,2.66184983 8.50592239,2.75551697 8.37194288,2.75251202 Z" id="Shape" fill="context-fill" fill-opacity="context-fill-opacity"></path> + </g> + </g> +</svg> \ No newline at end of file diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn index a33b1dcd5c81..136ceb6833fa 100644 --- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -262,3 +262,6 @@ skin/classic/browser/places/tree-icons.css (../shared/places/tree-icons.css) skin/classic/browser/privatebrowsing/aboutPrivateBrowsing.css (../shared/privatebrowsing/aboutPrivateBrowsing.css) skin/classic/browser/privatebrowsing/favicon.svg (../shared/privatebrowsing/favicon.svg) + + skin/classic/browser/new_circuit.svg (../shared/icons/new_circuit.svg) + skin/classic/browser/new_identity.svg (../shared/icons/new_identity.svg) diff --git a/browser/themes/shared/menupanel.inc.css b/browser/themes/shared/menupanel.inc.css index 26c0a1a0a068..06de3149d23b 100644 --- a/browser/themes/shared/menupanel.inc.css +++ b/browser/themes/shared/menupanel.inc.css @@ -192,3 +192,11 @@ toolbarpaletteitem[place="palette"] > #bookmarks-menu-button, list-style-image: url(chrome://browser/skin/fullscreen-exit.svg); } } /** END Proton **/ + +#appMenuNewIdentity { + list-style-image: url("chrome://browser/skin/new_identity.svg"); +} + +#appMenuNewCircuit { + list-style-image: url("chrome://browser/skin/new_circuit.svg"); +} diff --git a/browser/themes/shared/toolbarbutton-icons.inc.css b/browser/themes/shared/toolbarbutton-icons.inc.css index 6de168368436..a7c3cc0b6aee 100644 --- a/browser/themes/shared/toolbarbutton-icons.inc.css +++ b/browser/themes/shared/toolbarbutton-icons.inc.css @@ -225,6 +225,14 @@ toolbar[brighttext] { list-style-image: url("chrome://browser/skin/new-tab.svg"); } +#new-identity-button { + list-style-image: url("chrome://browser/skin/new_identity.svg"); +} + +#new-circuit-button { + list-style-image: url("chrome://browser/skin/new_circuit.svg"); +} + #privatebrowsing-button { list-style-image: url("chrome://browser/skin/privateBrowsing.svg"); }
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 31575: Replace Firefox Home (newtab) with about:tor
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit f7fcfff6c14345f5f4070135c71c95e3a5500909 Author: Alex Catarineu <acat(a)torproject.org> Date: Mon Sep 9 13:04:34 2019 +0200 Bug 31575: Replace Firefox Home (newtab) with about:tor Avoid loading AboutNewTab in BrowserGlue.jsm in order to avoid several network requests that we do not need. Besides, about:newtab will now point to about:blank or about:tor (depending on browser.newtabpage.enabled) and about:home will point to about:tor. --- browser/components/BrowserGlue.jsm | 33 ++---------------------- browser/components/newtab/AboutNewTabService.jsm | 15 +---------- browser/components/preferences/home.inc.xhtml | 4 +-- browser/components/preferences/preferences.xhtml | 5 +++- browser/modules/HomePage.jsm | 2 +- 5 files changed, 10 insertions(+), 49 deletions(-) diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 3dcd18d9b173..c37d564b80cd 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -20,7 +20,6 @@ const { AppConstants } = ChromeUtils.import( Cu.importGlobalProperties(["Glean"]); XPCOMUtils.defineLazyModuleGetters(this, { - AboutNewTab: "resource:///modules/AboutNewTab.jsm", ActorManagerParent: "resource://gre/modules/ActorManagerParent.jsm", AddonManager: "resource://gre/modules/AddonManager.jsm", AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm", @@ -213,28 +212,6 @@ let JSWINDOWACTORS = { matches: ["about:logins", "about:logins?*", "about:loginsimportreport"], }, - AboutNewTab: { - parent: { - moduleURI: "resource:///actors/AboutNewTabParent.jsm", - }, - child: { - moduleURI: "resource:///actors/AboutNewTabChild.jsm", - events: { - DOMContentLoaded: {}, - pageshow: {}, - visibilitychange: {}, - }, - }, - // The wildcard on about:newtab is for the ?endpoint query parameter - // that is used for snippets debugging. The wildcard for about:home - // is similar, and also allows for falling back to loading the - // about:home document dynamically if an attempt is made to load - // about:home?jscache from the AboutHomeStartupCache as a top-level - // load. - matches: ["about:home*", "about:welcome", "about:newtab*"], - remoteTypes: ["privilegedabout"], - }, - AboutPlugins: { parent: { moduleURI: "resource:///actors/AboutPluginsParent.jsm", @@ -1620,8 +1597,6 @@ BrowserGlue.prototype = { // the first browser window has finished initializing _onFirstWindowLoaded: function BG__onFirstWindowLoaded(aWindow) { - AboutNewTab.init(); - TabCrashHandler.init(); ProcessHangMonitor.init(); @@ -5307,12 +5282,8 @@ var AboutHomeStartupCache = { return { pageInputStream: null, scriptInputStream: null }; } - let state = AboutNewTab.activityStream.store.getState(); - return new Promise(resolve => { - this._cacheDeferred = resolve; - this.log.trace("Parent is requesting cache streams."); - this._procManager.sendAsyncMessage(this.CACHE_REQUEST_MESSAGE, { state }); - }); + this.log.error("Activity Stream is disabled in Tor Browser."); + return { pageInputStream: null, scriptInputStream: null }; }, /** diff --git a/browser/components/newtab/AboutNewTabService.jsm b/browser/components/newtab/AboutNewTabService.jsm index 44308daa2b2d..d98c014e3f9e 100644 --- a/browser/components/newtab/AboutNewTabService.jsm +++ b/browser/components/newtab/AboutNewTabService.jsm @@ -420,20 +420,7 @@ class BaseAboutNewTabService { * the newtab page has no effect on the result of this function. */ get defaultURL() { - // Generate the desired activity stream resource depending on state, e.g., - // "resource://activity-stream/prerendered/activity-stream.html" - // "resource://activity-stream/prerendered/activity-stream-debug.html" - // "resource://activity-stream/prerendered/activity-stream-noscripts.html" - return [ - "resource://activity-stream/prerendered/", - "activity-stream", - // Debug version loads dev scripts but noscripts separately loads scripts - this.activityStreamDebug && !this.privilegedAboutProcessEnabled - ? "-debug" - : "", - this.privilegedAboutProcessEnabled ? "-noscripts" : "", - ".html", - ].join(""); + return "about:tor"; } get welcomeURL() { diff --git a/browser/components/preferences/home.inc.xhtml b/browser/components/preferences/home.inc.xhtml index c348e1cf754b..c37dc5e731f6 100644 --- a/browser/components/preferences/home.inc.xhtml +++ b/browser/components/preferences/home.inc.xhtml @@ -33,7 +33,7 @@ class="check-home-page-controlled" data-preference-related="browser.startup.homepage"> <menupopup> - <menuitem value="0" data-l10n-id="home-mode-choice-default" /> + <menuitem value="0" label="&aboutTor.title;" /> <menuitem value="2" data-l10n-id="home-mode-choice-custom" /> <menuitem value="1" data-l10n-id="home-mode-choice-blank" /> </menupopup> @@ -85,7 +85,7 @@ Preferences so we need to handle setting the pref manually.--> <menulist id="newTabMode" flex="1" data-preference-related="browser.newtabpage.enabled"> <menupopup> - <menuitem value="0" data-l10n-id="home-mode-choice-default" /> + <menuitem value="0" label="&aboutTor.title;" /> <menuitem value="1" data-l10n-id="home-mode-choice-blank" /> </menupopup> </menulist> diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml index 10faf11bfecd..2d29b382350d 100644 --- a/browser/components/preferences/preferences.xhtml +++ b/browser/components/preferences/preferences.xhtml @@ -14,7 +14,10 @@ <?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?> <?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?> -<!DOCTYPE html> +<!DOCTYPE html [ +<!ENTITY % aboutTorDTD SYSTEM "chrome://torbutton/locale/aboutTor.dtd"> + %aboutTorDTD; +]> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" diff --git a/browser/modules/HomePage.jsm b/browser/modules/HomePage.jsm index 751e6ebb39b3..01317b9e9754 100644 --- a/browser/modules/HomePage.jsm +++ b/browser/modules/HomePage.jsm @@ -21,7 +21,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { }); const kPrefName = "browser.startup.homepage"; -const kDefaultHomePage = "about:home"; +const kDefaultHomePage = "about:tor"; const kExtensionControllerPref = "browser.startup.homepage_override.extensionControlled"; const kHomePageIgnoreListId = "homepage-urls";
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 32220: Improve the letterboxing experience
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit e67c532e6d15bc8d3ff422ed5a09a6f1ba346862 Author: Richard Pospesel <richard(a)torproject.org> Date: Mon Oct 28 17:42:17 2019 -0700 Bug 32220: Improve the letterboxing experience CSS and JS changes to alter the UX surrounding letterboxing. The browser element containing page content is now anchored to the bottom of the toolbar, and the remaining letterbox margin is the same color as the firefox chrome. The letterbox margin and border are tied to the currently selected theme. Also adds a 'needsLetterbox' property to tabbrowser.xml to fix a race condition present when using the 'isEmpty' property. Using 'isEmpty' as a proxy for 'needsLetterbox' resulted in over-zealous/unnecessary letterboxing of about:blank tabs. --- browser/base/content/browser.css | 8 ++ browser/base/content/tabbrowser-tab.js | 9 +++ browser/themes/shared/tabs.inc.css | 6 ++ .../components/resistfingerprinting/RFPHelper.jsm | 94 +++++++++++++++++++--- 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index ee7a87ea3b9d..c4ce845235de 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -99,6 +99,14 @@ body { display: none; } + +.browserStack > browser.letterboxing { + border-color: var(--chrome-content-separator-color); + border-style: solid; + border-width : 1px; + border-top: none; +} + %ifdef MENUBAR_CAN_AUTOHIDE #toolbar-menubar[autohide="true"] { overflow: hidden; diff --git a/browser/base/content/tabbrowser-tab.js b/browser/base/content/tabbrowser-tab.js index 09b088d59a90..d8d124439cc4 100644 --- a/browser/base/content/tabbrowser-tab.js +++ b/browser/base/content/tabbrowser-tab.js @@ -258,6 +258,15 @@ return true; } + get needsLetterbox() { + let browser = this.linkedBrowser; + if (isBlankPageURL(browser.currentURI.spec)) { + return false; + } + + return true; + } + get lastAccessed() { return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed; } diff --git a/browser/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css index 644d8d5fc97c..1732787434a0 100644 --- a/browser/themes/shared/tabs.inc.css +++ b/browser/themes/shared/tabs.inc.css @@ -70,6 +70,12 @@ background-color: var(--tabpanel-background-color); } +/* extend down the toolbar's colors when letterboxing is enabled*/ +#tabbrowser-tabpanels.letterboxing { + background-color: var(--toolbar-bgcolor); + background-image: var(--toolbar-bgimage); +} + #tabbrowser-tabs, #tabbrowser-arrowscrollbox, #tabbrowser-tabs[positionpinnedtabs] > #tabbrowser-arrowscrollbox > .tabbrowser-tab[pinned] { diff --git a/toolkit/components/resistfingerprinting/RFPHelper.jsm b/toolkit/components/resistfingerprinting/RFPHelper.jsm index 166ad21e9013..9520d8720631 100644 --- a/toolkit/components/resistfingerprinting/RFPHelper.jsm +++ b/toolkit/components/resistfingerprinting/RFPHelper.jsm @@ -40,6 +40,7 @@ class _RFPHelper { // ============================================================================ constructor() { this._initialized = false; + this._borderDimensions = null; } init() { @@ -361,6 +362,24 @@ class _RFPHelper { }); } + getBorderDimensions(aBrowser) { + if (this._borderDimensions) { + return this._borderDimensions; + } + + const win = aBrowser.ownerGlobal; + const browserStyle = win.getComputedStyle(aBrowser); + + this._borderDimensions = { + top : parseInt(browserStyle.borderTopWidth), + right: parseInt(browserStyle.borderRightWidth), + bottom : parseInt(browserStyle.borderBottomWidth), + left : parseInt(browserStyle.borderLeftWidth), + }; + + return this._borderDimensions; + } + _addOrClearContentMargin(aBrowser) { let tab = aBrowser.getTabBrowser().getTabForBrowser(aBrowser); @@ -369,9 +388,13 @@ class _RFPHelper { return; } + // we add the letterboxing class even if the content does not need letterboxing + // in which case margins are set such that the borders are hidden + aBrowser.classList.add("letterboxing"); + // We should apply no margin around an empty tab or a tab with system // principal. - if (tab.isEmpty || aBrowser.contentPrincipal.isSystemPrincipal) { + if (!tab.needsLetterbox || aBrowser.contentPrincipal.isSystemPrincipal) { this._clearContentViewMargin(aBrowser); } else { this._roundContentView(aBrowser); @@ -539,10 +562,29 @@ class _RFPHelper { // Calculating the margins around the browser element in order to round the // content viewport. We will use a 200x100 stepping if the dimension set // is not given. - let margins = calcMargins(containerWidth, containerHeight); + + const borderDimensions = this.getBorderDimensions(aBrowser); + const marginDims = calcMargins(containerWidth, containerHeight - borderDimensions.top); + + let margins = { + top : 0, + right : 0, + bottom : 0, + left : 0, + }; + + // snap browser element to top + margins.top = 0; + // and leave 'double' margin at the bottom + margins.bottom = 2 * marginDims.height - borderDimensions.bottom; + // identical margins left and right + margins.right = marginDims.width - borderDimensions.right; + margins.left = marginDims.width - borderDimensions.left; + + const marginStyleString = `${margins.top}px ${margins.right}px ${margins.bottom}px ${margins.left}px`; // If the size of the content is already quantized, we do nothing. - if (aBrowser.style.margin == `${margins.height}px ${margins.width}px`) { + if (aBrowser.style.margin === marginStyleString) { log("_roundContentView[" + logId + "] is_rounded == true"); if (this._isLetterboxingTesting) { log( @@ -563,19 +605,35 @@ class _RFPHelper { "_roundContentView[" + logId + "] setting margins to " + - margins.width + - " x " + - margins.height + marginStyleString ); - // One cannot (easily) control the color of a margin unfortunately. - // An initial attempt to use a border instead of a margin resulted - // in offset event dispatching; so for now we use a colorless margin. - aBrowser.style.margin = `${margins.height}px ${margins.width}px`; + + // The margin background color is determined by the background color of the + // window's tabpanels#tabbrowser-tabpanels element + aBrowser.style.margin = marginStyleString; }); } _clearContentViewMargin(aBrowser) { + const borderDimensions = this.getBorderDimensions(aBrowser); + // set the margins such that the browser elements border is visible up top, but + // are rendered off-screen on the remaining sides + let margins = { + top : 0, + right : -borderDimensions.right, + bottom : -borderDimensions.bottom, + left : -borderDimensions.left, + }; + const marginStyleString = `${margins.top}px ${margins.right}px ${margins.bottom}px ${margins.left}px`; + + aBrowser.ownerGlobal.requestAnimationFrame(() => { + aBrowser.style.margin = marginStyleString; + }); + } + + _removeLetterboxing(aBrowser) { aBrowser.ownerGlobal.requestAnimationFrame(() => { + aBrowser.classList.remove("letterboxing"); aBrowser.style.margin = ""; }); } @@ -593,6 +651,11 @@ class _RFPHelper { aWindow.gBrowser.addTabsProgressListener(this); aWindow.addEventListener("TabOpen", this); + const tabPanel = aWindow.document.getElementById("tabbrowser-tabpanels"); + if (tabPanel) { + tabPanel.classList.add("letterboxing"); + } + // Rounding the content viewport. this._updateMarginsForTabsInWindow(aWindow); } @@ -616,10 +679,17 @@ class _RFPHelper { tabBrowser.removeTabsProgressListener(this); aWindow.removeEventListener("TabOpen", this); - // Clear all margins and tooltip for all browsers. + // revert tabpanel's background colors to default + const tabPanel = aWindow.document.getElementById("tabbrowser-tabpanels"); + if (tabPanel) { + tabPanel.classList.remove("letterboxing"); + } + + // and revert each browser element to default, + // restore default margins and remove letterboxing class for (let tab of tabBrowser.tabs) { let browser = tab.linkedBrowser; - this._clearContentViewMargin(browser); + this._removeLetterboxing(browser); } }
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 31740: Remove some unnecessary RemoteSettings instances
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit fd7119150ec874e193ba4b0b06ecdd044f364279 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Oct 16 23:01:12 2019 +0200 Bug 31740: Remove some unnecessary RemoteSettings instances More concretely, SearchService.jsm 'hijack-blocklists' and url-classifier-skip-urls. Avoid creating instance for 'anti-tracking-url-decoration'. If prefs are disabling their usage, avoid creating instances for 'cert-revocations' and 'intermediates'. Do not ship JSON dumps for collections we do not expect to need. For the ones in the 'main' bucket, this prevents them from being synced unnecessarily (the code in remote-settings does so for collections in the main bucket for which a dump or local data exists). For the collections in the other buckets, we just save some size by not shipping their dumps. We also clear the collections database on the v2 -> v3 migration. --- browser/app/profile/000-tor-browser.js | 3 +++ browser/components/search/SearchSERPTelemetry.jsm | 6 ------ .../url-classifier/UrlClassifierFeatureBase.cpp | 2 +- netwerk/url-classifier/components.conf | 6 ------ security/manager/ssl/RemoteSecuritySettings.jsm | 23 ++++++++++++++++++++++ services/settings/IDBHelpers.jsm | 4 ++++ services/settings/dumps/blocklists/moz.build | 1 - services/settings/dumps/main/moz.build | 7 ------- services/settings/dumps/security-state/moz.build | 1 - .../components/antitracking/antitracking.manifest | 2 +- toolkit/components/antitracking/components.conf | 7 ------- toolkit/components/search/SearchService.jsm | 2 -- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js index d54f3aae2557..0200e68b5ce1 100644 --- a/browser/app/profile/000-tor-browser.js +++ b/browser/app/profile/000-tor-browser.js @@ -149,6 +149,9 @@ pref("extensions.fxmonitor.enabled", false); pref("signon.management.page.mobileAndroidURL", ""); pref("signon.management.page.mobileAppleURL", ""); +// Disable remote "password recipes" +pref("signon.recipes.remoteRecipesEnabled", false); + // Disable ServiceWorkers and push notifications by default pref("dom.serviceWorkers.enabled", false); pref("dom.push.enabled", false); diff --git a/browser/components/search/SearchSERPTelemetry.jsm b/browser/components/search/SearchSERPTelemetry.jsm index 3e9d92548213..5c499e91713a 100644 --- a/browser/components/search/SearchSERPTelemetry.jsm +++ b/browser/components/search/SearchSERPTelemetry.jsm @@ -96,13 +96,7 @@ class TelemetryHandler { return; } - this._telemetrySettings = RemoteSettings(TELEMETRY_SETTINGS_KEY); let rawProviderInfo = []; - try { - rawProviderInfo = await this._telemetrySettings.get(); - } catch (ex) { - logConsole.error("Could not get settings:", ex); - } // Send the provider info to the child handler. this._contentHandler.init(rawProviderInfo); diff --git a/netwerk/url-classifier/UrlClassifierFeatureBase.cpp b/netwerk/url-classifier/UrlClassifierFeatureBase.cpp index 07da1fd07374..48bcc7d10af9 100644 --- a/netwerk/url-classifier/UrlClassifierFeatureBase.cpp +++ b/netwerk/url-classifier/UrlClassifierFeatureBase.cpp @@ -78,7 +78,7 @@ void UrlClassifierFeatureBase::InitializePreferences() { nsCOMPtr<nsIUrlClassifierExceptionListService> exceptionListService = do_GetService("@mozilla.org/url-classifier/exception-list-service;1"); - if (NS_WARN_IF(!exceptionListService)) { + if (!exceptionListService) { return; } diff --git a/netwerk/url-classifier/components.conf b/netwerk/url-classifier/components.conf index 03a02f0ebeab..b2e667247317 100644 --- a/netwerk/url-classifier/components.conf +++ b/netwerk/url-classifier/components.conf @@ -13,10 +13,4 @@ Classes = [ 'constructor': 'mozilla::net::ChannelClassifierService::GetSingleton', 'headers': ['mozilla/net/ChannelClassifierService.h'], }, - { - 'cid': '{b9f4fd03-9d87-4bfd-9958-85a821750ddc}', - 'contract_ids': ['@mozilla.org/url-classifier/exception-list-service;1'], - 'jsm': 'resource://gre/modules/UrlClassifierExceptionListService.jsm', - 'constructor': 'UrlClassifierExceptionListService', - }, ] diff --git a/security/manager/ssl/RemoteSecuritySettings.jsm b/security/manager/ssl/RemoteSecuritySettings.jsm index b59b2c8a4391..898de699de07 100644 --- a/security/manager/ssl/RemoteSecuritySettings.jsm +++ b/security/manager/ssl/RemoteSecuritySettings.jsm @@ -282,6 +282,16 @@ var RemoteSecuritySettings = { class IntermediatePreloads { constructor() { + this.maybeInit(); + } + + maybeInit() { + if ( + this.client || + !Services.prefs.getBoolPref(INTERMEDIATES_ENABLED_PREF, true) + ) { + return; + } this.client = RemoteSettings( Services.prefs.getCharPref(INTERMEDIATES_COLLECTION_PREF), { @@ -311,6 +321,7 @@ class IntermediatePreloads { ); return; } + this.maybeInit(); // Download attachments that are awaiting download, up to a max. const maxDownloadsPerRun = Services.prefs.getIntPref( @@ -621,6 +632,16 @@ function compareFilters(filterA, filterB) { class CRLiteFilters { constructor() { + this.maybeInit(); + } + + maybeInit() { + if ( + this.client || + !Services.prefs.getBoolPref(CRLITE_FILTERS_ENABLED_PREF, true) + ) { + return; + } this.client = RemoteSettings( Services.prefs.getCharPref(CRLITE_FILTERS_COLLECTION_PREF), { @@ -648,6 +669,8 @@ class CRLiteFilters { return; } + this.maybeInit(); + let hasPriorFilter = await hasPriorData( Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_FULL ); diff --git a/services/settings/IDBHelpers.jsm b/services/settings/IDBHelpers.jsm index 5dc59c3687ef..010a5ea82987 100644 --- a/services/settings/IDBHelpers.jsm +++ b/services/settings/IDBHelpers.jsm @@ -188,6 +188,10 @@ async function openIDB(allowUpgrades = true) { }); } if (event.oldVersion < 3) { + // Clear existing stores for a fresh start + transaction.objectStore("records").clear(); + transaction.objectStore("timestamps").clear(); + transaction.objectStore("collections").clear(); // Attachment store db.createObjectStore("attachments", { keyPath: ["cid", "attachmentId"], diff --git a/services/settings/dumps/blocklists/moz.build b/services/settings/dumps/blocklists/moz.build index cdeb7e180c38..4ca18acd4ff6 100644 --- a/services/settings/dumps/blocklists/moz.build +++ b/services/settings/dumps/blocklists/moz.build @@ -10,7 +10,6 @@ with Files("**"): # The addons blocklist is also in mobile/android/installer/package-manifest.in FINAL_TARGET_FILES.defaults.settings.blocklists += [ "addons-bloomfilters.json", - "addons.json", "gfx.json", "plugins.json", ] diff --git a/services/settings/dumps/main/moz.build b/services/settings/dumps/main/moz.build index 1d194acb7eb9..de5ea7a9efdb 100644 --- a/services/settings/dumps/main/moz.build +++ b/services/settings/dumps/main/moz.build @@ -3,17 +3,10 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. FINAL_TARGET_FILES.defaults.settings.main += [ - "anti-tracking-url-decoration.json", "example.json", "hijack-blocklists.json", "language-dictionaries.json", - "password-recipes.json", - "search-config.json", "search-default-override-allowlist.json", - "search-telemetry.json", - "sites-classification.json", - "top-sites.json", - "url-classifier-skip-urls.json", "websites-with-shared-credential-backends.json", ] diff --git a/services/settings/dumps/security-state/moz.build b/services/settings/dumps/security-state/moz.build index 9133cd4e3ed6..0d250ecddbe8 100644 --- a/services/settings/dumps/security-state/moz.build +++ b/services/settings/dumps/security-state/moz.build @@ -3,7 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. FINAL_TARGET_FILES.defaults.settings["security-state"] += [ - "intermediates.json", "onecrl.json", ] diff --git a/toolkit/components/antitracking/antitracking.manifest b/toolkit/components/antitracking/antitracking.manifest index 5eb37f9a3f99..872e6af07575 100644 --- a/toolkit/components/antitracking/antitracking.manifest +++ b/toolkit/components/antitracking/antitracking.manifest @@ -1 +1 @@ -category profile-after-change URLDecorationAnnotationsService @mozilla.org/tracking-url-decoration-service;1 process=main +# category profile-after-change URLDecorationAnnotationsService @mozilla.org/tracking-url-decoration-service;1 process=main diff --git a/toolkit/components/antitracking/components.conf b/toolkit/components/antitracking/components.conf index c5e21b06156b..53db083e394c 100644 --- a/toolkit/components/antitracking/components.conf +++ b/toolkit/components/antitracking/components.conf @@ -11,13 +11,6 @@ Classes = [ 'jsm': 'resource://gre/modules/TrackingDBService.jsm', 'constructor': 'TrackingDBService', }, - { - 'cid': '{5874af6d-5719-4e1b-b155-ef4eae7fcb32}', - 'contract_ids': ['@mozilla.org/tracking-url-decoration-service;1'], - 'jsm': 'resource://gre/modules/URLDecorationAnnotationsService.jsm', - 'constructor': 'URLDecorationAnnotationsService', - 'processes': ProcessSelector.MAIN_PROCESS_ONLY, - }, { 'cid': '{90d1fd17-2018-4e16-b73c-a04a26fa6dd4}', 'contract_ids': ['@mozilla.org/purge-tracker-service;1'], diff --git a/toolkit/components/search/SearchService.jsm b/toolkit/components/search/SearchService.jsm index 57c77214d319..d111690894b0 100644 --- a/toolkit/components/search/SearchService.jsm +++ b/toolkit/components/search/SearchService.jsm @@ -250,8 +250,6 @@ SearchService.prototype = { // See if we have a settings file so we don't have to parse a bunch of XML. let settings = await this._settings.get(); - this._setupRemoteSettings().catch(Cu.reportError); - await this._loadEngines(settings); // If we've got this far, but the application is now shutting down,
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 32658: Create a new MAR signing key
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 30742b287716bf327867d011efa44eed9acabc4f Author: Georg Koppen <gk(a)torproject.org> Date: Fri Jan 17 12:54:31 2020 +0000 Bug 32658: Create a new MAR signing key It's time for our rotation again: Move the backup key in the front position and add a new backup key. Bug 33803: Move our primary nightly MAR signing key to tor-browser Bug 33803: Add a secondary nightly MAR signing key --- .../update/updater/nightly_aurora_level3_primary.der | Bin 1225 -> 1245 bytes .../updater/nightly_aurora_level3_secondary.der | Bin 1225 -> 1245 bytes toolkit/mozapps/update/updater/release_primary.der | Bin 1225 -> 1229 bytes toolkit/mozapps/update/updater/release_secondary.der | Bin 1225 -> 1229 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/toolkit/mozapps/update/updater/nightly_aurora_level3_primary.der b/toolkit/mozapps/update/updater/nightly_aurora_level3_primary.der index 44fd95dcff89..d579cf801e1a 100644 Binary files a/toolkit/mozapps/update/updater/nightly_aurora_level3_primary.der and b/toolkit/mozapps/update/updater/nightly_aurora_level3_primary.der differ diff --git a/toolkit/mozapps/update/updater/nightly_aurora_level3_secondary.der b/toolkit/mozapps/update/updater/nightly_aurora_level3_secondary.der index 90f8e6e82c63..7cbfa77d06e7 100644 Binary files a/toolkit/mozapps/update/updater/nightly_aurora_level3_secondary.der and b/toolkit/mozapps/update/updater/nightly_aurora_level3_secondary.der differ diff --git a/toolkit/mozapps/update/updater/release_primary.der b/toolkit/mozapps/update/updater/release_primary.der index 1d94f88ad73b..0103a171de88 100644 Binary files a/toolkit/mozapps/update/updater/release_primary.der and b/toolkit/mozapps/update/updater/release_primary.der differ diff --git a/toolkit/mozapps/update/updater/release_secondary.der b/toolkit/mozapps/update/updater/release_secondary.der index 474706c4b73c..fcee3944e9b7 100644 Binary files a/toolkit/mozapps/update/updater/release_secondary.der and b/toolkit/mozapps/update/updater/release_secondary.der differ
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 31607: App menu items stop working on macOS
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit afca75e28c2ba29890cc73119df13a1927810249 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Thu Oct 3 10:53:43 2019 -0400 Bug 31607: App menu items stop working on macOS Avoid re-creating the hidden window, since this causes the nsMenuBarX object that is associated with the app menu to be freed (which in turn causes all of the app menu items to stop working). More detail: There should only be one hidden window. XREMain::XRE_mainRun() contains an explicit call to create the hidden window and that is the normal path by which it is created. However, when Tor Launcher's wizard/progress window is opened during startup, a hidden window is created earlier as a side effect of calls to nsAppShellService::GetHiddenWindow(). Then, when XREMain::XRE_mainRun() creates its hidden window, the original one is freed which also causes the app menu's nsMenuBarX object which is associated with that window to be destroyed. When that happens, the menuGroupOwner property within each Cocoa menu items's MenuItemInfo object is cleared. This breaks the link that is necessary for NativeMenuItemTarget's menuItemHit method to dispatch a menu item event. --- xpfe/appshell/nsAppShellService.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index ed7c2227f4d4..e56cbfb77ca9 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -93,6 +93,10 @@ void nsAppShellService::EnsureHiddenWindow() { NS_IMETHODIMP nsAppShellService::CreateHiddenWindow() { + if (mHiddenWindow) { + return NS_OK; + } + if (!XRE_IsParentProcess()) { return NS_ERROR_NOT_IMPLEMENTED; }
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 27604: Fix addon issues when moving TB directory
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 9d8573ac361ce3612f4261cff5cf9cee95199ff4 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Oct 30 10:44:48 2019 +0100 Bug 27604: Fix addon issues when moving TB directory --- toolkit/mozapps/extensions/internal/XPIProvider.jsm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index a6e020ecd4c9..939dd6a70b24 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -475,7 +475,7 @@ class XPIState { // Builds prior to be 1512436 did not include the rootURI property. // If we're updating from such a build, add that property now. - if (!("rootURI" in this) && this.file) { + if (this.file) { this.rootURI = getURIForResourceInFile(this.file, "").spec; } @@ -488,7 +488,10 @@ class XPIState { saved.currentModifiedTime != this.lastModifiedTime ) { this.lastModifiedTime = saved.currentModifiedTime; - } else if (saved.currentModifiedTime === null) { + } else if ( + saved.currentModifiedTime === null && + (!this.file || !this.file.exists()) + ) { this.missing = true; } } @@ -1449,6 +1452,7 @@ var XPIStates = { if (shouldRestoreLocationData && oldState[loc.name]) { loc.restore(oldState[loc.name]); + changed = changed || loc.path != oldState[loc.name].path; } changed = changed || loc.changed;
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 30237: Add v3 onion services client authentication prompt
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit b50c3862a45bc601c47885efdf18f154bcd93b21 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Nov 12 16:11:05 2019 -0500 Bug 30237: Add v3 onion services client authentication prompt When Tor informs the browser that client authentication is needed, temporarily load about:blank instead of about:neterror and prompt for the user's key. If a correctly formatted key is entered, use Tor's ONION_CLIENT_AUTH_ADD control port command to add the key (via Torbutton's control port module) and reload the page. If the user cancels the prompt, display the standard about:neterror "Unable to connect" page. This requires a small change to browser/actors/NetErrorChild.jsm to account for the fact that the docShell no longer has the failedChannel information. The failedChannel is used to extract TLS-related error info, which is not applicable in the case of a canceled .onion authentication prompt. Add a leaveOpen option to PopupNotifications.show so we can display error messages within the popup notification doorhanger without closing the prompt. Add support for onion services strings to the TorStrings module. Add support for Tor extended SOCKS errors (Tor proposal 304) to the socket transport and SOCKS layers. Improved display of all of these errors will be implemented as part of bug 30025. Also fixes bug 19757: Add a "Remember this key" checkbox to the client auth prompt. Add an "Onion Services Authentication" section within the about:preferences "Privacy & Security section" to allow viewing and removal of v3 onion client auth keys that have been stored on disk. Also fixes bug 19251: use enhanced error pages for onion service errors. --- browser/actors/NetErrorChild.jsm | 7 + browser/base/content/browser.js | 10 + browser/base/content/browser.xhtml | 3 + browser/base/content/certerror/aboutNetError.js | 10 +- browser/base/content/certerror/aboutNetError.xhtml | 1 + browser/base/content/tab-content.js | 6 + browser/components/moz.build | 1 + .../content/authNotificationIcon.inc.xhtml | 6 + .../onionservices/content/authPopup.inc.xhtml | 16 ++ .../onionservices/content/authPreferences.css | 20 ++ .../content/authPreferences.inc.xhtml | 19 ++ .../onionservices/content/authPreferences.js | 66 +++++ .../components/onionservices/content/authPrompt.js | 316 +++++++++++++++++++++ .../components/onionservices/content/authUtil.jsm | 47 +++ .../onionservices/content/netError/browser.svg | 3 + .../onionservices/content/netError/network.svg | 3 + .../content/netError/onionNetError.css | 65 +++++ .../content/netError/onionNetError.js | 244 ++++++++++++++++ .../onionservices/content/netError/onionsite.svg | 7 + .../onionservices/content/onionservices.css | 69 +++++ .../onionservices/content/savedKeysDialog.js | 259 +++++++++++++++++ .../onionservices/content/savedKeysDialog.xhtml | 42 +++ browser/components/onionservices/jar.mn | 9 + browser/components/onionservices/moz.build | 1 + browser/components/preferences/preferences.xhtml | 1 + browser/components/preferences/privacy.inc.xhtml | 2 + browser/components/preferences/privacy.js | 7 + browser/themes/shared/notification-icons.inc.css | 3 + docshell/base/nsDocShell.cpp | 81 +++++- dom/ipc/BrowserParent.cpp | 21 ++ dom/ipc/BrowserParent.h | 3 + dom/ipc/PBrowser.ipdl | 9 + js/xpconnect/src/xpc.msg | 10 + netwerk/base/nsSocketTransport2.cpp | 6 + netwerk/socket/nsSOCKSIOLayer.cpp | 49 ++++ toolkit/modules/PopupNotifications.jsm | 6 + toolkit/modules/RemotePageAccessManager.jsm | 1 + .../lib/environments/frame-script.js | 1 + xpcom/base/ErrorList.py | 22 ++ 39 files changed, 1450 insertions(+), 2 deletions(-) diff --git a/browser/actors/NetErrorChild.jsm b/browser/actors/NetErrorChild.jsm index 82978412fe24..164fb7c95cd1 100644 --- a/browser/actors/NetErrorChild.jsm +++ b/browser/actors/NetErrorChild.jsm @@ -13,6 +13,8 @@ const { RemotePageChild } = ChromeUtils.import( "resource://gre/actors/RemotePageChild.jsm" ); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); + XPCOMUtils.defineLazyServiceGetter( this, "gSerializationHelper", @@ -33,6 +35,7 @@ class NetErrorChild extends RemotePageChild { "RPMAddToHistogram", "RPMRecordTelemetryEvent", "RPMGetHttpResponseHeader", + "RPMGetTorStrings", ]; this.exportFunctions(exportableFunctions); } @@ -115,4 +118,8 @@ class NetErrorChild extends RemotePageChild { return ""; } + + RPMGetTorStrings() { + return Cu.cloneInto(TorStrings.onionServices, this.contentWindow); + } } diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 32a35dd3dddc..501519db864e 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -230,6 +230,11 @@ XPCOMUtils.defineLazyScriptGetter( ["SecurityLevelButton"], "chrome://browser/content/securitylevel/securityLevel.js" ); +XPCOMUtils.defineLazyScriptGetter( + this, + ["OnionAuthPrompt"], + "chrome://browser/content/onionservices/authPrompt.js" +); XPCOMUtils.defineLazyScriptGetter( this, "gEditItemOverlay", @@ -1804,6 +1809,9 @@ var gBrowserInit = { // Init the SecuritySettingsButton SecurityLevelButton.init(); + // Init the OnionAuthPrompt + OnionAuthPrompt.init(); + // Certain kinds of automigration rely on this notification to complete // their tasks BEFORE the browser window is shown. SessionStore uses it to // restore tabs into windows AFTER important parts like gMultiProcessBrowser @@ -2530,6 +2538,8 @@ var gBrowserInit = { SecurityLevelButton.uninit(); + OnionAuthPrompt.uninit(); + gAccessibilityServiceIndicator.uninit(); if (gToolbarKeyNavEnabled) { diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 6b4120b34b4b..e4f3363e2180 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -33,6 +33,7 @@ <?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css" type="text/css"?> <?xml-stylesheet href="chrome://torbutton/skin/tor-circuit-display.css" type="text/css"?> <?xml-stylesheet href="chrome://torbutton/skin/torbutton.css" type="text/css"?> +<?xml-stylesheet href="chrome://browser/content/onionservices/onionservices.css" type="text/css"?> # All DTD information is stored in a separate file so that it can be shared by # hiddenWindowMac.xhtml. @@ -654,6 +655,7 @@ #include ../../components/downloads/content/downloadsPanel.inc.xhtml #include ../../../devtools/startup/enableDevToolsPopup.inc.xhtml #include ../../components/securitylevel/content/securityLevelPanel.inc.xhtml +#include ../../components/onionservices/content/authPopup.inc.xhtml #include browser-allTabsMenu.inc.xhtml <tooltip id="dynamic-shortcut-tooltip" @@ -1947,6 +1949,7 @@ data-l10n-id="urlbar-indexed-db-notification-anchor"/> <image id="password-notification-icon" class="notification-anchor-icon login-icon" role="button" data-l10n-id="urlbar-password-notification-anchor"/> +#include ../../components/onionservices/content/authNotificationIcon.inc.xhtml <stack id="plugins-notification-icon" class="notification-anchor-icon" role="button" align="center" data-l10n-id="urlbar-plugins-notification-anchor"> <image class="plugin-icon" /> <image id="plugin-icon-badge" /> diff --git a/browser/base/content/certerror/aboutNetError.js b/browser/base/content/certerror/aboutNetError.js index 31c4838a053d..e5b223025a8b 100644 --- a/browser/base/content/certerror/aboutNetError.js +++ b/browser/base/content/certerror/aboutNetError.js @@ -3,6 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ /* eslint-env mozilla/frame-script */ +/* import-globals-from ../../components/onionservices/content/netError/onionNetError.js */ import "chrome://global/content/certviewer/pvutils_bundle.js"; import "chrome://global/content/certviewer/asn1js_bundle.js"; @@ -307,7 +308,10 @@ function initPage() { errDesc = document.getElementById("ed_generic"); } - setErrorPageStrings(err); + const isOnionError = err.startsWith("onionServices."); + if (!isOnionError) { + setErrorPageStrings(err); + } var sd = document.getElementById("errorShortDescText"); if (sd) { @@ -459,6 +463,10 @@ function initPage() { span.textContent = HOST_NAME; } } + + if (isOnionError) { + OnionServicesAboutNetError.initPage(document); + } } function setupBlockingReportingUI() { diff --git a/browser/base/content/certerror/aboutNetError.xhtml b/browser/base/content/certerror/aboutNetError.xhtml index c645a2f2cc77..bf9a8fd58347 100644 --- a/browser/base/content/certerror/aboutNetError.xhtml +++ b/browser/base/content/certerror/aboutNetError.xhtml @@ -209,5 +209,6 @@ </div> </body> <script src="chrome://browser/content/certerror/aboutNetErrorCodes.js"/> + <script src="chrome://browser/content/onionservices/netError/onionNetError.js"/> <script type="module" src="chrome://browser/content/certerror/aboutNetError.js"/> </html> diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js index 83e55cf5ed87..96360a4307d2 100644 --- a/browser/base/content/tab-content.js +++ b/browser/base/content/tab-content.js @@ -7,4 +7,10 @@ var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +var { OnionAuthUtil } = ChromeUtils.import( + "chrome://browser/content/onionservices/authUtil.jsm" +); + Services.obs.notifyObservers(this, "tab-content-frameloader-created"); + +OnionAuthUtil.addCancelMessageListener(this, docShell); diff --git a/browser/components/moz.build b/browser/components/moz.build index e99fa19d896a..277d9ba42f3b 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -39,6 +39,7 @@ DIRS += [ "fxmonitor", "migration", "newtab", + "onionservices", "originattributes", "ion", "places", diff --git a/browser/components/onionservices/content/authNotificationIcon.inc.xhtml b/browser/components/onionservices/content/authNotificationIcon.inc.xhtml new file mode 100644 index 000000000000..91274d612739 --- /dev/null +++ b/browser/components/onionservices/content/authNotificationIcon.inc.xhtml @@ -0,0 +1,6 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<image id="tor-clientauth-notification-icon" + class="notification-anchor-icon tor-clientauth-icon" + role="button" + tooltiptext="&torbutton.onionServices.authPrompt.tooltip;"/> diff --git a/browser/components/onionservices/content/authPopup.inc.xhtml b/browser/components/onionservices/content/authPopup.inc.xhtml new file mode 100644 index 000000000000..bd0ec3aa0b00 --- /dev/null +++ b/browser/components/onionservices/content/authPopup.inc.xhtml @@ -0,0 +1,16 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<popupnotification id="tor-clientauth-notification" hidden="true"> + <popupnotificationcontent orient="vertical"> + <description id="tor-clientauth-notification-desc"/> + <label id="tor-clientauth-notification-learnmore" + class="text-link popup-notification-learnmore-link" + is="text-link"/> + <html:div> + <html:input id="tor-clientauth-notification-key" type="password"/> + <html:div id="tor-clientauth-warning"/> + <checkbox id="tor-clientauth-persistkey-checkbox" + label="&torbutton.onionServices.authPrompt.persistCheckboxLabel;"/> + </html:div> + </popupnotificationcontent> +</popupnotification> diff --git a/browser/components/onionservices/content/authPreferences.css b/browser/components/onionservices/content/authPreferences.css new file mode 100644 index 000000000000..b3fb79b26ddc --- /dev/null +++ b/browser/components/onionservices/content/authPreferences.css @@ -0,0 +1,20 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +#torOnionServiceKeys-overview-container { + margin-right: 30px; +} + +#onionservices-savedkeys-tree treechildren::-moz-tree-cell-text { + font-size: 80%; +} + +#onionservices-savedkeys-errorContainer { + margin-top: 4px; + min-height: 3em; +} + +#onionservices-savedkeys-errorIcon { + margin-right: 4px; + list-style-image: url("chrome://browser/skin/warning.svg"); + visibility: hidden; +} diff --git a/browser/components/onionservices/content/authPreferences.inc.xhtml b/browser/components/onionservices/content/authPreferences.inc.xhtml new file mode 100644 index 000000000000..f69c9dde66a2 --- /dev/null +++ b/browser/components/onionservices/content/authPreferences.inc.xhtml @@ -0,0 +1,19 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<groupbox id="torOnionServiceKeys" orient="vertical" + data-category="panePrivacy" hidden="true"> + <label><html:h2 id="torOnionServiceKeys-header"/></label> + <hbox> + <description id="torOnionServiceKeys-overview-container" flex="1"> + <html:span id="torOnionServiceKeys-overview" + class="tail-with-learn-more"/> + <label id="torOnionServiceKeys-learnMore" class="learnMore text-link" + is="text-link"/> + </description> + <vbox align="end"> + <button id="torOnionServiceKeys-savedKeys" + is="highlightable-button" + class="accessory-button"/> + </vbox> + </hbox> +</groupbox> diff --git a/browser/components/onionservices/content/authPreferences.js b/browser/components/onionservices/content/authPreferences.js new file mode 100644 index 000000000000..52f8272020cc --- /dev/null +++ b/browser/components/onionservices/content/authPreferences.js @@ -0,0 +1,66 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +ChromeUtils.defineModuleGetter( + this, + "TorStrings", + "resource:///modules/TorStrings.jsm" +); + +/* + Onion Services Client Authentication Preferences Code + + Code to handle init and update of onion services authentication section + in about:preferences#privacy +*/ + +const OnionServicesAuthPreferences = { + selector: { + groupBox: "#torOnionServiceKeys", + header: "#torOnionServiceKeys-header", + overview: "#torOnionServiceKeys-overview", + learnMore: "#torOnionServiceKeys-learnMore", + savedKeysButton: "#torOnionServiceKeys-savedKeys", + }, + + init() { + // populate XUL with localized strings + this._populateXUL(); + }, + + _populateXUL() { + const groupbox = document.querySelector(this.selector.groupBox); + + let elem = groupbox.querySelector(this.selector.header); + elem.textContent = TorStrings.onionServices.authPreferences.header; + + elem = groupbox.querySelector(this.selector.overview); + elem.textContent = TorStrings.onionServices.authPreferences.overview; + + elem = groupbox.querySelector(this.selector.learnMore); + elem.setAttribute("value", TorStrings.onionServices.learnMore); + elem.setAttribute("href", TorStrings.onionServices.learnMoreURL); + + elem = groupbox.querySelector(this.selector.savedKeysButton); + elem.setAttribute( + "label", + TorStrings.onionServices.authPreferences.savedKeys + ); + elem.addEventListener("command", () => + OnionServicesAuthPreferences.onViewSavedKeys() + ); + }, + + onViewSavedKeys() { + gSubDialog.open( + "chrome://browser/content/onionservices/savedKeysDialog.xhtml" + ); + }, +}; // OnionServicesAuthPreferences + +Object.defineProperty(this, "OnionServicesAuthPreferences", { + value: OnionServicesAuthPreferences, + enumerable: true, + writable: false, +}); diff --git a/browser/components/onionservices/content/authPrompt.js b/browser/components/onionservices/content/authPrompt.js new file mode 100644 index 000000000000..d4a59ac46487 --- /dev/null +++ b/browser/components/onionservices/content/authPrompt.js @@ -0,0 +1,316 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +XPCOMUtils.defineLazyModuleGetters(this, { + OnionAuthUtil: "chrome://browser/content/onionservices/authUtil.jsm", + CommonUtils: "resource://services-common/utils.js", + TorStrings: "resource:///modules/TorStrings.jsm", +}); + +const OnionAuthPrompt = (function() { + // 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. + function OnionServicesAuthPrompt(aBrowser, aFailedURI, aReason, aOnionName) { + this._browser = aBrowser; + this._failedURI = aFailedURI; + this._reasonForPrompt = aReason; + this._onionName = aOnionName; + } + + OnionServicesAuthPrompt.prototype = { + show(aWarningMessage) { + let mainAction = { + label: TorStrings.onionServices.authPrompt.done, + accessKey: TorStrings.onionServices.authPrompt.doneAccessKey, + leaveOpen: true, // Callback is responsible for closing the notification. + callback: this._onDone.bind(this), + }; + + let dialogBundle = Services.strings.createBundle( + "chrome://global/locale/dialog.properties"); + + let cancelAccessKey = dialogBundle.GetStringFromName("accesskey-cancel"); + if (!cancelAccessKey) + cancelAccessKey = "c"; // required by PopupNotifications.show() + + let cancelAction = { + label: dialogBundle.GetStringFromName("button-cancel"), + accessKey: cancelAccessKey, + callback: this._onCancel.bind(this), + }; + + let _this = this; + let options = { + autofocus: true, + hideClose: true, + persistent: true, + removeOnDismissal: false, + eventCallback(aTopic) { + if (aTopic === "showing") { + _this._onPromptShowing(aWarningMessage); + } else if (aTopic === "shown") { + _this._onPromptShown(); + } else if (aTopic === "removed") { + _this._onPromptRemoved(); + } + } + }; + + this._prompt = PopupNotifications.show(this._browser, + OnionAuthUtil.domid.notification, "", + OnionAuthUtil.domid.anchor, + mainAction, [cancelAction], options); + }, + + _onPromptShowing(aWarningMessage) { + let xulDoc = this._browser.ownerDocument; + let descElem = xulDoc.getElementById(OnionAuthUtil.domid.description); + 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.removeChild(descElem.firstChild); + + 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 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._onionName; + descElem.appendChild(span); + span = xulDoc.createElementNS(kHTMLNS, "span"); + span.textContent = suffix; + descElem.appendChild(span); + } + + // Set "Learn More" label and href. + let learnMoreElem = xulDoc.getElementById(OnionAuthUtil.domid.learnMore); + if (learnMoreElem) { + learnMoreElem.setAttribute("value", TorStrings.onionServices.learnMore); + learnMoreElem.setAttribute("href", TorStrings.onionServices.learnMoreURL); + } + + this._showWarning(aWarningMessage); + let checkboxElem = this._getCheckboxElement(); + if (checkboxElem) { + checkboxElem.checked = false; + } + }, + + _onPromptShown() { + let keyElem = this._getKeyElement(); + if (keyElem) { + keyElem.setAttribute("placeholder", + TorStrings.onionServices.authPrompt.keyPlaceholder); + this._boundOnKeyFieldKeyPress = this._onKeyFieldKeyPress.bind(this); + this._boundOnKeyFieldInput = this._onKeyFieldInput.bind(this); + keyElem.addEventListener("keypress", this._boundOnKeyFieldKeyPress); + keyElem.addEventListener("input", this._boundOnKeyFieldInput); + keyElem.focus(); + } + }, + + _onPromptRemoved() { + if (this._boundOnKeyFieldKeyPress) { + let keyElem = this._getKeyElement(); + if (keyElem) { + keyElem.value = ""; + keyElem.removeEventListener("keypress", + this._boundOnKeyFieldKeyPress); + this._boundOnKeyFieldKeyPress = undefined; + keyElem.removeEventListener("input", this._boundOnKeyFieldInput); + this._boundOnKeyFieldInput = undefined; + } + } + }, + + _onKeyFieldKeyPress(aEvent) { + if (aEvent.keyCode == aEvent.DOM_VK_RETURN) { + this._onDone(); + } else if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { + this._prompt.remove(); + this._onCancel(); + } + }, + + _onKeyFieldInput(aEvent) { + this._showWarning(undefined); // Remove the warning. + }, + + _onDone() { + let keyElem = this._getKeyElement(); + if (!keyElem) + return; + + let base64key = this._keyToBase64(keyElem.value); + if (!base64key) { + this._showWarning(TorStrings.onionServices.authPrompt.invalidKey); + return; + } + + this._prompt.remove(); + + // Use Torbutton's controller module to add the private key to Tor. + let controllerFailureMsg = + TorStrings.onionServices.authPrompt.failedToSetKey; + try { + let { controller } = + Cu.import("resource://torbutton/modules/tor-control-port.js", {}); + let torController = controller(aError => { + this.show(controllerFailureMsg); + }); + let onionAddr = this._onionName.toLowerCase().replace(/\.onion$/, ""); + let checkboxElem = this._getCheckboxElement(); + let isPermanent = (checkboxElem && checkboxElem.checked); + torController.onionAuthAdd(onionAddr, base64key, isPermanent) + .then(aResponse => { + // Success! Reload the page. + this._browser.sendMessageToActor( + "Browser:Reload", + {}, + "BrowserTab" + ); + }) + .catch(aError => { + if (aError.torMessage) + this.show(aError.torMessage); + else + this.show(controllerFailureMsg); + }); + } catch (e) { + this.show(controllerFailureMsg); + } + }, + + _onCancel() { + // Arrange for an error page to be displayed. + this._browser.messageManager.sendAsyncMessage( + OnionAuthUtil.message.authPromptCanceled, + {failedURI: this._failedURI.spec, + reasonForPrompt: this._reasonForPrompt}); + }, + + _getKeyElement() { + let xulDoc = this._browser.ownerDocument; + return xulDoc.getElementById(OnionAuthUtil.domid.keyElement); + }, + + _getCheckboxElement() { + let xulDoc = this._browser.ownerDocument; + return xulDoc.getElementById(OnionAuthUtil.domid.checkboxElement); + }, + + _showWarning(aWarningMessage) { + let xulDoc = this._browser.ownerDocument; + let warningElem = + xulDoc.getElementById(OnionAuthUtil.domid.warningElement); + let keyElem = this._getKeyElement(); + if (warningElem) { + if (aWarningMessage) { + warningElem.textContent = aWarningMessage; + warningElem.removeAttribute("hidden"); + if (keyElem) + keyElem.className = "invalid"; + } else { + warningElem.setAttribute("hidden", "true"); + if (keyElem) + keyElem.className = ""; + } + } + }, + + // Returns undefined if the key is the wrong length or format. + _keyToBase64(aKeyString) { + if (!aKeyString) + return undefined; + + let base64key; + if (aKeyString.length == 52) { + // The key is probably base32-encoded. Attempt to decode. + // Although base32 specifies uppercase letters, we accept lowercase + // as well because users may type in lowercase or copy a key out of + // a tor onion-auth file (which uses lowercase). + let rawKey; + try { + rawKey = CommonUtils.decodeBase32(aKeyString.toUpperCase()); + } catch (e) {} + + if (rawKey) try { + base64key = btoa(rawKey); + } catch (e) {} + } else if ((aKeyString.length == 44) && + /^[a-zA-Z0-9+/]*=*$/.test(aKeyString)) { + // The key appears to be a correctly formatted base64 value. If not, + // tor will return an error when we try to add the key via the + // control port. + base64key = aKeyString; + } + + return base64key; + }, + }; + + let retval = { + init() { + Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthMissing); + Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthIncorrect); + }, + + uninit() { + Services.obs.removeObserver(this, OnionAuthUtil.topic.clientAuthMissing); + Services.obs.removeObserver(this, OnionAuthUtil.topic.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)) { + return; + } + + let browser; + if (aSubject instanceof Ci.nsIDOMWindow) { + let contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow); + browser = contentWindow.docShell.chromeEventHandler; + } else { + browser = aSubject.QueryInterface(Ci.nsIBrowser); + } + + if (!gBrowser.browsers.some(aBrowser => aBrowser == browser)) { + return; // This window does not contain the subject browser; ignore. + } + + let failedURI = browser.currentURI; + let authPrompt = new OnionServicesAuthPrompt(browser, failedURI, + aTopic, aData); + authPrompt.show(undefined); + } + }; + + return retval; +})(); /* OnionAuthPrompt */ + + +Object.defineProperty(this, "OnionAuthPrompt", { + value: OnionAuthPrompt, + enumerable: true, + writable: false +}); diff --git a/browser/components/onionservices/content/authUtil.jsm b/browser/components/onionservices/content/authUtil.jsm new file mode 100644 index 000000000000..c9d83774da1f --- /dev/null +++ b/browser/components/onionservices/content/authUtil.jsm @@ -0,0 +1,47 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +var EXPORTED_SYMBOLS = [ + "OnionAuthUtil", +]; + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +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", + }, + + addCancelMessageListener(aTabContent, aDocShell) { + aTabContent.addMessageListener(this.message.authPromptCanceled, + (aMessage) => { + // Upon cancellation of the client authentication prompt, display + // the appropriate error page. When calling the docShell + // displayLoadError() function, we pass undefined for the failed + // channel so that displayLoadError() can determine that it should + // not display the client authentication prompt a second time. + let failedURI = Services.io.newURI(aMessage.data.failedURI); + let reasonForPrompt = aMessage.data.reasonForPrompt; + let errorCode = + (reasonForPrompt === this.topic.clientAuthMissing) ? + Cr.NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH : + Cr.NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH; + aDocShell.displayLoadError(errorCode, failedURI, undefined, undefined); + }); + }, +}; diff --git a/browser/components/onionservices/content/netError/browser.svg b/browser/components/onionservices/content/netError/browser.svg new file mode 100644 index 000000000000..b4c433b37bbb --- /dev/null +++ b/browser/components/onionservices/content/netError/browser.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="72" height="65" viewBox="0 0 72 65"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M0.0 0.0C0.0 0.0 0.0 65.0 0.0 65.0C0.0 65.0 72.0 65.0 72.0 65.0C72.0 65.0 72.0 0.0 72.0 0.0C72.0 0.0 52.9019692 0.0 52.9019692 0.0C52.9019692 0.0 0.0 0.0 0.0 0.0C0.0 0.0 0.0 0.0 0.0 0.0M65.0 58.0C65.0 58.0 6.0 58.0 6.0 58.0C6.0 58.0 6.0 25.0 6.0 25.0C6.0 25.0 65.0 25.0 65.0 25.0C65.0 25.0 65.0 58.0 65.0 58.0C65.0 58.0 65.0 58.0 65.0 58.0M6.0 10.0C6.0 10.0 10.0 10.0 10.0 10.0C10.0 10.0 10.0 14.0 10.0 14.0C10.0 14.0 6.0 14.0 6.0 14.0C6.0 14.0 6.0 10.0 6.0 10.0C6.0 10.0 6.0 10.0 6.0 10.0M14.0 10.0C14.0 10.0 18.0 10.0 18.0 10.0C18.0 10.0 18.0 14.0 18.0 14.0C18.0 14.0 14.0 14.0 14.0 14.0C14.0 14.0 14.0 10.0 14.0 10.0C14.0 10.0 14.0 10.0 14.0 10.0M22.0 10.0C22.0 10.0 26.0 10.0 26.0 10.0C26.0 10.0 26.0 14.0 26.0 14.0C26.0 14.0 22.0 14.0 22.0 14.0C22.0 14.0 22.0 10.0 22.0 10.0C22.0 10.0 22.0 10.0 22.0 10.0" /> +</svg> diff --git a/browser/components/onionservices/content/netError/network.svg b/browser/components/onionservices/content/netError/network.svg new file mode 100644 index 000000000000..808c53dedd09 --- /dev/null +++ b/browser/components/onionservices/content/netError/network.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="72" height="54" viewBox="0 0 72 54"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.0487805 54.0C6.28990244 54.0 0.0 47.3306322 0.0 39.1034585C0.0 32.0105634 4.68716488 26.0867675 10.9481707 24.585103C10.6902 23.574652 10.5365854 22.5107596 10.5365854 21.4138156C10.5365854 14.7292347 15.6471278 9.3103384 21.9512195 9.3103384C24.8076351 9.3103384 27.4126741 10.4393194 29.4146341 12.2780088C32.1344254 5.0777841 38.77452 0.0 46.5365854 0.0C56.7201249 0.0 64.9756098 8.7536733 64.9756098 19.5517479C64.9756098 20.7691677 64.8471688 21.9453428 64.6463415 23.1013144C69.0576849 26.0679606 72.0 31.2693674 72.0 37.2413909C72.0 46.5256603 64.9510244 54.0 56.195122 54.0C56.195122 54.0 14.0487805 54.0 14.0487805 54.0C14.0487805 54.0 14.0487805 54.0 14.0487805 54.0" /> +</svg> diff --git a/browser/components/onionservices/content/netError/onionNetError.css b/browser/components/onionservices/content/netError/onionNetError.css new file mode 100644 index 000000000000..58117ab93223 --- /dev/null +++ b/browser/components/onionservices/content/netError/onionNetError.css @@ -0,0 +1,65 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +:root { + --grey-70: #38383d; +} + +#onionErrorDiagramContainer { + margin: 60px auto; + width: 460px; /* 3 columns @ 140px plus 2 column gaps @ 20px */ + display: grid; + grid-row-gap: 15px; + grid-column-gap: 20px; + grid-template-columns: 1fr 1fr 1fr; +} + +#onionErrorDiagramContainer > div { + margin: auto; + position: relative; /* needed to allow overlay of the ok or error icon */ +} + +.onionErrorImage { + width: 72px; + height: 72px; + background-position: center; + background-repeat: no-repeat; + -moz-context-properties: fill; + fill: var(--grey-70); +} + +#onionErrorBrowserImage { + background-image: url("browser.svg"); +} + +#onionErrorNetworkImage { + background-image: url("network.svg"); +} + +#onionErrorOnionSiteImage { + background-image: url("onionsite.svg"); +} + +/* rules to support overlay of the ok or error icon */ +.onionErrorImage[status]::after { + content: " "; + position: absolute; + left: -18px; + top: 18px; + width: 36px; + height: 36px; + -moz-context-properties: fill; + fill: var(--in-content-page-background); + background-color: var(--grey-70); + background-repeat: no-repeat; + background-position: center; + border: 3px solid var(--in-content-page-background); + border-radius: 50%; +} + +.onionErrorImage[status="ok"]::after { + background-image: url("chrome://global/skin/icons/check.svg"); +} + +.onionErrorImage[status="error"]::after { + background-image: url("chrome://browser/skin/stop.svg"); +} diff --git a/browser/components/onionservices/content/netError/onionNetError.js b/browser/components/onionservices/content/netError/onionNetError.js new file mode 100644 index 000000000000..8fabb3f38eb7 --- /dev/null +++ b/browser/components/onionservices/content/netError/onionNetError.js @@ -0,0 +1,244 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +/* eslint-env mozilla/frame-script */ + +var OnionServicesAboutNetError = { + _selector: { + header: ".title-text", + longDesc: "#errorLongDesc", + learnMoreContainer: "#learnMoreContainer", + learnMoreLink: "#learnMoreLink", + contentContainer: "#errorLongContent", + tryAgainButtonContainer: "#netErrorButtonContainer", + }, + _status: { + ok: "ok", + error: "error", + }, + + _diagramInfoMap: undefined, + + // Public functions (called from outside this file). + // + // This initPage() function may need to be updated if the structure of + // browser/base/content/aboutNetError.xhtml changes. Specifically, it + // references the following elements: + // query string parameter e + // class title-text + // id errorLongDesc + // id learnMoreContainer + // id learnMoreLink + // id errorLongContent + initPage(aDoc) { + const searchParams = new URLSearchParams(aDoc.documentURI.split("?")[1]); + const err = searchParams.get("e"); + + const errPrefix = "onionServices."; + const errName = err.substring(errPrefix.length); + + this._strings = RPMGetTorStrings(); + + const stringsObj = this._strings[errName]; + if (!stringsObj) { + return; + } + + this._insertStylesheet(aDoc); + + const pageTitle = stringsObj.pageTitle; + const header = stringsObj.header; + const longDescription = stringsObj.longDescription; // optional + const learnMoreURL = stringsObj.learnMoreURL; + + if (pageTitle) { + aDoc.title = pageTitle; + } + + if (header) { + const headerElem = aDoc.querySelector(this._selector.header); + if (headerElem) { + headerElem.textContent = header; + } + } + + const ld = aDoc.querySelector(this._selector.longDesc); + if (ld) { + if (longDescription) { + const hexErr = this._hexErrorFromName(errName); + ld.textContent = longDescription.replace("%S", hexErr); + } else { + // This onion service error does not have a long description. Since + // it is set to a generic error string by the code in + // browser/base/content/aboutNetError.js, hide it here. + ld.style.display = "none"; + } + } + + if (learnMoreURL) { + const lmContainer = aDoc.querySelector(this._selector.learnMoreContainer); + if (lmContainer) { + lmContainer.style.display = "block"; + } + const lmLink = lmContainer.querySelector(this._selector.learnMoreLink); + if (lmLink) { + lmLink.setAttribute("href", learnMoreURL); + } + } + + // Remove the "Try Again" button if the user made a typo in the .onion + // address since it is not useful in that case. + if (errName === "badAddress") { + const tryAgainButton = aDoc.querySelector( + this._selector.tryAgainButtonContainer + ); + if (tryAgainButton) { + tryAgainButton.style.display = "none"; + } + } + + this._insertDiagram(aDoc, errName); + }, // initPage() + + _insertStylesheet(aDoc) { + const url = + "chrome://browser/content/onionservices/netError/onionNetError.css"; + let linkElem = aDoc.createElement("link"); + linkElem.rel = "stylesheet"; + linkElem.href = url; + linkElem.type = "text/css"; + aDoc.head.appendChild(linkElem); + }, + + _insertDiagram(aDoc, aErrorName) { + // The onion error diagram consists of a grid of div elements. + // The first row contains three images (Browser, Network, Onionsite) and + // the second row contains labels for the images that are in the first row. + // The _diagramInfoMap describes for each type of onion service error + // whether a small ok or error status icon is overlaid on top of the main + // Browser/Network/Onionsite images. + if (!this._diagramInfoMap) { + this._diagramInfoMap = new Map(); + this._diagramInfoMap.set("descNotFound", { + browser: this._status.ok, + network: this._status.ok, + onionSite: this._status.error, + }); + this._diagramInfoMap.set("descInvalid", { + browser: this._status.ok, + network: this._status.error, + }); + this._diagramInfoMap.set("introFailed", { + browser: this._status.ok, + network: this._status.error, + }); + this._diagramInfoMap.set("rendezvousFailed", { + browser: this._status.ok, + network: this._status.error, + }); + this._diagramInfoMap.set("clientAuthMissing", { + browser: this._status.error, + }); + this._diagramInfoMap.set("clientAuthIncorrect", { + browser: this._status.error, + }); + this._diagramInfoMap.set("badAddress", { + browser: this._status.error, + }); + this._diagramInfoMap.set("introTimedOut", { + browser: this._status.ok, + network: this._status.error, + }); + } + + const diagramInfo = this._diagramInfoMap.get(aErrorName); + + const container = this._createDiv(aDoc, "onionErrorDiagramContainer"); + const imageClass = "onionErrorImage"; + + const browserImage = this._createDiv( + aDoc, + "onionErrorBrowserImage", + imageClass, + container + ); + if (diagramInfo && diagramInfo.browser) { + browserImage.setAttribute("status", diagramInfo.browser); + } + + const networkImage = this._createDiv( + aDoc, + "onionErrorNetworkImage", + imageClass, + container + ); + if (diagramInfo && diagramInfo.network) { + networkImage.setAttribute("status", diagramInfo.network); + } + + const onionSiteImage = this._createDiv( + aDoc, + "onionErrorOnionSiteImage", + imageClass, + container + ); + if (diagramInfo && diagramInfo.onionSite) { + onionSiteImage.setAttribute("status", diagramInfo.onionSite); + } + + let labelDiv = this._createDiv(aDoc, undefined, undefined, container); + labelDiv.textContent = this._strings.errorPage.browser; + labelDiv = this._createDiv(aDoc, undefined, undefined, container); + labelDiv.textContent = this._strings.errorPage.network; + labelDiv = this._createDiv(aDoc, undefined, undefined, container); + labelDiv.textContent = this._strings.errorPage.onionSite; + + const contentContainer = aDoc.querySelector( + this._selector.contentContainer + ); + if (contentContainer) { + contentContainer.insertBefore(container, contentContainer.firstChild); + } + }, // _insertDiagram() + + _createDiv(aDoc, aID, aClass, aParentElem) { + const div = aDoc.createElement("div"); + if (aID) { + div.id = aID; + } + if (aClass) { + div.setAttribute("class", aClass); + } + if (aParentElem) { + aParentElem.appendChild(div); + } + + return div; + }, + + _hexErrorFromName(aErrorName) { + // We do not have access to the original Tor SOCKS error code here, so + // perform a reverse mapping from the error name. + switch (aErrorName) { + case "descNotFound": + return "0xF0"; + case "descInvalid": + return "0xF1"; + case "introFailed": + return "0xF2"; + case "rendezvousFailed": + return "0xF3"; + case "clientAuthMissing": + return "0xF4"; + case "clientAuthIncorrect": + return "0xF5"; + case "badAddress": + return "0xF6"; + case "introTimedOut": + return "0xF7"; + } + + return ""; + }, +}; diff --git a/browser/components/onionservices/content/netError/onionsite.svg b/browser/components/onionservices/content/netError/onionsite.svg new file mode 100644 index 000000000000..1f2777e6acc7 --- /dev/null +++ b/browser/components/onionservices/content/netError/onionsite.svg @@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="70" height="63" viewBox="0 0 70 63"> + <g fill="context-fill" fill-opacity="context-fill-opacity"> + <path d="M64.0 2.0C64.0 2.0 4.0 2.0 4.0 2.0C2.8954305 2.0 2.0 2.81148389 2.0 3.8125C2.0 3.8125 2.0 58.1875 2.0 58.1875C2.0 59.1885161 2.8954305 60.0 4.0 60.0C4.0 60.0 36.0 60.0 36.0 60.0C36.0 60.0 36.0 56.375 36.0 56.375C36.0 56.375 6.0 56.375 6.0 56.375C6.0 56.375 6.0 41.875 6.0 41.875C6.0 41.875 38.0 41.875 38.0 41.875C38.0 41.875 38.0 38.25 38.0 38.25C38.0 38.25 6.0 38.25 6.0 38.25C6.0 38.25 6.0 23.75 6.0 23.75C6.0 23.75 62.0 23.75 62.0 23.75C62.0 23.75 62.0 36.4375 62.0 36.4375C62.0 36.4375 66.0 36.4375 66.0 36.4375C66.0 36.4375 66.0 3.8125 66.0 3.8125C66.0 2.81148389 65.1045695 2.0 64.0 2.0C64.0 2.0 64.0 2.0 64.0 2.0M62.0 20.125C62.0 20.125 6.0 20.125 6.0 20.125C6.0 20.125 6.0 5.625 6.0 5.625C6.0 5.625 62.0 5.625 62.0 5.625C62.0 5.625 62.0 20.125 62.0 20.125C62.0 20.125 62.0 20.125 62.0 20.125" /> + <path d="M24.0 47.0C24.0 47.0 24.0 51.0 24.0 51.0C24.0 51.0 20.0 51.0 20.0 51.0C20.0 51.0 20.0 47.0 20.0 47.0C20.0 47.0 24.0 47.0 24.0 47.0C24.0 47.0 24.0 47.0 24.0 47.0M16.0 47.0C16.0 47.0 16.0 51.0 16.0 51.0C16.0 51.0 12.0 51.0 12.0 51.0C12.0 51.0 12.0 47.0 12.0 47.0C12.0 47.0 16.0 47.0 16.0 47.0C16.0 47.0 16.0 47.0 16.0 47.0M56.0 29.0C56.0 29.0 56.0 33.0 56.0 33.0C56.0 33.0 52.0 33.0 52.0 33.0C52.0 33.0 52.0 29.0 52.0 29.0C52.0 29.0 56.0 29.0 56.0 29.0C56.0 29.0 56.0 29.0 56.0 29.0M48.0 29.0C48.0 29.0 48.0 33.0 48.0 33.0C48.0 33.0 12.0 33.0 12.0 33.0C12.0 33.0 12.0 29.0 12.0 29.0C12.0 29.0 48.0 29.0 48.0 29.0C48.0 29.0 48.0 29.0 48.0 29.0M22.0 11.0C22.0 11.0 22.0 15.0 22.0 15.0C22.0 15.0 10.0 15.0 10.0 15.0C10.0 15.0 10.0 11.0 10.0 11.0C10.0 11.0 22.0 11.0 22.0 11.0C22.0 11.0 22.0 11.0 22.0 11.0M70.0 0.0C70.0 0.0 70.0 36.5 70.0 36.5C70.0 36.5 65.0 36.5 65.0 36.5C65.0 36.5 65.0 4.5 65.0 4.5C65.0 4.5 5.0 4.5 5.0 4.5C5.0 4.5 5.0 58.5 5.0 58.5C5.0 58.5 36.0 58.5 36.0 58.5C36.0 58 .5 36.0 63.0 36.0 63.0C36.0 63.0 0.0 63.0 0.0 63.0C0.0 63.0 0.0 0.0 0.0 0.0C0.0 0.0 70.0 0.0 70.0 0.0C70.0 0.0 70.0 0.0 70.0 0.0M32.0 47.0C32.0 47.0 32.0 51.0 32.0 51.0C32.0 51.0 28.0 51.0 28.0 51.0C28.0 51.0 28.0 47.0 28.0 47.0C28.0 47.0 32.0 47.0 32.0 47.0C32.0 47.0 32.0 47.0 32.0 47.0M54.0 11.0C54.0 11.0 54.0 15.0 54.0 15.0C54.0 15.0 50.0 15.0 50.0 15.0C50.0 15.0 50.0 11.0 50.0 11.0C50.0 11.0 54.0 11.0 54.0 11.0C54.0 11.0 54.0 11.0 54.0 11.0M46.0 11.0C46.0 11.0 46.0 15.0 46.0 15.0C46.0 15.0 42.0 15.0 42.0 15.0C42.0 15.0 42.0 11.0 42.0 11.0C42.0 11.0 46.0 11.0 46.0 11.0C46.0 11.0 46.0 11.0 46.0 11.0M38.0 11.0C38.0 11.0 38.0 15.0 38.0 15.0C38.0 15.0 34.0 15.0 34.0 15.0C34.0 15.0 34.0 11.0 34.0 11.0C34.0 11.0 38.0 11.0 38.0 11.0C38.0 11.0 38.0 11.0 38.0 11.0M30.0 11.0C30.0 11.0 30.0 15.0 30.0 15.0C30.0 15.0 26.0 15.0 26.0 15.0C26.0 15.0 26.0 11.0 26.0 11.0C26.0 11.0 30.0 11.0 30.0 11.0C30.0 11.0 30.0 11.0 30.0 11.0" /> + <path d="M61.0 46.0C61.0 46.0 59.0 46.0 59.0 46.0C59.0 46.0 59.0 40.0 59.0 40.0C59.0 38.8954305 58.1045695 38.0 57.0 38.0C57.0 38.0 49.0 38.0 49.0 38.0C47.8954305 38.0 47.0 38.8954305 47.0 40.0C47.0 40.0 47.0 46.0 47.0 46.0C47.0 46.0 45.0 46.0 45.0 46.0C43.8954305 46.0 43.0 46.8954305 43.0 48.0C43.0 48.0 43.0 60.0 43.0 60.0C43.0 61.1045695 43.8954305 62.0 45.0 62.0C45.0 62.0 61.0 62.0 61.0 62.0C62.1045695 62.0 63.0 61.1045695 63.0 60.0C63.0 60.0 63.0 48.0 63.0 48.0C63.0 46.8954305 62.1045695 46.0 61.0 46.0C61.0 46.0 61.0 46.0 61.0 46.0M51.0 42.0C51.0 42.0 55.0 42.0 55.0 42.0C55.0 42.0 55.0 46.0 55.0 46.0C55.0 46.0 51.0 46.0 51.0 46.0C51.0 46.0 51.0 42.0 51.0 42.0C51.0 42.0 51.0 42.0 51.0 42.0M59.0 58.0C59.0 58.0 47.0 58.0 47.0 58.0C47.0 58.0 47.0 50.0 47.0 50.0C47.0 50.0 59.0 50.0 59.0 50.0C59.0 50.0 59.0 58.0 59.0 58.0C59.0 58.0 59.0 58.0 59.0 58.0" /> + </g> +</svg> diff --git a/browser/components/onionservices/content/onionservices.css b/browser/components/onionservices/content/onionservices.css new file mode 100644 index 000000000000..e2621ec8266d --- /dev/null +++ b/browser/components/onionservices/content/onionservices.css @@ -0,0 +1,69 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +@namespace html url("http://www.w3.org/1999/xhtml"); + +html|*#tor-clientauth-notification-onionname { + font-weight: bold; +} + +html|*#tor-clientauth-notification-key { + box-sizing: border-box; + width: 100%; + margin-top: 15px; + padding: 6px; +} + +/* Start of rules adapted from + * browser/components/newtab/css/activity-stream-mac.css (linux and windows + * use the same rules). + */ +html|*#tor-clientauth-notification-key.invalid { + border: 1px solid #D70022; + box-shadow: 0 0 0 1px #D70022, 0 0 0 4px rgba(215, 0, 34, 0.3); +} + +html|*#tor-clientauth-warning { + display: inline-block; + animation: fade-up-tt 450ms; + background: #D70022; + border-radius: 2px; + color: #FFF; + inset-inline-start: 3px; + padding: 5px 12px; + position: relative; + top: 6px; + z-index: 1; +} + +html|*#tor-clientauth-warning[hidden] { + display: none; +} + +html|*#tor-clientauth-warning::before { + background: #D70022; + bottom: -8px; + content: '.'; + height: 16px; + inset-inline-start: 12px; + position: absolute; + text-indent: -999px; + top: -7px; + transform: rotate(45deg); + white-space: nowrap; + width: 16px; + z-index: -1; +} + +@keyframes fade-up-tt { + 0% { + opacity: 0; + transform: translateY(15px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} +/* End of rules adapted from + * browser/components/newtab/css/activity-stream-mac.css + */ diff --git a/browser/components/onionservices/content/savedKeysDialog.js b/browser/components/onionservices/content/savedKeysDialog.js new file mode 100644 index 000000000000..b1376bbabe85 --- /dev/null +++ b/browser/components/onionservices/content/savedKeysDialog.js @@ -0,0 +1,259 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +ChromeUtils.defineModuleGetter( + this, + "TorStrings", + "resource:///modules/TorStrings.jsm" +); + +ChromeUtils.defineModuleGetter( + this, + "controller", + "resource://torbutton/modules/tor-control-port.js" +); + +var gOnionServicesSavedKeysDialog = { + selector: { + dialog: "#onionservices-savedkeys-dialog", + intro: "#onionservices-savedkeys-intro", + tree: "#onionservices-savedkeys-tree", + onionSiteCol: "#onionservices-savedkeys-siteCol", + onionKeyCol: "#onionservices-savedkeys-keyCol", + errorIcon: "#onionservices-savedkeys-errorIcon", + errorMessage: "#onionservices-savedkeys-errorMessage", + removeButton: "#onionservices-savedkeys-remove", + removeAllButton: "#onionservices-savedkeys-removeall", + }, + + _tree: undefined, + _isBusy: false, // true when loading data, deleting a key, etc. + + // Public functions (called from outside this file). + async deleteSelectedKeys() { + this._setBusyState(true); + + const indexesToDelete = []; + const count = this._tree.view.selection.getRangeCount(); + for (let i = 0; i < count; ++i) { + const minObj = {}; + const maxObj = {}; + this._tree.view.selection.getRangeAt(i, minObj, maxObj); + for (let idx = minObj.value; idx <= maxObj.value; ++idx) { + indexesToDelete.push(idx); + } + } + + if (indexesToDelete.length > 0) { + const controllerFailureMsg = + TorStrings.onionServices.authPreferences.failedToRemoveKey; + try { + const torController = controller(aError => { + this._showError(controllerFailureMsg); + }); + + // Remove in reverse index order to avoid issues caused by index changes. + for (let i = indexesToDelete.length - 1; i >= 0; --i) { + await this._deleteOneKey(torController, indexesToDelete[i]); + } + } catch (e) { + if (e.torMessage) { + this._showError(e.torMessage); + } else { + this._showError(controllerFailureMsg); + } + } + } + + this._setBusyState(false); + }, + + async deleteAllKeys() { + this._tree.view.selection.selectAll(); + await this.deleteSelectedKeys(); + }, + + updateButtonsState() { + const haveSelection = this._tree.view.selection.getRangeCount() > 0; + const dialog = document.querySelector(this.selector.dialog); + const removeSelectedBtn = dialog.querySelector(this.selector.removeButton); + removeSelectedBtn.disabled = this._isBusy || !haveSelection; + const removeAllBtn = dialog.querySelector(this.selector.removeAllButton); + removeAllBtn.disabled = this._isBusy || this.rowCount === 0; + }, + + // Private functions. + _onLoad() { + document.mozSubdialogReady = this._init(); + }, + + async _init() { + await this._populateXUL(); + + window.addEventListener("keypress", this._onWindowKeyPress.bind(this)); + + // We don't use await here because we want _loadSavedKeys() to run + // in the background and not block loading of this dialog. + this._loadSavedKeys(); + }, + + async _populateXUL() { + const dialog = document.querySelector(this.selector.dialog); + const authPrefStrings = TorStrings.onionServices.authPreferences; + dialog.setAttribute("title", authPrefStrings.dialogTitle); + + let elem = dialog.querySelector(this.selector.intro); + elem.textContent = authPrefStrings.dialogIntro; + + elem = dialog.querySelector(this.selector.onionSiteCol); + elem.setAttribute("label", authPrefStrings.onionSite); + + elem = dialog.querySelector(this.selector.onionKeyCol); + elem.setAttribute("label", authPrefStrings.onionKey); + + elem = dialog.querySelector(this.selector.removeButton); + elem.setAttribute("label", authPrefStrings.remove); + + elem = dialog.querySelector(this.selector.removeAllButton); + elem.setAttribute("label", authPrefStrings.removeAll); + + this._tree = dialog.querySelector(this.selector.tree); + }, + + async _loadSavedKeys() { + const controllerFailureMsg = + TorStrings.onionServices.authPreferences.failedToGetKeys; + this._setBusyState(true); + + try { + this._tree.view = this; + + const torController = controller(aError => { + this._showError(controllerFailureMsg); + }); + + const keyInfoList = await torController.onionAuthViewKeys(); + if (keyInfoList) { + // Filter out temporary keys. + this._keyInfoList = keyInfoList.filter(aKeyInfo => { + if (!aKeyInfo.Flags) { + return false; + } + + const flags = aKeyInfo.Flags.split(","); + return flags.includes("Permanent"); + }); + + // Sort by the .onion address. + this._keyInfoList.sort((aObj1, aObj2) => { + const hsAddr1 = aObj1.hsAddress.toLowerCase(); + const hsAddr2 = aObj2.hsAddress.toLowerCase(); + if (hsAddr1 < hsAddr2) { + return -1; + } + return hsAddr1 > hsAddr2 ? 1 : 0; + }); + } + + // Render the tree content. + this._tree.rowCountChanged(0, this.rowCount); + } catch (e) { + if (e.torMessage) { + this._showError(e.torMessage); + } else { + this._showError(controllerFailureMsg); + } + } + + this._setBusyState(false); + }, + + // This method may throw; callers should catch errors. + async _deleteOneKey(aTorController, aIndex) { + const keyInfoObj = this._keyInfoList[aIndex]; + await aTorController.onionAuthRemove(keyInfoObj.hsAddress); + this._tree.view.selection.clearRange(aIndex, aIndex); + this._keyInfoList.splice(aIndex, 1); + this._tree.rowCountChanged(aIndex + 1, -1); + }, + + _setBusyState(aIsBusy) { + this._isBusy = aIsBusy; + this.updateButtonsState(); + }, + + _onWindowKeyPress(event) { + if (event.keyCode === KeyEvent.DOM_VK_ESCAPE) { + window.close(); + } else if (event.keyCode === KeyEvent.DOM_VK_DELETE) { + this.deleteSelectedKeys(); + } + }, + + _showError(aMessage) { + const dialog = document.querySelector(this.selector.dialog); + const errorIcon = dialog.querySelector(this.selector.errorIcon); + errorIcon.style.visibility = aMessage ? "visible" : "hidden"; + const errorDesc = dialog.querySelector(this.selector.errorMessage); + errorDesc.textContent = aMessage ? aMessage : ""; + }, + + // XUL tree widget view implementation. + get rowCount() { + return this._keyInfoList ? this._keyInfoList.length : 0; + }, + + getCellText(aRow, aCol) { + let val = ""; + if (this._keyInfoList && aRow < this._keyInfoList.length) { + const keyInfo = this._keyInfoList[aRow]; + if (aCol.id.endsWith("-siteCol")) { + val = keyInfo.hsAddress; + } else if (aCol.id.endsWith("-keyCol")) { + val = keyInfo.typeAndKey; + // Omit keyType because it is always "x25519". + const idx = val.indexOf(":"); + if (idx > 0) { + val = val.substring(idx + 1); + } + } + } + + return val; + }, + + isSeparator(index) { + return false; + }, + + isSorted() { + return false; + }, + + isContainer(index) { + return false; + }, + + setTree(tree) {}, + + getImageSrc(row, column) {}, + + getCellValue(row, column) {}, + + cycleHeader(column) {}, + + getRowProperties(row) { + return ""; + }, + + getColumnProperties(column) { + return ""; + }, + + getCellProperties(row, column) { + return ""; + }, +}; + +window.addEventListener("load", () => gOnionServicesSavedKeysDialog._onLoad()); diff --git a/browser/components/onionservices/content/savedKeysDialog.xhtml b/browser/components/onionservices/content/savedKeysDialog.xhtml new file mode 100644 index 000000000000..3db9bb05ea82 --- /dev/null +++ b/browser/components/onionservices/content/savedKeysDialog.xhtml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- Copyright (c) 2020, The Tor Project, Inc. --> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?> +<?xml-stylesheet href="chrome://browser/content/onionservices/authPreferences.css" type="text/css"?> + +<window id="onionservices-savedkeys-dialog" + windowtype="OnionServices:SavedKeys" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + style="width: 45em;"> + + <script src="chrome://browser/content/onionservices/savedKeysDialog.js"/> + + <vbox id="onionservices-savedkeys" class="contentPane" flex="1"> + <label id="onionservices-savedkeys-intro" + control="onionservices-savedkeys-tree"/> + <separator class="thin"/> + <tree id="onionservices-savedkeys-tree" flex="1" hidecolumnpicker="true" + width="750" + style="height: 20em;" + onselect="gOnionServicesSavedKeysDialog.updateButtonsState();"> + <treecols> + <treecol id="onionservices-savedkeys-siteCol" flex="1" persist="width"/> + <splitter class="tree-splitter"/> + <treecol id="onionservices-savedkeys-keyCol" flex="1" persist="width"/> + </treecols> + <treechildren/> + </tree> + <hbox id="onionservices-savedkeys-errorContainer" align="baseline" flex="1"> + <image id="onionservices-savedkeys-errorIcon"/> + <description id="onionservices-savedkeys-errorMessage" flex="1"/> + </hbox> + <separator class="thin"/> + <hbox id="onionservices-savedkeys-buttons"> + <button id="onionservices-savedkeys-remove" disabled="true" + oncommand="gOnionServicesSavedKeysDialog.deleteSelectedKeys();"/> + <button id="onionservices-savedkeys-removeall" + oncommand="gOnionServicesSavedKeysDialog.deleteAllKeys();"/> + </hbox> + </vbox> +</window> diff --git a/browser/components/onionservices/jar.mn b/browser/components/onionservices/jar.mn new file mode 100644 index 000000000000..9d6ce88d1841 --- /dev/null +++ b/browser/components/onionservices/jar.mn @@ -0,0 +1,9 @@ +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) + content/browser/onionservices/savedKeysDialog.xhtml (content/savedKeysDialog.xhtml) diff --git a/browser/components/onionservices/moz.build b/browser/components/onionservices/moz.build new file mode 100644 index 000000000000..2661ad7cb9f3 --- /dev/null +++ b/browser/components/onionservices/moz.build @@ -0,0 +1 @@ +JAR_MANIFESTS += ["jar.mn"] diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml index 0139abf95cbd..07ab5cc7b626 100644 --- a/browser/components/preferences/preferences.xhtml +++ b/browser/components/preferences/preferences.xhtml @@ -12,6 +12,7 @@ <?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?> +<?xml-stylesheet href="chrome://browser/content/onionservices/authPreferences.css"?> <?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?> <?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?> diff --git a/browser/components/preferences/privacy.inc.xhtml b/browser/components/preferences/privacy.inc.xhtml index 29179473aadd..eb410c13a8cc 100644 --- a/browser/components/preferences/privacy.inc.xhtml +++ b/browser/components/preferences/privacy.inc.xhtml @@ -493,6 +493,8 @@ <label id="fips-desc" hidden="true" data-l10n-id="forms-master-pw-fips-desc"></label> </groupbox> +#include ../onionservices/content/authPreferences.inc.xhtml + <!-- The form autofill section is inserted in to this box after the form autofill extension has initialized. --> <groupbox id="formAutofillGroupBox" diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js index 36259321dd06..0b1e28dfac92 100644 --- a/browser/components/preferences/privacy.js +++ b/browser/components/preferences/privacy.js @@ -80,6 +80,12 @@ XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() { } }); +XPCOMUtils.defineLazyScriptGetter( + this, + ["OnionServicesAuthPreferences"], + "chrome://browser/content/onionservices/authPreferences.js" +); + // TODO: module import via ChromeUtils.defineModuleGetter XPCOMUtils.defineLazyScriptGetter( this, @@ -529,6 +535,7 @@ var gPrivacyPane = { this.trackingProtectionReadPrefs(); this.networkCookieBehaviorReadPrefs(); this._initTrackingProtectionExtensionControl(); + OnionServicesAuthPreferences.init(); this._initSecurityLevel(); Services.telemetry.setEventRecordingEnabled("pwmgr", true); diff --git a/browser/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css index f93db99f22bd..39eb59a04964 100644 --- a/browser/themes/shared/notification-icons.inc.css +++ b/browser/themes/shared/notification-icons.inc.css @@ -146,6 +146,9 @@ list-style-image: url(chrome://browser/skin/notification-icons/indexedDB.svg); } +/* Reuse Firefox's login (key) icon for the Tor onion services auth. prompt */ +.popup-notification-icon[popupid="tor-clientauth"], +.tor-clientauth-icon, .popup-notification-icon[popupid="password"], .login-icon { list-style-image: url(chrome://browser/skin/login.svg); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index f1119393898d..94ceeb67f301 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -3814,6 +3814,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, } } else { // Errors requiring simple formatting + bool isOnionAuthError = false; switch (aError) { case NS_ERROR_MALFORMED_URI: // URI is malformed @@ -3896,10 +3897,44 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, // HTTP/2 or HTTP/3 stack detected a protocol error error = "networkProtocolError"; break; - + case NS_ERROR_TOR_ONION_SVC_NOT_FOUND: + error = "onionServices.descNotFound"; + break; + case NS_ERROR_TOR_ONION_SVC_IS_INVALID: + error = "onionServices.descInvalid"; + break; + case NS_ERROR_TOR_ONION_SVC_INTRO_FAILED: + error = "onionServices.introFailed"; + break; + case NS_ERROR_TOR_ONION_SVC_REND_FAILED: + error = "onionServices.rendezvousFailed"; + break; + case NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH: + error = "onionServices.clientAuthMissing"; + isOnionAuthError = true; + break; + case NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH: + error = "onionServices.clientAuthIncorrect"; + isOnionAuthError = true; + break; + case NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS: + error = "onionServices.badAddress"; + break; + case NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT: + error = "onionServices.introTimedOut"; + break; default: break; } + + // The presence of aFailedChannel indicates that we arrived here due to a + // failed connection attempt. Note that we will arrive here a second time + // if the user cancels the Tor client auth prompt, but in that case we + // will not have a failed channel and therefore we will not prompt again. + if (isOnionAuthError && aFailedChannel) { + // Display about:blank while the Tor client auth prompt is open. + errorPage.AssignLiteral("blank"); + } } // If the HTTPS-Only Mode upgraded this request and the upgrade might have @@ -3982,6 +4017,20 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, nsAutoString str; rv = stringBundle->FormatStringFromName(errorDescriptionID, formatStrs, str); + if (NS_FAILED(rv)) { + // As a fallback, check torbutton.properties for the error string. + const char bundleURL[] = "chrome://torbutton/locale/torbutton.properties"; + nsCOMPtr<nsIStringBundleService> stringBundleService = + mozilla::services::GetStringBundleService(); + if (stringBundleService) { + nsCOMPtr<nsIStringBundle> tbStringBundle; + if (NS_SUCCEEDED(stringBundleService->CreateBundle( + bundleURL, getter_AddRefs(tbStringBundle)))) { + rv = tbStringBundle->FormatStringFromName(errorDescriptionID, + formatStrs, str); + } + } + } NS_ENSURE_SUCCESS(rv, rv); messageStr.Assign(str); } @@ -6402,6 +6451,7 @@ nsresult nsDocShell::FilterStatusForErrorPage( aStatus == NS_ERROR_FILE_ACCESS_DENIED || aStatus == NS_ERROR_CORRUPTED_CONTENT || aStatus == NS_ERROR_INVALID_CONTENT_ENCODING || + NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_TOR || NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { // Errors to be shown for any frame return aStatus; @@ -8187,6 +8237,35 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType, FireOnLocationChange(this, aRequest, mCurrentURI, locationFlags); } + // Arrange to show a Tor onion service client authentication prompt if + // appropriate. + if ((mLoadType == LOAD_ERROR_PAGE) && failedChannel) { + nsresult status = NS_OK; + if (NS_SUCCEEDED(failedChannel->GetStatus(&status)) && + ((status == NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH) || + (status == NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH))) { + nsAutoCString onionHost; + failedURI->GetHost(onionHost); + const char* topic = (status == NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH) + ? "tor-onion-services-clientauth-missing" + : "tor-onion-services-clientauth-incorrect"; + if (XRE_IsContentProcess()) { + nsCOMPtr<nsIBrowserChild> browserChild = GetBrowserChild(); + if (browserChild) { + static_cast<BrowserChild*>(browserChild.get()) + ->SendShowOnionServicesAuthPrompt(onionHost, nsCString(topic)); + } + } else { + nsCOMPtr<nsPIDOMWindowOuter> browserWin = GetWindow(); + nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService(); + if (browserWin && obsSvc) { + obsSvc->NotifyObservers(browserWin, topic, + NS_ConvertUTF8toUTF16(onionHost).get()); + } + } + } + } + return NS_OK; } diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index 378211d237a0..240b386f6dde 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -3805,6 +3805,27 @@ mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt( return IPC_OK(); } +mozilla::ipc::IPCResult BrowserParent::RecvShowOnionServicesAuthPrompt( + const nsCString& aOnionName, const nsCString& aTopic) { + nsCOMPtr<nsIBrowser> browser = + mFrameElement ? mFrameElement->AsBrowser() : nullptr; + if (!browser) { + // If the tab is being closed, the browser may not be available. + // In this case we can ignore the request. + return IPC_OK(); + } + nsCOMPtr<nsIObserverService> os = services::GetObserverService(); + if (!os) { + return IPC_FAIL_NO_REASON(this); + } + nsresult rv = os->NotifyObservers(browser, aTopic.get(), + NS_ConvertUTF8toUTF16(aOnionName).get()); + if (NS_FAILED(rv)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(nsIURI* aURI, nsIURI* aLastVisitedURI, const uint32_t& aFlags) { diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h index 0d4e3e1c9c8a..a37271da9544 100644 --- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -740,6 +740,9 @@ class BrowserParent final : public PBrowserParent, mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt( const nsCString& aOrigin, const bool& aHideDoorHanger); + mozilla::ipc::IPCResult RecvShowOnionServicesAuthPrompt( + const nsCString& aOnionName, const nsCString& aTopic); + mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName); mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName); diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index df77d19287bd..29433edcde78 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -580,6 +580,15 @@ parent: async RequestPointerCapture(uint32_t aPointerId) returns (bool aSuccess); async ReleasePointerCapture(uint32_t aPointerId); + /** + * This function is used to notify the parent that it should display a + * onion services client authentication prompt. + * + * @param aOnionHost The hostname of the .onion that needs authentication. + * @param aTopic The reason for the prompt. + */ + async ShowOnionServicesAuthPrompt(nsCString aOnionHost, nsCString aTopic); + child: async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse); async UpdateEpoch(uint32_t aEpoch); diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg index c7fbdd23f378..07f529957bd0 100644 --- a/js/xpconnect/src/xpc.msg +++ b/js/xpconnect/src/xpc.msg @@ -248,5 +248,15 @@ XPC_MSG_DEF(NS_ERROR_FINGERPRINTING_URI , "The URI is fingerprinti XPC_MSG_DEF(NS_ERROR_CRYPTOMINING_URI , "The URI is cryptomining") XPC_MSG_DEF(NS_ERROR_SOCIALTRACKING_URI , "The URI is social tracking") +/* Codes related to Tor */ +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_NOT_FOUND , "Tor onion service descriptor cannot be found") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_IS_INVALID , "Tor onion service descriptor is invalid") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_INTRO_FAILED , "Tor onion service introduction failed") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_REND_FAILED , "Tor onion service rendezvous failed") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH, "Tor onion service missing client authorization") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH , "Tor onion service wrong client authorization") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS , "Tor onion service bad address") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT , "Tor onion service introduction timed out") + /* Profile manager error codes */ XPC_MSG_DEF(NS_ERROR_DATABASE_CHANGED , "Flushing the profiles to disk would have overwritten changes made elsewhere.") diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index 551fa4d50997..0cbc65e43c99 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -216,6 +216,12 @@ nsresult ErrorAccordingToNSPR(PRErrorCode errorCode) { default: if (psm::IsNSSErrorCode(errorCode)) { rv = psm::GetXPCOMFromNSSError(errorCode); + } else { + // If we received a Tor extended error code via SOCKS, pass it through. + nsresult res = nsresult(errorCode); + if (NS_ERROR_GET_MODULE(res) == NS_ERROR_MODULE_TOR) { + rv = res; + } } break; diff --git a/netwerk/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp index 0a16d6c7236f..c2bf0e951dda 100644 --- a/netwerk/socket/nsSOCKSIOLayer.cpp +++ b/netwerk/socket/nsSOCKSIOLayer.cpp @@ -1007,6 +1007,55 @@ PRStatus nsSOCKSSocketInfo::ReadV5ConnectResponseTop() { "08, Address type not supported.")); c = PR_BAD_ADDRESS_ERROR; break; + case 0xF0: // Tor SOCKS5_HS_NOT_FOUND + LOGERROR( + ("socks5: connect failed: F0," + " Tor onion service descriptor can not be found.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_NOT_FOUND); + break; + case 0xF1: // Tor SOCKS5_HS_IS_INVALID + LOGERROR( + ("socks5: connect failed: F1," + " Tor onion service descriptor is invalid.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_IS_INVALID); + break; + case 0xF2: // Tor SOCKS5_HS_INTRO_FAILED + LOGERROR( + ("socks5: connect failed: F2," + " Tor onion service introduction failed.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_INTRO_FAILED); + break; + case 0xF3: // Tor SOCKS5_HS_REND_FAILED + LOGERROR( + ("socks5: connect failed: F3," + " Tor onion service rendezvous failed.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_REND_FAILED); + break; + case 0xF4: // Tor SOCKS5_HS_MISSING_CLIENT_AUTH + LOGERROR( + ("socks5: connect failed: F4," + " Tor onion service missing client authorization.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH); + break; + case 0xF5: // Tor SOCKS5_HS_BAD_CLIENT_AUTH + LOGERROR( + ("socks5: connect failed: F5," + " Tor onion service wrong client authorization.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH); + break; + case 0xF6: // Tor SOCKS5_HS_BAD_ADDRESS + LOGERROR( + ("socks5: connect failed: F6," + " Tor onion service bad address.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS); + break; + case 0xF7: // Tor SOCKS5_HS_INTRO_TIMEDOUT + LOGERROR( + ("socks5: connect failed: F7," + " Tor onion service introduction timed out.")); + c = static_cast<uint32_t>(NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT); + break; + default: LOGERROR(("socks5: connect failed.")); break; diff --git a/toolkit/modules/PopupNotifications.jsm b/toolkit/modules/PopupNotifications.jsm index d6518723afab..9764cfd496c3 100644 --- a/toolkit/modules/PopupNotifications.jsm +++ b/toolkit/modules/PopupNotifications.jsm @@ -410,6 +410,8 @@ PopupNotifications.prototype = { * will be dismissed instead of removed after running the callback. * - [optional] disabled (boolean): If this is true, the button * will be disabled. + * - [optional] leaveOpen (boolean): If this is true, the notification + * will not be removed after running the callback. * - [optional] disableHighlight (boolean): If this is true, the button * will not apply the default highlight style. * If null, the notification will have a default "OK" action button @@ -1916,6 +1918,10 @@ PopupNotifications.prototype = { this._dismiss(); return; } + + if (action.leaveOpen) { + return; + } } this._remove(notification); diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm index e5111ff83782..c12e71ac4d42 100644 --- a/toolkit/modules/RemotePageAccessManager.jsm +++ b/toolkit/modules/RemotePageAccessManager.jsm @@ -102,6 +102,7 @@ let RemotePageAccessManager = { RPMAddToHistogram: ["*"], RPMGetInnerMostURI: ["*"], RPMGetHttpResponseHeader: ["*"], + RPMGetTorStrings: ["*"], }, "about:plugins": { RPMSendQuery: ["RequestPlugins"], diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js index 15c15615ad97..57458ba0bf5e 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/frame-script.js @@ -41,5 +41,6 @@ module.exports = { RPMGetHttpResponseHeader: false, RPMTryPingSecureWWWLink: false, RPMOpenSecureWWWLink: false, + RPMGetTorStrings: false, }, }; diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py index 9b9ce1a4acc5..7f860b127b8b 100755 --- a/xpcom/base/ErrorList.py +++ b/xpcom/base/ErrorList.py @@ -89,6 +89,7 @@ modules["ERRORRESULT"] = Mod(43) # Win32 system error codes, which are not mapped to a specific other value, # see Bug 1686041. modules["WIN32"] = Mod(44) +modules["TOR"] = Mod(45) # NS_ERROR_MODULE_GENERAL should be used by modules that do not # care if return code values overlap. Callers of methods that @@ -1206,6 +1207,27 @@ with modules["ERRORRESULT"]: errors["NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR"] = FAILURE(5) +# ======================================================================= +# 45: Tor-specific error codes. +# ======================================================================= +with modules["TOR"]: + # Tor onion service descriptor can not be found. + errors["NS_ERROR_TOR_ONION_SVC_NOT_FOUND"] = FAILURE(1) + # Tor onion service descriptor is invalid. + errors["NS_ERROR_TOR_ONION_SVC_IS_INVALID"] = FAILURE(2) + # Tor onion service introduction failed. + errors["NS_ERROR_TOR_ONION_SVC_INTRO_FAILED"] = FAILURE(3) + # Tor onion service rendezvous failed. + errors["NS_ERROR_TOR_ONION_SVC_REND_FAILED"] = FAILURE(4) + # Tor onion service missing client authorization. + errors["NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH"] = FAILURE(5) + # Tor onion service wrong client authorization. + errors["NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH"] = FAILURE(6) + # Tor onion service bad address. + errors["NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS"] = FAILURE(7) + # Tor onion service introduction timed out. + errors["NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT"] = FAILURE(8) + # ======================================================================= # 51: NS_ERROR_MODULE_GENERAL # =======================================================================
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 28005: Implement .onion alias urlbar rewrites
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit b4c6b1e785e7914fd986cb89bb0af6f83e6ebc17 Author: Alex Catarineu <acat(a)torproject.org> Date: Thu Feb 13 13:24:33 2020 +0100 Bug 28005: Implement .onion alias urlbar rewrites A custom HTTPS Everywhere update channel is installed, which provides rules for locally redirecting some memorable .tor.onion URLs to non-memorable .onion URLs. When these redirects occur, we also rewrite the URL in the urlbar to display the human-memorable hostname instead of the actual .onion. Bug 34196: Update site info URL with the onion name --- browser/actors/ClickHandlerChild.jsm | 20 ++ browser/actors/ClickHandlerParent.jsm | 1 + browser/actors/ContextMenuChild.jsm | 4 + browser/base/content/browser-places.js | 12 +- browser/base/content/browser-siteIdentity.js | 12 +- browser/base/content/browser.js | 43 ++++- browser/base/content/nsContextMenu.js | 18 ++ browser/base/content/pageinfo/pageInfo.js | 2 +- browser/base/content/pageinfo/pageInfo.xhtml | 10 + browser/base/content/pageinfo/security.js | 17 +- browser/base/content/tabbrowser.js | 7 + browser/base/content/utilityOverlay.js | 12 ++ browser/components/BrowserGlue.jsm | 8 + .../onionservices/ExtensionMessaging.jsm | 77 ++++++++ .../onionservices/HttpsEverywhereControl.jsm | 119 ++++++++++++ .../components/onionservices/OnionAliasStore.jsm | 201 +++++++++++++++++++++ browser/components/onionservices/moz.build | 6 + browser/components/urlbar/UrlbarInput.jsm | 13 +- docshell/base/nsDocShell.cpp | 52 ++++++ docshell/base/nsDocShell.h | 6 + docshell/base/nsDocShellLoadState.cpp | 8 + docshell/base/nsIDocShell.idl | 5 + docshell/base/nsIWebNavigation.idl | 5 + docshell/shistory/SessionHistoryEntry.cpp | 14 ++ docshell/shistory/SessionHistoryEntry.h | 1 + docshell/shistory/nsISHEntry.idl | 5 + docshell/shistory/nsSHEntry.cpp | 22 ++- docshell/shistory/nsSHEntry.h | 1 + dom/interfaces/base/nsIBrowser.idl | 3 +- dom/ipc/BrowserChild.cpp | 2 + dom/ipc/BrowserParent.cpp | 3 +- dom/ipc/PBrowser.ipdl | 1 + modules/libpref/init/StaticPrefList.yaml | 6 + netwerk/dns/effective_tld_names.dat | 2 + netwerk/ipc/DocumentLoadListener.cpp | 10 + toolkit/content/widgets/browser-custom-element.js | 13 +- toolkit/modules/sessionstore/SessionHistory.jsm | 5 + xpcom/reflect/xptinfo/xptinfo.h | 3 +- 38 files changed, 726 insertions(+), 23 deletions(-) diff --git a/browser/actors/ClickHandlerChild.jsm b/browser/actors/ClickHandlerChild.jsm index 4f5c2b0b7ea1..3ba2f11bf362 100644 --- a/browser/actors/ClickHandlerChild.jsm +++ b/browser/actors/ClickHandlerChild.jsm @@ -114,6 +114,26 @@ class ClickHandlerChild extends JSWindowActorChild { json.originStoragePrincipal = ownerDoc.effectiveStoragePrincipal; json.triggeringPrincipal = ownerDoc.nodePrincipal; + // Check if the link needs to be opened with .tor.onion urlbar rewrites + // allowed. Only when the owner doc has onionUrlbarRewritesAllowed = true + // and the same origin we should allow this. + json.onionUrlbarRewritesAllowed = false; + if (this.docShell.onionUrlbarRewritesAllowed) { + const sm = Services.scriptSecurityManager; + try { + let targetURI = Services.io.newURI(href); + let isPrivateWin = + ownerDoc.nodePrincipal.originAttributes.privateBrowsingId > 0; + sm.checkSameOriginURI( + docshell.currentDocumentChannel.URI, + targetURI, + false, + isPrivateWin + ); + json.onionUrlbarRewritesAllowed = true; + } catch (e) {} + } + // If a link element is clicked with middle button, user wants to open // the link somewhere rather than pasting clipboard content. Therefore, // when it's clicked with middle button, we should prevent multiple diff --git a/browser/actors/ClickHandlerParent.jsm b/browser/actors/ClickHandlerParent.jsm index 0f658fccf7b8..ad8f6c2a27e2 100644 --- a/browser/actors/ClickHandlerParent.jsm +++ b/browser/actors/ClickHandlerParent.jsm @@ -98,6 +98,7 @@ class ClickHandlerParent extends JSWindowActorParent { let params = { charset: browser.characterSet, referrerInfo: E10SUtils.deserializeReferrerInfo(data.referrerInfo), + onionUrlbarRewritesAllowed: data.onionUrlbarRewritesAllowed, isContentWindowPrivate: data.isContentWindowPrivate, originPrincipal: data.originPrincipal, originStoragePrincipal: data.originStoragePrincipal, diff --git a/browser/actors/ContextMenuChild.jsm b/browser/actors/ContextMenuChild.jsm index a286eafe0f6d..d332cb41acc8 100644 --- a/browser/actors/ContextMenuChild.jsm +++ b/browser/actors/ContextMenuChild.jsm @@ -545,6 +545,9 @@ class ContextMenuChild extends JSWindowActorChild { doc.defaultView ).getFieldContext(aEvent.composedTarget); + let parentAllowsOnionUrlbarRewrites = this.docShell + .onionUrlbarRewritesAllowed; + let disableSetDesktopBackground = null; // Media related cache info parent needs for saving @@ -656,6 +659,7 @@ class ContextMenuChild extends JSWindowActorChild { frameID, frameBrowsingContextID, disableSetDesktopBackground, + parentAllowsOnionUrlbarRewrites, }; if (context.inFrame && !context.inSrcdocFrame) { diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index a73e2090bbee..cb8fbeab9bf4 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -470,7 +470,8 @@ var PlacesCommandHook = { */ async bookmarkPage() { let browser = gBrowser.selectedBrowser; - let url = new URL(browser.currentURI.spec); + const uri = browser.currentOnionAliasURI || browser.currentURI; + let url = new URL(uri.spec); let info = await PlacesUtils.bookmarks.fetch({ url }); let isNewBookmark = !info; let showEditUI = !isNewBookmark || StarUI.showForNewBookmarks; @@ -581,7 +582,7 @@ var PlacesCommandHook = { tabs.forEach(tab => { let browser = tab.linkedBrowser; - let uri = browser.currentURI; + let uri = browser.currentOnionAliasURI || browser.currentURI; let title = browser.contentTitle || tab.label; let spec = uri.spec; if (!(spec in uniquePages)) { @@ -1828,14 +1829,17 @@ var BookmarkingUI = { }, onLocationChange: function BUI_onLocationChange() { - if (this._uri && gBrowser.currentURI.equals(this._uri)) { + const uri = + gBrowser.selectedBrowser.currentOnionAliasURI || gBrowser.currentURI; + if (this._uri && uri.equals(this._uri)) { return; } this.updateStarState(); }, updateStarState: function BUI_updateStarState() { - this._uri = gBrowser.currentURI; + this._uri = + gBrowser.selectedBrowser.currentOnionAliasURI || gBrowser.currentURI; this._itemGuids.clear(); let guids = new Set(); diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 7c9a91ed5af1..7c132668f6b4 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -658,13 +658,13 @@ var gIdentityHandler = { * nsIURI for which the identity UI should be displayed, already * processed by createExposableURI. */ - updateIdentity(state, uri) { + updateIdentity(state, uri, onionAliasURI) { let shouldHidePopup = this._uri && this._uri.spec != uri.spec; this._state = state; // Firstly, populate the state properties required to display the UI. See // the documentation of the individual properties for details. - this.setURI(uri); + this.setURI(uri, onionAliasURI); this._secInfo = gBrowser.securityUI.secInfo; this._isSecureContext = gBrowser.securityUI.isSecureContext; @@ -687,17 +687,18 @@ var gIdentityHandler = { * Attempt to provide proper IDN treatment for host names */ getEffectiveHost() { + let uri = this._onionAliasURI || this._uri; if (!this._IDNService) { this._IDNService = Cc["@mozilla.org/network/idn-service;1"].getService( Ci.nsIIDNService ); } try { - return this._IDNService.convertToDisplayIDN(this._uri.host, {}); + return this._IDNService.convertToDisplayIDN(uri.host, {}); } catch (e) { // If something goes wrong (e.g. host is an IP address) just fail back // to the full domain. - return this._uri.host; + return uri.host; } }, @@ -1140,11 +1141,12 @@ var gIdentityHandler = { this._identityPopupContentVerif.textContent = verifier; }, - setURI(uri) { + setURI(uri, onionAliasURI) { if (uri.schemeIs("view-source")) { uri = Services.io.newURI(uri.spec.replace(/^view-source:/i, "")); } this._uri = uri; + this._onionAliasURI = onionAliasURI; try { // Account for file: urls and catch when "" is the value diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 501519db864e..7103cd2c374b 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -82,6 +82,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", Translation: "resource:///modules/translation/TranslationParent.jsm", + OnionAliasStore: "resource:///modules/OnionAliasStore.jsm", UITour: "resource:///modules/UITour.jsm", UpdateUtils: "resource://gre/modules/UpdateUtils.jsm", UrlbarInput: "resource:///modules/UrlbarInput.jsm", @@ -2286,6 +2287,7 @@ var gBrowserInit = { // [9]: allowInheritPrincipal (bool) // [10]: csp (nsIContentSecurityPolicy) // [11]: nsOpenWindowInfo + // [12]: onionUrlbarRewritesAllowed (bool) let userContextId = window.arguments[5] != undefined ? window.arguments[5] @@ -2305,7 +2307,8 @@ var gBrowserInit = { // TODO fix allowInheritPrincipal to default to false. // Default to true unless explicitly set to false because of bug 1475201. window.arguments[9] !== false, - window.arguments[10] + window.arguments[10], + window.arguments[12] ); window.focus(); } else { @@ -3085,7 +3088,8 @@ function loadURI( forceAboutBlankViewerInCurrent, triggeringPrincipal, allowInheritPrincipal = false, - csp = null + csp = null, + onionUrlbarRewritesAllowed = false ) { if (!triggeringPrincipal) { throw new Error("Must load with a triggering Principal"); @@ -3103,6 +3107,7 @@ function loadURI( csp, forceAboutBlankViewerInCurrent, allowInheritPrincipal, + onionUrlbarRewritesAllowed, }); } catch (e) { Cu.reportError(e); @@ -5227,11 +5232,24 @@ var XULBrowserWindow = { this.reloadCommand.removeAttribute("disabled"); } + // The onion memorable alias needs to be used in gURLBar.setURI, but also in + // other parts of the code (like the bookmarks UI), so we save it. + if (gBrowser.selectedBrowser.onionUrlbarRewritesAllowed) { + gBrowser.selectedBrowser.currentOnionAliasURI = OnionAliasStore.getShortURI( + aLocationURI + ); + } else { + gBrowser.selectedBrowser.currentOnionAliasURI = null; + } + // We want to update the popup visibility if we received this notification // via simulated locationchange events such as switching between tabs, however // if this is a document navigation then PopupNotifications will be updated // via TabsProgressListener.onLocationChange and we do not want it called twice - gURLBar.setURI(aLocationURI, aIsSimulated); + gURLBar.setURI( + gBrowser.selectedBrowser.currentOnionAliasURI || aLocationURI, + aIsSimulated + ); BookmarkingUI.onLocationChange(); // If we've actually changed document, update the toolbar visibility. @@ -5426,6 +5444,7 @@ var XULBrowserWindow = { // Don't need to do anything if the data we use to update the UI hasn't // changed let uri = gBrowser.currentURI; + let onionAliasURI = gBrowser.selectedBrowser.currentOnionAliasURI; let spec = uri.spec; let isSecureContext = gBrowser.securityUI.isSecureContext; if ( @@ -5449,7 +5468,7 @@ var XULBrowserWindow = { try { uri = Services.io.createExposableURI(uri); } catch (e) {} - gIdentityHandler.updateIdentity(this._state, uri); + gIdentityHandler.updateIdentity(this._state, uri, onionAliasURI); }, // simulate all change notifications after switching tabs @@ -6956,6 +6975,21 @@ function handleLinkClick(event, href, linkNode) { return true; } + // Check if the link needs to be opened with .tor.onion urlbar rewrites + // allowed. Only when the owner doc has onionUrlbarRewritesAllowed = true + // and the same origin we should allow this. + let persistOnionUrlbarRewritesAllowedInChildTab = false; + if (where == "tab" && gBrowser.docShell.onionUrlbarRewritesAllowed) { + const sm = Services.scriptSecurityManager; + try { + let tURI = makeURI(href); + let isPrivateWin = + doc.nodePrincipal.originAttributes.privateBrowsingId > 0; + sm.checkSameOriginURI(doc.documentURIObject, tURI, false, isPrivateWin); + persistOnionUrlbarRewritesAllowedInChildTab = true; + } catch (e) {} + } + let frameID = WebNavigationFrames.getFrameId(doc.defaultView); urlSecurityCheck(href, doc.nodePrincipal); @@ -6967,6 +7001,7 @@ function handleLinkClick(event, href, linkNode) { triggeringPrincipal: doc.nodePrincipal, csp: doc.csp, frameID, + onionUrlbarRewritesAllowed: persistOnionUrlbarRewritesAllowedInChildTab, }; // The new tab/window must use the same userContextId diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index f84f5fb7d028..c6b1257e45be 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -57,6 +57,7 @@ function openContextMenu(aMessage, aBrowser, aActor) { selectionInfo: data.selectionInfo, disableSetDesktopBackground: data.disableSetDesktopBackground, loginFillInfo: data.loginFillInfo, + parentAllowsOnionUrlbarRewrites: data.parentAllowsOnionUrlbarRewrites, userContextId: data.userContextId, webExtContextData: data.webExtContextData, cookieJarSettings: E10SUtils.deserializeCookieJarSettings( @@ -1195,6 +1196,7 @@ class nsContextMenu { triggeringPrincipal: this.principal, csp: this.csp, frameID: this.contentData.frameID, + onionUrlbarRewritesAllowed: false, }; for (let p in extra) { params[p] = extra[p]; @@ -1218,6 +1220,22 @@ class nsContextMenu { } params.referrerInfo = referrerInfo; + + // Check if the link needs to be opened with .tor.onion urlbar rewrites + // allowed. Only when parent has onionUrlbarRewritesAllowed = true + // and the same origin we should allow this. + if (this.contentData.parentAllowsOnionUrlbarRewrites) { + let referrerURI = this.contentData.documentURIObject; + const sm = Services.scriptSecurityManager; + try { + let targetURI = this.linkURI; + let isPrivateWin = + this.browser.contentPrincipal.originAttributes.privateBrowsingId > 0; + sm.checkSameOriginURI(referrerURI, targetURI, false, isPrivateWin); + params.onionUrlbarRewritesAllowed = true; + } catch (e) {} + } + return params; } diff --git a/browser/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js index f63ee0a457e1..ae152f97f7b3 100644 --- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -398,7 +398,7 @@ async function onNonMediaPageInfoLoad(browser, pageInfoData, imageInfo) { ); } onLoadPermission(uri, principal); - securityOnLoad(uri, windowInfo); + securityOnLoad(uri, windowInfo, browser.currentOnionAliasURI); } function resetPageInfo(args) { diff --git a/browser/base/content/pageinfo/pageInfo.xhtml b/browser/base/content/pageinfo/pageInfo.xhtml index f40ffd3778d8..a23f2bb5748c 100644 --- a/browser/base/content/pageinfo/pageInfo.xhtml +++ b/browser/base/content/pageinfo/pageInfo.xhtml @@ -312,6 +312,16 @@ <input id="security-identity-domain-value" readonly="readonly"/> </td> </tr> + <!-- Onion Alias --> + <tr id="security-view-identity-onionalias-row"> + <th> + <xul:label id="security-view-identity-onionalias" + control="security-view-identity-onionalias-value"/> + </th> + <td> + <input id="security-view-identity-onionalias-value" readonly="true"/> + </td> + </tr> <!-- Owner --> <tr> <th> diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js index 192e9f763700..7693a0304823 100644 --- a/browser/base/content/pageinfo/security.js +++ b/browser/base/content/pageinfo/security.js @@ -249,7 +249,7 @@ var security = { }, }; -async function securityOnLoad(uri, windowInfo) { +async function securityOnLoad(uri, windowInfo, onionAliasURI) { await security.init(uri, windowInfo); let info = security.securityInfo; @@ -262,6 +262,21 @@ async function securityOnLoad(uri, windowInfo) { } document.getElementById("securityTab").hidden = false; + if (onionAliasURI) { + setText( + "security-view-identity-onionalias", + gTorButtonBundle.GetStringFromName("pageInfo_OnionName") + ); + setText("security-view-identity-onionalias-value", onionAliasURI.host); + document.getElementById( + "security-view-identity-onionalias-row" + ).hidden = false; + } else { + document.getElementById( + "security-view-identity-onionalias-row" + ).hidden = true; + } + /* Set Identity section text */ setText("security-identity-domain-value", windowInfo.hostName); diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js index 0081810bd43e..d1457a6638b7 100644 --- a/browser/base/content/tabbrowser.js +++ b/browser/base/content/tabbrowser.js @@ -1647,6 +1647,7 @@ var aFromExternal; var aRelatedToCurrent; var aAllowInheritPrincipal; + var aOnionUrlbarRewritesAllowed; var aSkipAnimation; var aForceNotRemote; var aPreferredRemoteType; @@ -1676,6 +1677,7 @@ aFromExternal = params.fromExternal; aRelatedToCurrent = params.relatedToCurrent; aAllowInheritPrincipal = !!params.allowInheritPrincipal; + aOnionUrlbarRewritesAllowed = params.onionUrlbarRewritesAllowed; aSkipAnimation = params.skipAnimation; aForceNotRemote = params.forceNotRemote; aPreferredRemoteType = params.preferredRemoteType; @@ -1716,6 +1718,7 @@ fromExternal: aFromExternal, relatedToCurrent: aRelatedToCurrent, skipAnimation: aSkipAnimation, + onionUrlbarRewritesAllowed: aOnionUrlbarRewritesAllowed, forceNotRemote: aForceNotRemote, createLazyBrowser: aCreateLazyBrowser, preferredRemoteType: aPreferredRemoteType, @@ -2548,6 +2551,7 @@ aURI, { allowInheritPrincipal, + onionUrlbarRewritesAllowed, allowThirdPartyFixup, bulkOrderedOpen, charset, @@ -2888,6 +2892,9 @@ // lands. flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIRST_LOAD; } + if (onionUrlbarRewritesAllowed) { + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES; + } if (!allowInheritPrincipal) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL; } diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 78eb18a203fd..342a92a766a4 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -367,6 +367,7 @@ function openLinkIn(url, where, params) { : new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, null); var aRelatedToCurrent = params.relatedToCurrent; var aAllowInheritPrincipal = !!params.allowInheritPrincipal; + var aOnionUrlbarRewritesAllowed = params.onionUrlbarRewritesAllowed; var aForceAllowDataURI = params.forceAllowDataURI; var aInBackground = params.inBackground; var aInitiatingDoc = params.initiatingDoc; @@ -483,6 +484,11 @@ function openLinkIn(url, where, params) { ].createInstance(Ci.nsISupportsPRBool); allowThirdPartyFixupSupports.data = aAllowThirdPartyFixup; + var onionUrlbarRewritesAllowed = Cc[ + "@mozilla.org/supports-PRBool;1" + ].createInstance(Ci.nsISupportsPRBool); + onionUrlbarRewritesAllowed.data = aOnionUrlbarRewritesAllowed; + var userContextIdSupports = Cc[ "@mozilla.org/supports-PRUint32;1" ].createInstance(Ci.nsISupportsPRUint32); @@ -499,6 +505,8 @@ function openLinkIn(url, where, params) { sa.appendElement(aTriggeringPrincipal); sa.appendElement(null); // allowInheritPrincipal sa.appendElement(aCsp); + sa.appendElement(null); // nsOpenWindowInfo + sa.appendElement(onionUrlbarRewritesAllowed); const sourceWindow = w || window; let win; @@ -616,6 +624,9 @@ function openLinkIn(url, where, params) { if (aForceAllowDataURI) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI; } + if (aOnionUrlbarRewritesAllowed) { + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES; + } let { URI_INHERITS_SECURITY_CONTEXT } = Ci.nsIProtocolHandler; if ( @@ -662,6 +673,7 @@ function openLinkIn(url, where, params) { allowThirdPartyFixup: aAllowThirdPartyFixup, relatedToCurrent: aRelatedToCurrent, skipAnimation: aSkipTabAnimation, + onionUrlbarRewritesAllowed: aOnionUrlbarRewritesAllowed, userContextId: aUserContextId, originPrincipal: aPrincipal, originStoragePrincipal: aStoragePrincipal, diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 6186479ac306..5b320bd989f0 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -86,6 +86,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { TabUnloader: "resource:///modules/TabUnloader.jsm", TelemetryUtils: "resource://gre/modules/TelemetryUtils.jsm", TRRRacer: "resource:///modules/TRRPerformance.jsm", + OnionAliasStore: "resource:///modules/OnionAliasStore.jsm", UIState: "resource://services-sync/UIState.jsm", UrlbarQuickSuggest: "resource:///modules/UrlbarQuickSuggest.jsm", UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm", @@ -1933,6 +1934,7 @@ BrowserGlue.prototype = { Normandy.uninit(); RFPHelper.uninit(); ASRouterNewTabHook.destroy(); + OnionAliasStore.uninit(); }, // Set up a listener to enable/disable the screenshots extension @@ -2422,6 +2424,12 @@ BrowserGlue.prototype = { }, }, + { + task: () => { + OnionAliasStore.init(); + }, + }, + { task: () => { Blocklist.loadBlocklistAsync(); diff --git a/browser/components/onionservices/ExtensionMessaging.jsm b/browser/components/onionservices/ExtensionMessaging.jsm new file mode 100644 index 000000000000..c93b8c6edf85 --- /dev/null +++ b/browser/components/onionservices/ExtensionMessaging.jsm @@ -0,0 +1,77 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +const EXPORTED_SYMBOLS = ["ExtensionMessaging"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { ExtensionUtils } = ChromeUtils.import( + "resource://gre/modules/ExtensionUtils.jsm" +); +const { MessageChannel } = ChromeUtils.import( + "resource://gre/modules/MessageChannel.jsm" +); +const { AddonManager } = ChromeUtils.import( + "resource://gre/modules/AddonManager.jsm" +); + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +XPCOMUtils.defineLazyModuleGetters(this, { + ExtensionParent: "resource://gre/modules/ExtensionParent.jsm", +}); + +class ExtensionMessaging { + constructor() { + this._callback = null; + this._handlers = new Map(); + this._messageManager = Services.cpmm; + } + + async sendMessage(message, extensionId) { + const addon = await AddonManager.getAddonByID(extensionId); + if (!addon) { + throw new Error(`extension '${extensionId} does not exist`); + } + await addon.startupPromise; + + const { torSendExtensionMessage } = ExtensionParent; + return torSendExtensionMessage(extensionId, message); + } + + unload() { + if (this._callback) { + this._handlers.clear(); + this._messageManager.removeMessageListener( + "MessageChannel:Response", + this._callback + ); + this._callback = null; + } + } + + _onMessage({ data }) { + const channelId = data.messageName; + if (this._handlers.has(channelId)) { + const { resolve, reject } = this._handlers.get(channelId); + this._handlers.delete(channelId); + if (data.error) { + reject(new Error(data.error.message)); + } else { + resolve(data.value); + } + } + } + + _init() { + if (this._callback === null) { + this._callback = this._onMessage.bind(this); + this._messageManager.addMessageListener( + "MessageChannel:Response", + this._callback + ); + } + } +} diff --git a/browser/components/onionservices/HttpsEverywhereControl.jsm b/browser/components/onionservices/HttpsEverywhereControl.jsm new file mode 100644 index 000000000000..60c3b5fca282 --- /dev/null +++ b/browser/components/onionservices/HttpsEverywhereControl.jsm @@ -0,0 +1,119 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +const EXPORTED_SYMBOLS = ["HttpsEverywhereControl"]; + +const { ExtensionMessaging } = ChromeUtils.import( + "resource:///modules/ExtensionMessaging.jsm" +); +const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm"); + +const EXTENSION_ID = "https-everywhere-eff(a)eff.org"; +const SECUREDROP_TOR_ONION_CHANNEL = { + name: "SecureDropTorOnion", + jwk: { + kty: "RSA", + e: "AQAB", + n: + "p10BbUVc5Xj2S_-MH3bACNBaISo_r9e3PVPyTTjsGsdg2qSXvqUO42fBtpFAy0zUzIGS83v4JjiRdvKJaZTIvbC8AcpymzdsTqujMm8RPTSy3hO_8mXzGa4DEsIB1uNLnUWRBKXvSGCmT9kFyxhTpkYqokNBzafVihTU34tN2Md1xFHnmZGqfYtPtbJLWAa5Z1M11EyR4lIyUxIiPTV9t1XstDbWr3iS83REJrGEFmjG1-BAgx8_lDUTa41799N2yYEhgZud7bL0M3ei8s5OERjiion5uANkUV3-s2QqUZjiVA-XR_HizXjciaUWNd683KqekpNOZ_0STh_UGwpcwU-KwG07QyiCrLrRpz8S_vH8CqGrrcWY3GSzYe9dp34jJdO65oA-G8tK6fMXtvTCFDZI6oNNaXJH71F5J0YbqO2ZqwKYc2WSi0gKVl2wd9roOVjaBmkJqvocntYuNM7t38fDEWHn5KUkmrTbiG68Cy56tDUfpKl3D9Uj4LaMvxJ1tKGvzQ4k_60odT7gIxu6DqYjXUHZpwPsSGBq3njaD7boe4CUXF2K7ViOc87BsKxRNCzDD8OklRjjXzOTOBH3PqFJ93CJ-4ECE5t9STU20aZ8E-2zKB8vjKyCySE4-kcIvBBsnkwVaJTPy9Ft1qYybo-soXEWVEZATANNWklBt8k", + }, + update_path_prefix: "https://securedrop.org/https-everywhere/", + scope: + "^https?:\\/\\/[a-z0-9-]+(?:\\.[a-z0-9-]+)*\\.securedrop\\.tor\\.onion\\/", + replaces_default_rulesets: false, +}; + +class HttpsEverywhereControl { + constructor() { + this._extensionMessaging = null; + } + + async _sendMessage(type, object) { + return this._extensionMessaging.sendMessage( + { + type, + object, + }, + EXTENSION_ID + ); + } + + static async wait(seconds = 1) { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)); + } + + /** + * Installs the .tor.onion update channel in https-everywhere + */ + async installTorOnionUpdateChannel(retries = 5) { + this._init(); + + // TODO: https-everywhere store is initialized asynchronously, so sending a message + // immediately results in a `store.get is undefined` error. + // For now, let's wait a bit and retry a few times if there is an error, but perhaps + // we could suggest https-everywhere to send a message when that happens and listen + // for that here. + await HttpsEverywhereControl.wait(); + + try { + // TODO: we may want a way to "lock" this update channel, so that it cannot be modified + // by the user via UI, but I think this is not possible at the time of writing via + // the existing messages in https-everywhere. + await this._sendMessage( + "create_update_channel", + SECUREDROP_TOR_ONION_CHANNEL.name + ); + } catch (e) { + if (retries <= 0) { + throw new Error("Could not install SecureDropTorOnion update channel"); + } + await this.installTorOnionUpdateChannel(retries - 1); + return; + } + + await this._sendMessage( + "update_update_channel", + SECUREDROP_TOR_ONION_CHANNEL + ); + } + + /** + * Returns the .tor.onion rulesets available in https-everywhere + */ + async getTorOnionRules() { + return this._sendMessage("get_simple_rules_ending_with", ".tor.onion"); + } + + /** + * Returns the timestamp of the last .tor.onion update channel update. + */ + async getRulesetTimestamp() { + const rulesets = await this._sendMessage("get_ruleset_timestamps"); + const securedrop = + rulesets && + rulesets.find(([{ name }]) => name === SECUREDROP_TOR_ONION_CHANNEL.name); + if (securedrop) { + const [ + updateChannel, // This has the same structure as SECUREDROP_TOR_ONION_CHANNEL + lastUpdatedTimestamp, // An integer, 0 if the update channel was never updated + ] = securedrop; + void updateChannel; // Ignore eslint unused warning for ruleset + return lastUpdatedTimestamp; + } + return null; + } + + unload() { + if (this._extensionMessaging) { + this._extensionMessaging.unload(); + this._extensionMessaging = null; + } + } + + _init() { + if (!this._extensionMessaging) { + this._extensionMessaging = new ExtensionMessaging(); + } + } +} diff --git a/browser/components/onionservices/OnionAliasStore.jsm b/browser/components/onionservices/OnionAliasStore.jsm new file mode 100644 index 000000000000..66cf569227bf --- /dev/null +++ b/browser/components/onionservices/OnionAliasStore.jsm @@ -0,0 +1,201 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +const EXPORTED_SYMBOLS = ["OnionAliasStore"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +const { setTimeout, clearTimeout } = ChromeUtils.import( + "resource://gre/modules/Timer.jsm" +); +const { HttpsEverywhereControl } = ChromeUtils.import( + "resource:///modules/HttpsEverywhereControl.jsm" +); + +// Logger adapted from CustomizableUI.jsm +const kPrefOnionAliasDebug = "browser.onionalias.debug"; +XPCOMUtils.defineLazyPreferenceGetter( + this, + "gDebuggingEnabled", + kPrefOnionAliasDebug, + false, + (pref, oldVal, newVal) => { + if (typeof log != "undefined") { + log.maxLogLevel = newVal ? "all" : "log"; + } + } +); +XPCOMUtils.defineLazyGetter(this, "log", () => { + let scope = {}; + ChromeUtils.import("resource://gre/modules/Console.jsm", scope); + let consoleOptions = { + maxLogLevel: gDebuggingEnabled ? "all" : "log", + prefix: "OnionAlias", + }; + return new scope.ConsoleAPI(consoleOptions); +}); + +function observe(topic, callback) { + let observer = { + observe(aSubject, aTopic, aData) { + if (topic === aTopic) { + callback(aSubject, aData); + } + }, + }; + Services.obs.addObserver(observer, topic); + return () => Services.obs.removeObserver(observer, topic); +} + +class _OnionAliasStore { + static get RULESET_CHECK_INTERVAL() { + return 1000 * 60; // 1 minute + } + + static get RULESET_CHECK_INTERVAL_FAST() { + return 1000 * 5; // 5 seconds + } + + constructor() { + this._onionMap = new Map(); + this._rulesetTimeout = null; + this._removeObserver = () => {}; + this._canLoadRules = false; + this._rulesetTimestamp = null; + this._updateChannelInstalled = false; + } + + async _periodicRulesetCheck() { + // TODO: it would probably be preferable to listen to some message broadcasted by + // the https-everywhere extension when some update channel is updated, instead of + // polling every N seconds. + log.debug("Checking for new rules"); + const ts = await this.httpsEverywhereControl.getRulesetTimestamp(); + log.debug( + `Found ruleset timestamp ${ts}, current is ${this._rulesetTimestamp}` + ); + if (ts !== this._rulesetTimestamp) { + this._rulesetTimestamp = ts; + log.debug("New rules found, updating"); + // We clear the mappings even if we cannot load the rules from https-everywhere, + // since we cannot be sure if the stored mappings are correct anymore. + this._clear(); + if (this._canLoadRules) { + await this._loadRules(); + } + } + // If the timestamp is 0, that means the update channel was not yet updated, so + // we schedule a check soon. + this._rulesetTimeout = setTimeout( + () => this._periodicRulesetCheck(), + ts === 0 + ? _OnionAliasStore.RULESET_CHECK_INTERVAL_FAST + : _OnionAliasStore.RULESET_CHECK_INTERVAL + ); + } + + async init() { + this.httpsEverywhereControl = new HttpsEverywhereControl(); + + // Setup .tor.onion rule loading. + // The http observer is a fallback, and is removed in _loadRules() as soon as we are able + // to load some rules from HTTPS Everywhere. + this._loadHttpObserver(); + try { + await this.httpsEverywhereControl.installTorOnionUpdateChannel(); + this._updateChannelInstalled = true; + await this.httpsEverywhereControl.getTorOnionRules(); + this._canLoadRules = true; + } catch (e) { + // Loading rules did not work, probably because "get_simple_rules_ending_with" is not yet + // working in https-everywhere. Use an http observer as a fallback for learning the rules. + log.debug(`Could not load rules: ${e.message}`); + } + + // Setup checker for https-everywhere ruleset updates + if (this._updateChannelInstalled) { + this._periodicRulesetCheck(); + } + } + + /** + * Loads the .tor.onion mappings from https-everywhere. + */ + async _loadRules() { + const rules = await this.httpsEverywhereControl.getTorOnionRules(); + // Remove http observer if we are able to load some rules directly. + if (rules.length) { + this._removeObserver(); + this._removeObserver = () => {}; + } + this._clear(); + log.debug(`Loading ${rules.length} rules`, rules); + for (const rule of rules) { + // Here we are trusting that the securedrop ruleset follows some conventions so that we can + // assume there is a host mapping from `rule.host` to the hostname of the URL in `rule.to`. + try { + const url = new URL(rule.to); + const shortHost = rule.host; + const longHost = url.hostname; + this._addMapping(shortHost, longHost); + } catch (e) { + log.error("Could not process rule:", rule); + } + } + } + + /** + * Loads a http observer to listen for local redirects for populating + * the .tor.onion -> .onion mappings. Should only be used if we cannot ask https-everywhere + * directly for the mappings. + */ + _loadHttpObserver() { + this._removeObserver = observe("http-on-before-connect", channel => { + if ( + channel.isMainDocumentChannel && + channel.originalURI.host.endsWith(".tor.onion") + ) { + this._addMapping(channel.originalURI.host, channel.URI.host); + } + }); + } + + uninit() { + this._clear(); + this._removeObserver(); + this._removeObserver = () => {}; + if (this.httpsEverywhereControl) { + this.httpsEverywhereControl.unload(); + delete this.httpsEverywhereControl; + } + clearTimeout(this._rulesetTimeout); + this._rulesetTimeout = null; + this._rulesetTimestamp = null; + } + + _clear() { + this._onionMap.clear(); + } + + _addMapping(shortOnionHost, longOnionHost) { + this._onionMap.set(longOnionHost, shortOnionHost); + } + + getShortURI(onionURI) { + if ( + (onionURI.schemeIs("http") || onionURI.schemeIs("https")) && + this._onionMap.has(onionURI.host) + ) { + return onionURI + .mutate() + .setHost(this._onionMap.get(onionURI.host)) + .finalize(); + } + return null; + } +} + +let OnionAliasStore = new _OnionAliasStore(); diff --git a/browser/components/onionservices/moz.build b/browser/components/onionservices/moz.build index 2661ad7cb9f3..815685322024 100644 --- a/browser/components/onionservices/moz.build +++ b/browser/components/onionservices/moz.build @@ -1 +1,7 @@ JAR_MANIFESTS += ["jar.mn"] + +EXTRA_JS_MODULES += [ + "ExtensionMessaging.jsm", + "HttpsEverywhereControl.jsm", + "OnionAliasStore.jsm", +] diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm index e448f6f7ba83..827ea6f19128 100644 --- a/browser/components/urlbar/UrlbarInput.jsm +++ b/browser/components/urlbar/UrlbarInput.jsm @@ -330,7 +330,10 @@ class UrlbarInput { // bar if the user has deleted the URL and we'd just put the same URL // back. See bug 304198. if (value === null) { - uri = uri || this.window.gBrowser.currentURI; + uri = + uri || + this.window.gBrowser.selectedBrowser.currentOnionAliasURI || + this.window.gBrowser.currentURI; // Strip off usernames and passwords for the location bar try { uri = Services.io.createExposableURI(uri); @@ -2100,7 +2103,13 @@ class UrlbarInput { } let uri; - if (this.getAttribute("pageproxystate") == "valid") { + // When we rewrite .onion to an alias, gBrowser.currentURI will be different than + // the URI displayed in the urlbar. We need to use the urlbar value to copy the + // alias instead of the actual .onion URI that is loaded. + if ( + this.getAttribute("pageproxystate") == "valid" && + !this.window.gBrowser.selectedBrowser.currentOnionAliasURI + ) { uri = this.window.gBrowser.currentURI; } else { // The value could be: diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 94ceeb67f301..3f5c8eab97b3 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -5993,6 +5993,10 @@ void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, return; } + if (!mOnionUrlbarRewritesAllowed && IsTorOnionRedirect(oldURI, newURI)) { + mOnionUrlbarRewritesAllowed = true; + } + // DocumentChannel adds redirect chain to global history in the parent // process. The redirect chain can't be queried from the content process, so // there's no need to update global history here. @@ -9405,6 +9409,20 @@ static bool NavigationShouldTakeFocus(nsDocShell* aDocShell, return !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false); } +/* static */ +bool nsDocShell::IsTorOnionRedirect(nsIURI* aOldURI, nsIURI* aNewURI) { + nsAutoCString oldHost; + nsAutoCString newHost; + if (aOldURI && aNewURI && NS_SUCCEEDED(aOldURI->GetHost(oldHost)) && + StringEndsWith(oldHost, ".tor.onion"_ns) && + NS_SUCCEEDED(aNewURI->GetHost(newHost)) && + StringEndsWith(newHost, ".onion"_ns) && + !StringEndsWith(newHost, ".tor.onion"_ns)) { + return true; + } + return false; +} + nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, Maybe<uint32_t> aCacheKey) { MOZ_ASSERT(aLoadState, "need a load state!"); @@ -9558,6 +9576,30 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, mAllowKeywordFixup = aLoadState->HasInternalLoadFlags( INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP); + + if (mOnionUrlbarRewritesAllowed) { + mOnionUrlbarRewritesAllowed = false; + nsCOMPtr<nsIURI> referrer; + nsIReferrerInfo* referrerInfo = aLoadState->GetReferrerInfo(); + if (referrerInfo) { + referrerInfo->GetOriginalReferrer(getter_AddRefs(referrer)); + bool isPrivateWin = false; + Document* doc = GetDocument(); + if (doc) { + isPrivateWin = + doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0; + nsCOMPtr<nsIScriptSecurityManager> secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + mOnionUrlbarRewritesAllowed = + secMan && NS_SUCCEEDED(secMan->CheckSameOriginURI( + aLoadState->URI(), referrer, false, isPrivateWin)); + } + } + } + mOnionUrlbarRewritesAllowed = + mOnionUrlbarRewritesAllowed || + aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES); + mURIResultedInDocument = false; // reset the clock... // See if this is actually a load between two history entries for the same @@ -11916,6 +11958,7 @@ nsresult nsDocShell::AddToSessionHistory( HistoryID(), GetCreatedDynamically(), originalURI, resultPrincipalURI, loadReplace, referrerInfo, srcdoc, srcdocEntry, baseURI, saveLayoutState, expired, userActivation); + entry->SetOnionUrlbarRewritesAllowed(mOnionUrlbarRewritesAllowed); if (mBrowsingContext->IsTop() && GetSessionHistory()) { bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel); @@ -13815,3 +13858,12 @@ void nsDocShell::MaybeDisconnectChildListenersOnPageHide() { mChannelToDisconnectOnPageHide = 0; } } + +NS_IMETHODIMP +nsDocShell::GetOnionUrlbarRewritesAllowed(bool* aOnionUrlbarRewritesAllowed) { + NS_ENSURE_ARG(aOnionUrlbarRewritesAllowed); + *aOnionUrlbarRewritesAllowed = + StaticPrefs::browser_urlbar_onionRewrites_enabled() && + mOnionUrlbarRewritesAllowed; + return NS_OK; +} diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index fe61eda9267d..30f7fcfe1bbd 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -134,6 +134,9 @@ class nsDocShell final : public nsDocLoader, // Whether the load should go through LoadURIDelegate. INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE = 0x2000, + + // Whether rewriting the urlbar to a short .onion alias is allowed. + INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES = 0x4000, }; // Event type dispatched by RestorePresentation @@ -563,6 +566,8 @@ class nsDocShell final : public nsDocLoader, virtual void DestroyChildren() override; + static bool IsTorOnionRedirect(nsIURI* aOldURI, nsIURI* aNewURI); + // Overridden from nsDocLoader, this provides more information than the // normal OnStateChange with flags STATE_REDIRECTING virtual void OnRedirectStateChange(nsIChannel* aOldChannel, @@ -1254,6 +1259,7 @@ class nsDocShell final : public nsDocLoader, bool mCSSErrorReportingEnabled : 1; bool mAllowAuth : 1; bool mAllowKeywordFixup : 1; + bool mOnionUrlbarRewritesAllowed : 1; bool mDisableMetaRefreshWhenInactive : 1; bool mIsAppTab : 1; bool mDeviceSizeIsPageSize : 1; diff --git a/docshell/base/nsDocShellLoadState.cpp b/docshell/base/nsDocShellLoadState.cpp index 7122c2769119..5fb9f4aab2b5 100644 --- a/docshell/base/nsDocShellLoadState.cpp +++ b/docshell/base/nsDocShellLoadState.cpp @@ -847,6 +847,14 @@ void nsDocShellLoadState::CalculateLoadURIFlags() { mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD; } + if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES) { + mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES; + } + + if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) { + mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD; + } + if (mLoadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CLASSIFIER) { mInternalLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; } diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index dcf0b8c00d70..15887de5cbda 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -864,4 +864,9 @@ interface nsIDocShell : nsIDocShellTreeItem * until session history state is moved into the parent process. */ void persistLayoutHistoryState(); + + /** + * Whether rewriting the urlbar to a short .onion alias is allowed. + */ + [infallible] readonly attribute boolean onionUrlbarRewritesAllowed; }; diff --git a/docshell/base/nsIWebNavigation.idl b/docshell/base/nsIWebNavigation.idl index bec4f13d8b2b..98f3b6a2f9a3 100644 --- a/docshell/base/nsIWebNavigation.idl +++ b/docshell/base/nsIWebNavigation.idl @@ -268,6 +268,11 @@ interface nsIWebNavigation : nsISupports */ const unsigned long LOAD_FLAGS_USER_ACTIVATION = 0x8000000; + /** + * Allow rewriting the urlbar to a short .onion alias. + */ + const unsigned long LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES = 0x9000000; + /** * Loads a given URI. This will give priority to loading the requested URI * in the object implementing this interface. If it can't be loaded here diff --git a/docshell/shistory/SessionHistoryEntry.cpp b/docshell/shistory/SessionHistoryEntry.cpp index 61ec28bbb9be..9890c99b22dc 100644 --- a/docshell/shistory/SessionHistoryEntry.cpp +++ b/docshell/shistory/SessionHistoryEntry.cpp @@ -926,6 +926,20 @@ SessionHistoryEntry::SetPersist(bool aPersist) { return NS_OK; } +NS_IMETHODIMP +SessionHistoryEntry::GetOnionUrlbarRewritesAllowed( + bool* aOnionUrlbarRewritesAllowed) { + *aOnionUrlbarRewritesAllowed = mInfo->mOnionUrlbarRewritesAllowed; + return NS_OK; +} + +NS_IMETHODIMP +SessionHistoryEntry::SetOnionUrlbarRewritesAllowed( + bool aOnionUrlbarRewritesAllowed) { + mInfo->mOnionUrlbarRewritesAllowed = aOnionUrlbarRewritesAllowed; + return NS_OK; +} + NS_IMETHODIMP SessionHistoryEntry::GetScrollPosition(int32_t* aX, int32_t* aY) { *aX = mInfo->mScrollPositionX; diff --git a/docshell/shistory/SessionHistoryEntry.h b/docshell/shistory/SessionHistoryEntry.h index e74311578368..aa4c86f2a368 100644 --- a/docshell/shistory/SessionHistoryEntry.h +++ b/docshell/shistory/SessionHistoryEntry.h @@ -170,6 +170,7 @@ class SessionHistoryInfo { bool mPersist = true; bool mHasUserInteraction = false; bool mHasUserActivation = false; + bool mOnionUrlbarRewritesAllowed = false; union SharedState { SharedState(); diff --git a/docshell/shistory/nsISHEntry.idl b/docshell/shistory/nsISHEntry.idl index 73ac40551d4e..622402456d07 100644 --- a/docshell/shistory/nsISHEntry.idl +++ b/docshell/shistory/nsISHEntry.idl @@ -260,6 +260,11 @@ interface nsISHEntry : nsISupports */ [infallible] attribute boolean persist; + /** + * Whether rewriting the urlbar to a short .onion alias is allowed. + */ + [infallible] attribute boolean onionUrlbarRewritesAllowed; + /** * Set/Get the visual viewport scroll position if session history is * changed through anchor navigation or pushState. diff --git a/docshell/shistory/nsSHEntry.cpp b/docshell/shistory/nsSHEntry.cpp index 1e4000eacd2b..41ea6086df8b 100644 --- a/docshell/shistory/nsSHEntry.cpp +++ b/docshell/shistory/nsSHEntry.cpp @@ -44,7 +44,8 @@ nsSHEntry::nsSHEntry() mLoadedInThisProcess(false), mPersist(true), mHasUserInteraction(false), - mHasUserActivation(false) {} + mHasUserActivation(false), + mOnionUrlbarRewritesAllowed(false) {} nsSHEntry::nsSHEntry(const nsSHEntry& aOther) : mShared(aOther.mShared), @@ -72,7 +73,8 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther) mLoadedInThisProcess(aOther.mLoadedInThisProcess), mPersist(aOther.mPersist), mHasUserInteraction(false), - mHasUserActivation(aOther.mHasUserActivation) {} + mHasUserActivation(aOther.mHasUserActivation), + mOnionUrlbarRewritesAllowed(aOther.mOnionUrlbarRewritesAllowed) {} nsSHEntry::~nsSHEntry() { // Null out the mParent pointers on all our kids. @@ -880,6 +882,18 @@ nsSHEntry::SetPersist(bool aPersist) { return NS_OK; } +NS_IMETHODIMP +nsSHEntry::GetOnionUrlbarRewritesAllowed(bool* aOnionUrlbarRewritesAllowed) { + *aOnionUrlbarRewritesAllowed = mOnionUrlbarRewritesAllowed; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SetOnionUrlbarRewritesAllowed(bool aOnionUrlbarRewritesAllowed) { + mOnionUrlbarRewritesAllowed = aOnionUrlbarRewritesAllowed; + return NS_OK; +} + NS_IMETHODIMP nsSHEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) { nsCOMPtr<nsIURI> uri = GetURI(); @@ -929,6 +943,10 @@ nsSHEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) { } else { srcdoc = VoidString(); } + if (GetOnionUrlbarRewritesAllowed()) { + flags |= nsDocShell::InternalLoad:: + INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES; + } loadState->SetSrcdocData(srcdoc); loadState->SetBaseURI(baseURI); loadState->SetInternalLoadFlags(flags); diff --git a/docshell/shistory/nsSHEntry.h b/docshell/shistory/nsSHEntry.h index 326b0092cf94..76be0ac65050 100644 --- a/docshell/shistory/nsSHEntry.h +++ b/docshell/shistory/nsSHEntry.h @@ -66,6 +66,7 @@ class nsSHEntry : public nsISHEntry { bool mPersist; bool mHasUserInteraction; bool mHasUserActivation; + bool mOnionUrlbarRewritesAllowed; }; #endif /* nsSHEntry_h */ diff --git a/dom/interfaces/base/nsIBrowser.idl b/dom/interfaces/base/nsIBrowser.idl index 1a05957dba83..1c42486da87c 100644 --- a/dom/interfaces/base/nsIBrowser.idl +++ b/dom/interfaces/base/nsIBrowser.idl @@ -130,7 +130,8 @@ interface nsIBrowser : nsISupports in boolean aIsSynthetic, in boolean aHasRequestContextID, in uint64_t aRequestContextID, - in AString aContentType); + in AString aContentType, + in boolean aOnionUrlbarRewritesAllowed); /** * Determine what process switching behavior this browser element should have. diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index ce5e1ff14890..0830c22d0b5c 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -3621,6 +3621,8 @@ NS_IMETHODIMP BrowserChild::OnLocationChange(nsIWebProgress* aWebProgress, docShell->GetMayEnableCharacterEncodingMenu(); locationChangeData->charsetAutodetected() = docShell->GetCharsetAutodetected(); + locationChangeData->onionUrlbarRewritesAllowed() = + docShell->GetOnionUrlbarRewritesAllowed(); locationChangeData->contentPrincipal() = document->NodePrincipal(); locationChangeData->contentPartitionedPrincipal() = diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index 240b386f6dde..fd14908abc85 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -2794,7 +2794,8 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange( aLocationChangeData->isSyntheticDocument(), aLocationChangeData->requestContextID().isSome(), aLocationChangeData->requestContextID().valueOr(0), - aLocationChangeData->contentType()); + aLocationChangeData->contentType(), + aLocationChangeData->onionUrlbarRewritesAllowed()); } } diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 29433edcde78..4a0086a98c50 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -145,6 +145,7 @@ struct WebProgressLocationChangeData bool isSyntheticDocument; bool mayEnableCharacterEncodingMenu; bool charsetAutodetected; + bool onionUrlbarRewritesAllowed; nsString contentType; nsString title; nsString charset; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index cc155b47b645..238177c47894 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -1329,6 +1329,12 @@ value: true mirror: always + # Whether rewriting the urlbar to a short .onion alias is allowed. +- name: browser.urlbar.onionRewrites.enabled + type: RelaxedAtomicBool + value: true + mirror: always + - name: browser.viewport.desktopWidth type: RelaxedAtomicInt32 value: 980 diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index a91e02c54191..959773e54a1f 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -5518,6 +5518,8 @@ pro.om // onion : https://tools.ietf.org/html/rfc7686 onion +tor.onion +securedrop.tor.onion // org : https://en.wikipedia.org/wiki/.org org diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp index 27cc9939dc5f..7a6fddedd411 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp @@ -2522,6 +2522,16 @@ DocumentLoadListener::AsyncOnChannelRedirect( "mHaveVisibleRedirect=%c", this, mHaveVisibleRedirect ? 'T' : 'F')); + // Like the code above for allowing mixed content, we need to check this here + // in case the redirect is not handled in the docshell. + nsCOMPtr<nsIURI> oldURI, newURI; + aOldChannel->GetURI(getter_AddRefs(oldURI)); + aNewChannel->GetURI(getter_AddRefs(newURI)); + if (nsDocShell::IsTorOnionRedirect(oldURI, newURI)) { + mLoadStateInternalLoadFlags |= + nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES; + } + // We need the original URI of the current channel to use to open the real // channel in the content process. Unfortunately we overwrite the original // uri of the new channel with the original pre-redirect URI, so grab diff --git a/toolkit/content/widgets/browser-custom-element.js b/toolkit/content/widgets/browser-custom-element.js index 778cadd6b810..bcf622e70c65 100644 --- a/toolkit/content/widgets/browser-custom-element.js +++ b/toolkit/content/widgets/browser-custom-element.js @@ -255,6 +255,8 @@ this._mayEnableCharacterEncodingMenu = null; + this._onionUrlbarRewritesAllowed = false; + this._charsetAutodetected = false; this._contentPrincipal = null; @@ -615,6 +617,12 @@ } } + get onionUrlbarRewritesAllowed() { + return this.isRemoteBrowser + ? this._onionUrlbarRewritesAllowed + : this.docShell.onionUrlbarRewritesAllowed; + } + get charsetAutodetected() { return this.isRemoteBrowser ? this._charsetAutodetected @@ -1157,7 +1165,8 @@ aIsSynthetic, aHaveRequestContextID, aRequestContextID, - aContentType + aContentType, + aOnionUrlbarRewritesAllowed ) { if (this.isRemoteBrowser && this.messageManager) { if (aCharset != null) { @@ -1180,6 +1189,7 @@ this._contentRequestContextID = aHaveRequestContextID ? aRequestContextID : null; + this._onionUrlbarRewritesAllowed = aOnionUrlbarRewritesAllowed; } } @@ -1582,6 +1592,7 @@ "_contentPrincipal", "_contentPartitionedPrincipal", "_isSyntheticDocument", + "_onionUrlbarRewritesAllowed", ] ); } diff --git a/toolkit/modules/sessionstore/SessionHistory.jsm b/toolkit/modules/sessionstore/SessionHistory.jsm index 87af372acb79..a03eb85b938b 100644 --- a/toolkit/modules/sessionstore/SessionHistory.jsm +++ b/toolkit/modules/sessionstore/SessionHistory.jsm @@ -313,6 +313,7 @@ var SessionHistoryInternal = { } entry.persist = shEntry.persist; + entry.onionUrlbarRewritesAllowed = shEntry.onionUrlbarRewritesAllowed; return entry; }, @@ -607,6 +608,10 @@ var SessionHistoryInternal = { } } + if (entry.onionUrlbarRewritesAllowed) { + shEntry.onionUrlbarRewritesAllowed = entry.onionUrlbarRewritesAllowed; + } + return shEntry; }, diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h index efee881c1421..4295efb39f1f 100644 --- a/xpcom/reflect/xptinfo/xptinfo.h +++ b/xpcom/reflect/xptinfo/xptinfo.h @@ -514,7 +514,8 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size"); #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) # define PARAM_BUFFER_COUNT 18 #else -# define PARAM_BUFFER_COUNT 14 +// The max is currently updateForLocationChange in nsIBrowser.idl +# define PARAM_BUFFER_COUNT 15 #endif /**
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 32092: Fix Tor Browser Support link in preferences
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 385092dae42e23c60c97bd11634b74105e374fb1 Author: Alex Catarineu <acat(a)torproject.org> Date: Tue Oct 15 22:54:10 2019 +0200 Bug 32092: Fix Tor Browser Support link in preferences --- browser/components/preferences/preferences.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js index a89fddd0306d..ce338584142e 100644 --- a/browser/components/preferences/preferences.js +++ b/browser/components/preferences/preferences.js @@ -166,10 +166,7 @@ function init_all() { gotoPref().then(() => { let helpButton = document.getElementById("helpButton"); - let helpUrl = - Services.urlFormatter.formatURLPref("app.support.baseURL") + - "preferences"; - helpButton.setAttribute("href", helpUrl); + helpButton.setAttribute("href", "https://support.torproject.org/tbb"); document.getElementById("addonsButton").addEventListener("click", e => { if (e.button >= 2) {
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 21952: Implement Onion-Location
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 38f0abd191236b397121262f5248deb44b6b5bc7 Author: Alex Catarineu <acat(a)torproject.org> Date: Thu Mar 5 22:16:39 2020 +0100 Bug 21952: Implement Onion-Location Whenever a valid Onion-Location HTTP header (or corresponding HTML <meta> http-equiv attribute) is found in a document load, we either redirect to it (if the user opted-in via preference) or notify the presence of an onionsite alternative with a badge in the urlbar. --- browser/base/content/browser.js | 12 ++ browser/base/content/browser.xhtml | 3 + browser/components/BrowserGlue.jsm | 13 ++ .../onionservices/OnionLocationChild.jsm | 39 +++++ .../onionservices/OnionLocationParent.jsm | 168 +++++++++++++++++++++ .../content/onionlocation-notification-icons.css | 5 + .../onionservices/content/onionlocation-urlbar.css | 27 ++++ .../content/onionlocation-urlbar.inc.xhtml | 10 ++ .../onionservices/content/onionlocation.svg | 3 + .../content/onionlocationPreferences.inc.xhtml | 11 ++ .../content/onionlocationPreferences.js | 31 ++++ browser/components/onionservices/jar.mn | 2 + browser/components/onionservices/moz.build | 2 + browser/components/preferences/privacy.inc.xhtml | 2 + browser/components/preferences/privacy.js | 17 +++ browser/themes/shared/notification-icons.inc.css | 2 + browser/themes/shared/urlbar-searchbar.inc.css | 2 + dom/base/Document.cpp | 34 ++++- dom/base/Document.h | 2 + dom/webidl/Document.webidl | 8 + modules/libpref/init/StaticPrefList.yaml | 5 + xpcom/ds/StaticAtoms.py | 1 + 22 files changed, 398 insertions(+), 1 deletion(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 7103cd2c374b..a443220ba6e8 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -50,6 +50,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { NetUtil: "resource://gre/modules/NetUtil.jsm", NewTabUtils: "resource://gre/modules/NewTabUtils.jsm", OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm", + OnionLocationParent: "resource:///modules/OnionLocationParent.jsm", PageActions: "resource:///modules/PageActions.jsm", PageThumbs: "resource://gre/modules/PageThumbs.jsm", PanelMultiView: "resource:///modules/PanelMultiView.jsm", @@ -5310,6 +5311,7 @@ var XULBrowserWindow = { CFRPageActions.updatePageActions(gBrowser.selectedBrowser); AboutReaderParent.updateReaderButton(gBrowser.selectedBrowser); + OnionLocationParent.updateOnionLocationBadge(gBrowser.selectedBrowser); if (!gMultiProcessBrowser) { // Bug 1108553 - Cannot rotate images with e10s @@ -5800,6 +5802,16 @@ var CombinedStopReload = { var TabsProgressListener = { onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { + // Clear OnionLocation UI + if ( + aStateFlags & Ci.nsIWebProgressListener.STATE_START && + aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK && + aRequest && + aWebProgress.isTopLevel + ) { + OnionLocationParent.onStateChange(aBrowser); + } + // Collect telemetry data about tab load times. if ( aWebProgress.isTopLevel && diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index e4f3363e2180..5b64d914d414 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -2039,6 +2039,9 @@ onclick="FullZoom.reset(); FullZoom.resetScalingZoom();" tooltip="dynamic-shortcut-tooltip" hidden="true"/> + +#include ../../components/onionservices/content/onionlocation-urlbar.inc.xhtml + <hbox id="pageActionButton" class="urlbar-page-action urlbar-icon-wrapper" role="button" diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 5b320bd989f0..c23f926a2de2 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -546,6 +546,19 @@ let JSWINDOWACTORS = { allFrames: true, }, + OnionLocation: { + parent: { + moduleURI: "resource:///modules/OnionLocationParent.jsm", + }, + child: { + moduleURI: "resource:///modules/OnionLocationChild.jsm", + events: { + pageshow: { mozSystemGroup: true }, + }, + }, + messageManagerGroups: ["browsers"], + }, + PageInfo: { child: { moduleURI: "resource:///actors/PageInfoChild.jsm", diff --git a/browser/components/onionservices/OnionLocationChild.jsm b/browser/components/onionservices/OnionLocationChild.jsm new file mode 100644 index 000000000000..9e00054ac56c --- /dev/null +++ b/browser/components/onionservices/OnionLocationChild.jsm @@ -0,0 +1,39 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +var EXPORTED_SYMBOLS = ["OnionLocationChild"]; + +class OnionLocationChild extends JSWindowActorChild { + handleEvent(event) { + this.onPageShow(event); + } + + onPageShow(event) { + if (event.target != this.document) { + return; + } + const onionLocationURI = this.document.onionLocationURI; + if (onionLocationURI) { + this.sendAsyncMessage("OnionLocation:Set"); + } + } + + receiveMessage(aMessage) { + if (aMessage.name == "OnionLocation:Refresh") { + const doc = this.document; + const docShell = this.docShell; + const onionLocationURI = doc.onionLocationURI; + const refreshURI = docShell.QueryInterface(Ci.nsIRefreshURI); + if (onionLocationURI && refreshURI) { + refreshURI.refreshURI( + onionLocationURI, + doc.nodePrincipal, + 0, + false, + true + ); + } + } + } +} diff --git a/browser/components/onionservices/OnionLocationParent.jsm b/browser/components/onionservices/OnionLocationParent.jsm new file mode 100644 index 000000000000..f6250e554862 --- /dev/null +++ b/browser/components/onionservices/OnionLocationParent.jsm @@ -0,0 +1,168 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +var EXPORTED_SYMBOLS = ["OnionLocationParent"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); + +// Prefs +const NOTIFICATION_PREF = "privacy.prioritizeonions.showNotification"; +const PRIORITIZE_ONIONS_PREF = "privacy.prioritizeonions.enabled"; + +// Element IDs +const ONIONLOCATION_BOX_ID = "onion-location-box"; +const ONIONLOCATION_BUTTON_ID = "onion-location-button"; +const ONIONLOCATION_LABEL_ID = "onion-label"; + +// Notification IDs +const NOTIFICATION_ID = "onion-location"; +const NOTIFICATION_ANCHOR_ID = "onionlocation"; + +// Strings +const STRING_ONION_AVAILABLE = TorStrings.onionLocation.onionAvailable; +const NOTIFICATION_CANCEL_LABEL = TorStrings.onionLocation.notNow; +const NOTIFICATION_CANCEL_ACCESSKEY = TorStrings.onionLocation.notNowAccessKey; +const NOTIFICATION_OK_LABEL = TorStrings.onionLocation.alwaysPrioritize; +const NOTIFICATION_OK_ACCESSKEY = + TorStrings.onionLocation.alwaysPrioritizeAccessKey; +const NOTIFICATION_TITLE = TorStrings.onionLocation.tryThis; +const NOTIFICATION_DESCRIPTION = TorStrings.onionLocation.description; +const NOTIFICATION_LEARN_MORE_URL = TorStrings.onionLocation.learnMoreURL; + +class OnionLocationParent extends JSWindowActorParent { + // Listeners are added in BrowserGlue.jsm + receiveMessage(aMsg) { + switch (aMsg.name) { + case "OnionLocation:Set": + let browser = this.browsingContext.embedderElement; + OnionLocationParent.setOnionLocation(browser); + break; + } + } + + static buttonClick(event) { + if (event.button !== 0) { + return; + } + const win = event.target.ownerGlobal; + if (win.gBrowser) { + const browser = win.gBrowser.selectedBrowser; + OnionLocationParent.redirect(browser); + } + } + + static redirect(browser) { + let windowGlobal = browser.browsingContext.currentWindowGlobal; + let actor = windowGlobal.getActor("OnionLocation"); + if (actor) { + actor.sendAsyncMessage("OnionLocation:Refresh", {}); + OnionLocationParent.setDisabled(browser); + } + } + + static onStateChange(browser) { + delete browser._onionLocation; + OnionLocationParent.hideNotification(browser); + } + + static setOnionLocation(browser) { + browser._onionLocation = true; + let tabBrowser = browser.getTabBrowser(); + if (tabBrowser && browser === tabBrowser.selectedBrowser) { + OnionLocationParent.updateOnionLocationBadge(browser); + } + } + + static hideNotification(browser) { + const win = browser.ownerGlobal; + if (browser._onionLocationPrompt) { + win.PopupNotifications.remove(browser._onionLocationPrompt); + } + } + + static showNotification(browser) { + const mustShow = Services.prefs.getBoolPref(NOTIFICATION_PREF, true); + if (!mustShow) { + return; + } + + const win = browser.ownerGlobal; + Services.prefs.setBoolPref(NOTIFICATION_PREF, false); + + const mainAction = { + label: NOTIFICATION_OK_LABEL, + accessKey: NOTIFICATION_OK_ACCESSKEY, + callback() { + Services.prefs.setBoolPref(PRIORITIZE_ONIONS_PREF, true); + OnionLocationParent.redirect(browser); + win.openPreferences("privacy-onionservices"); + }, + }; + + const cancelAction = { + label: NOTIFICATION_CANCEL_LABEL, + accessKey: NOTIFICATION_CANCEL_ACCESSKEY, + callback: () => {}, + }; + + const options = { + autofocus: true, + persistent: true, + removeOnDismissal: false, + eventCallback(aTopic) { + if (aTopic === "removed") { + delete browser._onionLocationPrompt; + delete browser.onionpopupnotificationanchor; + } + }, + learnMoreURL: NOTIFICATION_LEARN_MORE_URL, + displayURI: { + hostPort: NOTIFICATION_TITLE, // This is hacky, but allows us to have a title without extra markup/css. + }, + hideClose: true, + popupIconClass: "onionlocation-notification-icon", + }; + + // A hacky way of setting the popup anchor outside the usual url bar icon box + // onionlocationpopupnotificationanchor comes from `${ANCHOR_ID}popupnotificationanchor` + // From https://searchfox.org/mozilla-esr68/rev/080f9ed47742644d2ff84f7aa0b10aea5c4… + browser.onionlocationpopupnotificationanchor = win.document.getElementById( + ONIONLOCATION_BUTTON_ID + ); + + browser._onionLocationPrompt = win.PopupNotifications.show( + browser, + NOTIFICATION_ID, + NOTIFICATION_DESCRIPTION, + NOTIFICATION_ANCHOR_ID, + mainAction, + [cancelAction], + options + ); + } + + static setEnabled(browser) { + const win = browser.ownerGlobal; + const label = win.document.getElementById(ONIONLOCATION_LABEL_ID); + label.textContent = STRING_ONION_AVAILABLE; + const elem = win.document.getElementById(ONIONLOCATION_BOX_ID); + elem.removeAttribute("hidden"); + } + + static setDisabled(browser) { + const win = browser.ownerGlobal; + const elem = win.document.getElementById(ONIONLOCATION_BOX_ID); + elem.setAttribute("hidden", true); + } + + static updateOnionLocationBadge(browser) { + if (browser._onionLocation) { + OnionLocationParent.setEnabled(browser); + OnionLocationParent.showNotification(browser); + } else { + OnionLocationParent.setDisabled(browser); + } + } +} diff --git a/browser/components/onionservices/content/onionlocation-notification-icons.css b/browser/components/onionservices/content/onionlocation-notification-icons.css new file mode 100644 index 000000000000..7c8a6d892c6f --- /dev/null +++ b/browser/components/onionservices/content/onionlocation-notification-icons.css @@ -0,0 +1,5 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +.onionlocation-notification-icon { + display: none; +} \ No newline at end of file diff --git a/browser/components/onionservices/content/onionlocation-urlbar.css b/browser/components/onionservices/content/onionlocation-urlbar.css new file mode 100644 index 000000000000..91cad5f178d1 --- /dev/null +++ b/browser/components/onionservices/content/onionlocation-urlbar.css @@ -0,0 +1,27 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ + +#onion-location-button { + list-style-image: url(chrome://browser/content/onionservices/onionlocation.svg); +} + +#onion-location-box { + border-radius: 3px; + background-color: #6200A4; + padding-left: 5px; + padding-right: 5px; + color: white; + -moz-context-properties: fill; + fill: white; +} + +#onion-location-box:hover { + background-color: #0060DF !important; +} + +toolbar[brighttext] #onion-location-box { + background-color: #9400ff; +} + +toolbar[brighttext] #onion-location-box:hover { + background-color: #0060DF !important; +} diff --git a/browser/components/onionservices/content/onionlocation-urlbar.inc.xhtml b/browser/components/onionservices/content/onionlocation-urlbar.inc.xhtml new file mode 100644 index 000000000000..b612a4236f3c --- /dev/null +++ b/browser/components/onionservices/content/onionlocation-urlbar.inc.xhtml @@ -0,0 +1,10 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<hbox id="onion-location-box" + class="urlbar-icon-wrapper urlbar-page-action" + role="button" + hidden="true" + onclick="OnionLocationParent.buttonClick(event);"> + <image id="onion-location-button" role="presentation"/> + <hbox id="onion-label-container"><label id="onion-label"/></hbox> +</hbox> diff --git a/browser/components/onionservices/content/onionlocation.svg b/browser/components/onionservices/content/onionlocation.svg new file mode 100644 index 000000000000..37f40ac1812f --- /dev/null +++ b/browser/components/onionservices/content/onionlocation.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="m8.016411 14.54499v-0.969784c3.071908-0.0089 5.559239-2.501304 5.559239-5.575429 0-3.073903-2.487331-5.566336-5.559239-5.575206v-0.9697843c3.607473 0.00909 6.528802 2.935521 6.528802 6.544991 0 3.609691-2.921329 6.536342-6.528802 6.545213zm0-3.394356c1.732661-0.0091 3.135111-1.415756 3.135111-3.150857 0-1.734878-1.402451-3.141542-3.135111-3.150634v-0.9695626c2.268448 0.00887 4.104895 1.849753 4.104895 4.120197 0 2.270666-1.836447 4.111549-4.104895 4.120419zm0-4.846926c0.9294227 0.00887 1.680545 0.7644289 1.680545 1.696069 0 0.9318627-0.7511226 1.687421-1.680545 1.696291zm-8.016411 1.696069c0 4.418473 3.581527 8.000222 8 8.000222 4.418251 0 8-3.581749 8-8.000222 0-4.418251-3.581749-7.999778-8-7.999778-4.418473 0-8 3.581527-8 7.999778z" /> +</svg> \ No newline at end of file diff --git a/browser/components/onionservices/content/onionlocationPreferences.inc.xhtml b/browser/components/onionservices/content/onionlocationPreferences.inc.xhtml new file mode 100644 index 000000000000..c285f403f99b --- /dev/null +++ b/browser/components/onionservices/content/onionlocationPreferences.inc.xhtml @@ -0,0 +1,11 @@ +# Copyright (c) 2020, The Tor Project, Inc. + +<groupbox id="onionServicesGroup" data-category="panePrivacy" data-subcategory="onionservices" hidden="true"> + <label><html:h2 id="onionServicesTitle"></html:h2></label> + <label><label class="tail-with-learn-more" id="prioritizeOnionsDesc"></label><label + class="learnMore" is="text-link" id="onionServicesLearnMore"></label></label> + <radiogroup id="prioritizeOnionsRadioGroup" aria-labelledby="prioritizeOnionsDesc" preference="privacy.prioritizeonions.enabled"> + <radio id="onionServicesRadioAlways" value="true"/> + <radio id="onionServicesRadioAsk" value="false"/> + </radiogroup> +</groupbox> diff --git a/browser/components/onionservices/content/onionlocationPreferences.js b/browser/components/onionservices/content/onionlocationPreferences.js new file mode 100644 index 000000000000..aa569b54721c --- /dev/null +++ b/browser/components/onionservices/content/onionlocationPreferences.js @@ -0,0 +1,31 @@ +// Copyright (c) 2020, The Tor Project, Inc. + +"use strict"; + +ChromeUtils.defineModuleGetter( + this, + "TorStrings", + "resource:///modules/TorStrings.jsm" +); + +const OnionLocationPreferences = { + init() { + document.getElementById("onionServicesTitle").textContent = + TorStrings.onionLocation.onionServicesTitle; + document.getElementById("prioritizeOnionsDesc").textContent = + TorStrings.onionLocation.prioritizeOnionsDescription; + const learnMore = document.getElementById("onionServicesLearnMore"); + learnMore.textContent = TorStrings.onionLocation.learnMore; + learnMore.href = TorStrings.onionLocation.learnMoreURL; + document.getElementById("onionServicesRadioAlways").label = + TorStrings.onionLocation.always; + document.getElementById("onionServicesRadioAsk").label = + TorStrings.onionLocation.askEverytime; + }, +}; + +Object.defineProperty(this, "OnionLocationPreferences", { + value: OnionLocationPreferences, + enumerable: true, + writable: false, +}); diff --git a/browser/components/onionservices/jar.mn b/browser/components/onionservices/jar.mn index 9d6ce88d1841..f45b16dc5d29 100644 --- a/browser/components/onionservices/jar.mn +++ b/browser/components/onionservices/jar.mn @@ -7,3 +7,5 @@ browser.jar: content/browser/onionservices/onionservices.css (content/onionservices.css) content/browser/onionservices/savedKeysDialog.js (content/savedKeysDialog.js) content/browser/onionservices/savedKeysDialog.xhtml (content/savedKeysDialog.xhtml) + content/browser/onionservices/onionlocationPreferences.js (content/onionlocationPreferences.js) + content/browser/onionservices/onionlocation.svg (content/onionlocation.svg) diff --git a/browser/components/onionservices/moz.build b/browser/components/onionservices/moz.build index 815685322024..8027233d65a6 100644 --- a/browser/components/onionservices/moz.build +++ b/browser/components/onionservices/moz.build @@ -4,4 +4,6 @@ EXTRA_JS_MODULES += [ "ExtensionMessaging.jsm", "HttpsEverywhereControl.jsm", "OnionAliasStore.jsm", + "OnionLocationChild.jsm", + "OnionLocationParent.jsm", ] diff --git a/browser/components/preferences/privacy.inc.xhtml b/browser/components/preferences/privacy.inc.xhtml index eb410c13a8cc..be629399bdb9 100644 --- a/browser/components/preferences/privacy.inc.xhtml +++ b/browser/components/preferences/privacy.inc.xhtml @@ -14,6 +14,8 @@ <html:h1 data-l10n-id="privacy-header"/> </hbox> +#include ../onionservices/content/onionlocationPreferences.inc.xhtml + <!-- Tracking / Content Blocking --> <groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" aria-describedby="contentBlockingDescription"> <label id="contentBlockingHeader"><html:h2 data-l10n-id="content-blocking-enhanced-tracking-protection"/></label> diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js index 0b1e28dfac92..290b22271807 100644 --- a/browser/components/preferences/privacy.js +++ b/browser/components/preferences/privacy.js @@ -93,6 +93,12 @@ XPCOMUtils.defineLazyScriptGetter( "chrome://browser/content/securitylevel/securityLevel.js" ); +XPCOMUtils.defineLazyScriptGetter( + this, + ["OnionLocationPreferences"], + "chrome://browser/content/onionservices/onionlocationPreferences.js" +); + XPCOMUtils.defineLazyServiceGetter( this, "listManager", @@ -169,6 +175,9 @@ Preferences.addAll([ // Do not track { id: "privacy.donottrackheader.enabled", type: "bool" }, + // Onion Location + { id: "privacy.prioritizeonions.enabled", type: "bool" }, + // Media { id: "media.autoplay.default", type: "int" }, @@ -330,6 +339,13 @@ var gPrivacyPane = { window.addEventListener("unload", unload); }, + /** + * Show the OnionLocation preferences UI + */ + _initOnionLocation() { + OnionLocationPreferences.init(); + }, + /** * Whether the prompt to restart Firefox should appear when changing the autostart pref. */ @@ -537,6 +553,7 @@ var gPrivacyPane = { this._initTrackingProtectionExtensionControl(); OnionServicesAuthPreferences.init(); this._initSecurityLevel(); + this._initOnionLocation(); Services.telemetry.setEventRecordingEnabled("pwmgr", true); diff --git a/browser/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css index 39eb59a04964..0312654b6bcf 100644 --- a/browser/themes/shared/notification-icons.inc.css +++ b/browser/themes/shared/notification-icons.inc.css @@ -536,3 +536,5 @@ border-radius: 50%; } } /** END not Proton **/ + +%include ../../components/onionservices/content/onionlocation-notification-icons.css diff --git a/browser/themes/shared/urlbar-searchbar.inc.css b/browser/themes/shared/urlbar-searchbar.inc.css index 89e77b8ce90a..dc608af4b7fa 100644 --- a/browser/themes/shared/urlbar-searchbar.inc.css +++ b/browser/themes/shared/urlbar-searchbar.inc.css @@ -904,3 +904,5 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after { opacity: 0.69; } } /*** END !proton ***/ + +%include ../../components/onionservices/content/onionlocation-urlbar.css diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index c0494f7ccc74..c5592ec6bcbd 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -2781,6 +2781,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup, // mDocumentURI. mDocumentBaseURI = nullptr; mChromeXHRDocBaseURI = nullptr; + mOnionLocationURI = nullptr; // Check if the current document is the top-level DevTools document. // For inner DevTools frames, mIsDevToolsDocument will be set when @@ -6498,6 +6499,22 @@ void Document::GetHeaderData(nsAtom* aHeaderField, nsAString& aData) const { } } +static bool IsValidOnionLocation(nsIURI* aDocumentURI, + nsIURI* aOnionLocationURI) { + bool isHttpish; + nsAutoCString host; + return aDocumentURI && aOnionLocationURI && + NS_SUCCEEDED(aDocumentURI->SchemeIs("https", &isHttpish)) && + isHttpish && NS_SUCCEEDED(aDocumentURI->GetAsciiHost(host)) && + !StringEndsWith(host, ".onion"_ns) && + ((NS_SUCCEEDED(aOnionLocationURI->SchemeIs("http", &isHttpish)) && + isHttpish) || + (NS_SUCCEEDED(aOnionLocationURI->SchemeIs("https", &isHttpish)) && + isHttpish)) && + NS_SUCCEEDED(aOnionLocationURI->GetAsciiHost(host)) && + StringEndsWith(host, ".onion"_ns); +} + void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) { if (!aHeaderField) { NS_ERROR("null headerField"); @@ -6572,6 +6589,21 @@ void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) { aHeaderField == nsGkAtoms::handheldFriendly) { mViewportType = Unknown; } + + if (aHeaderField == nsGkAtoms::headerOnionLocation && !aData.IsEmpty()) { + nsCOMPtr<nsIURI> onionURI; + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(onionURI), aData)) && + IsValidOnionLocation(Document::GetDocumentURI(), onionURI)) { + if (StaticPrefs::privacy_prioritizeonions_enabled()) { + nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer); + if (refresher) { + refresher->RefreshURI(onionURI, NodePrincipal(), 0, false, true); + } + } else { + mOnionLocationURI = onionURI; + } + } + } } void Document::TryChannelCharset(nsIChannel* aChannel, int32_t& aCharsetSource, @@ -10681,7 +10713,7 @@ void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) { static const char* const headers[] = { "default-style", "content-style-type", "content-language", "content-disposition", "refresh", "x-dns-prefetch-control", - "x-frame-options", + "x-frame-options", "onion-location", // add more http headers if you need // XXXbz don't add content-location support without reading bug // 238654 and its dependencies/dups first. diff --git a/dom/base/Document.h b/dom/base/Document.h index 619484ceb2d0..18c28e40ed76 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -3374,6 +3374,7 @@ class Document : public nsINode, void ReleaseCapture() const; void MozSetImageElement(const nsAString& aImageElementId, Element* aElement); nsIURI* GetDocumentURIObject() const; + nsIURI* GetOnionLocationURI() const { return mOnionLocationURI; } // Not const because all the fullscreen goop is not const const char* GetFullscreenError(CallerType); bool FullscreenEnabled(CallerType aCallerType) { @@ -4360,6 +4361,7 @@ class Document : public nsINode, nsCOMPtr<nsIURI> mChromeXHRDocURI; nsCOMPtr<nsIURI> mDocumentBaseURI; nsCOMPtr<nsIURI> mChromeXHRDocBaseURI; + nsCOMPtr<nsIURI> mOnionLocationURI; // The base domain of the document for third-party checks. nsCString mBaseDomain; diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index 23a8f6a038b2..a3d06fb8e4be 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -717,3 +717,11 @@ partial interface Document { [ChromeOnly] void setNotifyFormOrPasswordRemoved(boolean aShouldNotify); }; + +/** + * Extension to allows chrome JS to know whether the document has a valid + * Onion-Location that we could redirect to. + */ +partial interface Document { + [ChromeOnly] readonly attribute URI? onionLocationURI; +}; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 238177c47894..0c8ea070ed45 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -10296,6 +10296,11 @@ value: "" mirror: never +- name: privacy.prioritizeonions.enabled + type: RelaxedAtomicBool + value: false + mirror: always + #--------------------------------------------------------------------------- # Prefs starting with "prompts." #--------------------------------------------------------------------------- diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py index 0cc7799d4370..09a91aee3f2a 100644 --- a/xpcom/ds/StaticAtoms.py +++ b/xpcom/ds/StaticAtoms.py @@ -818,6 +818,7 @@ STATIC_ATOMS = [ Atom("oninputsourceschange", "oninputsourceschange"), Atom("oninstall", "oninstall"), Atom("oninvalid", "oninvalid"), + Atom("headerOnionLocation", "onion-location"), Atom("onkeydown", "onkeydown"), Atom("onkeypress", "onkeypress"), Atom("onkeyup", "onkeyup"),
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 24796 - Comment out excess permissions from GeckoView
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 9bc32b4360fc3d334a8184f5738610b05feed0e5 Author: Matthew Finkel <Matthew.Finkel(a)gmail.com> Date: Wed Apr 11 17:52:59 2018 +0000 Bug 24796 - Comment out excess permissions from GeckoView The GeckoView AndroidManifest.xml is not preprocessed unlike Fennec's manifest, so we can't use the ifdef preprocessor guards around the permissions we do not want. Commenting the permissions is the next-best-thing. --- .../android/geckoview/src/main/AndroidManifest.xml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/mobile/android/geckoview/src/main/AndroidManifest.xml b/mobile/android/geckoview/src/main/AndroidManifest.xml index a76b6a4754b6..7a2f30708fc3 100644 --- a/mobile/android/geckoview/src/main/AndroidManifest.xml +++ b/mobile/android/geckoview/src/main/AndroidManifest.xml @@ -6,20 +6,32 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.mozilla.geckoview"> +<!--#ifdef MOZ_ANDROID_NETWORK_STATE--> + <!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + --> +<!--#endif--> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> +<!--#ifdef MOZ_ANDROID_LOCATION--> + <!-- <uses-feature android:name="android.hardware.location" android:required="false"/> <uses-feature android:name="android.hardware.location.gps" android:required="false"/> + --> +<!--#endif--> <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> +<!--#ifdef MOZ_WEBRTC--> + <!-- TODO preprocess AndroidManifest.xml so that we can + conditionally include WebRTC permissions based on MOZ_WEBRTC. --> + <!-- <uses-feature android:name="android.hardware.camera" android:required="false"/> @@ -28,14 +40,16 @@ android:required="false"/> <uses-feature - android:name="android.hardware.audio.low_latency" + android:name="android.hardware.camera.any" android:required="false"/> <uses-feature - android:name="android.hardware.microphone" + android:name="android.hardware.audio.low_latency" android:required="false"/> <uses-feature - android:name="android.hardware.camera.any" + android:name="android.hardware.microphone" android:required="false"/> + --> +<!--#endif--> <!-- GeckoView requires OpenGL ES 2.0 --> <uses-feature
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 33342: Avoid disconnect search addon error after removal.
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 1e8101b9b67f3bef398b02845fdd59423b5902a9 Author: Alex Catarineu <acat(a)torproject.org> Date: Fri Mar 13 18:19:30 2020 +0100 Bug 33342: Avoid disconnect search addon error after removal. We removed the addon in #32767, but it was still being loaded from addonStartup.json.lz4 and throwing an error on startup because its resource: location is not available anymore. --- toolkit/mozapps/extensions/internal/XPIProvider.jsm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 939dd6a70b24..ddf6f0049054 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -959,6 +959,12 @@ var BuiltInLocation = new (class _BuiltInLocation extends XPIStateLocation { isLinkedAddon(/* aId */) { return false; } + + restore(saved) { + super.restore(saved); + // Bug 33342: avoid restoring disconnect addon from addonStartup.json.lz4. + this.removeAddon("disconnect(a)search.mozilla.org"); + } })(); /**
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 32418: Allow updates to be disabled via an enterprise policy.
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 363379b7b4fbdc6811879ca6583f7a8352e3ef0a Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Thu Apr 16 17:07:09 2020 -0400 Bug 32418: Allow updates to be disabled via an enterprise policy. Restrict the Enterprise Policies mechanism to only consult a policies.json file (avoiding the Windows Registry and macOS's file system attributes). Add a few disabledByPolicy() checks to the update service to avoid extraneous (and potentially confusing) log messages when updates are disabled by policy. Sample content for distribution/policies.json: { "policies": { "DisableAppUpdate": true } } On Linux, avoid reading policies from /etc/firefox/policies/policies.json --- .../enterprisepolicies/EnterprisePoliciesParent.jsm | 14 ++++++++++++-- toolkit/components/enterprisepolicies/moz.build | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm index 775144e8a649..9fe916236cbc 100644 --- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm +++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm @@ -4,6 +4,10 @@ var EXPORTED_SYMBOLS = ["EnterprisePoliciesManager"]; +// To ensure that policies intended for Firefox or another browser will not +// be used, Tor Browser only looks for policies in ${InstallDir}/distribution +#define AVOID_SYSTEM_POLICIES MOZ_PROXY_BYPASS_PROTECTION + const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); @@ -13,9 +17,11 @@ const { AppConstants } = ChromeUtils.import( ); XPCOMUtils.defineLazyModuleGetters(this, { +#ifndef AVOID_SYSTEM_POLICIES WindowsGPOParser: "resource://gre/modules/policies/WindowsGPOParser.jsm", macOSPoliciesParser: "resource://gre/modules/policies/macOSPoliciesParser.jsm", +#endif Policies: "resource:///modules/policies/Policies.jsm", JsonSchemaValidator: "resource://gre/modules/components-utils/JsonSchemaValidator.jsm", @@ -140,11 +146,13 @@ EnterprisePoliciesManager.prototype = { _chooseProvider() { let platformProvider = null; +#ifndef AVOID_SYSTEM_POLICIES if (AppConstants.platform == "win") { platformProvider = new WindowsGPOPoliciesProvider(); } else if (AppConstants.platform == "macosx") { platformProvider = new macOSPoliciesProvider(); } +#endif let jsonProvider = new JSONPoliciesProvider(); if (platformProvider && platformProvider.hasPolicies) { if (jsonProvider.hasPolicies) { @@ -491,7 +499,7 @@ class JSONPoliciesProvider { _getConfigurationFile() { let configFile = null; - +#ifndef AVOID_SYSTEM_POLICIES if (AppConstants.platform == "linux") { let systemConfigFile = Cc["@mozilla.org/file/local;1"].createInstance( Ci.nsIFile @@ -504,7 +512,7 @@ class JSONPoliciesProvider { return systemConfigFile; } } - +#endif try { let perUserPath = Services.prefs.getBoolPref(PREF_PER_USER_DIR, false); if (perUserPath) { @@ -585,6 +593,7 @@ class JSONPoliciesProvider { } } +#ifndef AVOID_SYSTEM_POLICIES class WindowsGPOPoliciesProvider { constructor() { this._policies = null; @@ -686,3 +695,4 @@ class CombinedProvider { return false; } } +#endif diff --git a/toolkit/components/enterprisepolicies/moz.build b/toolkit/components/enterprisepolicies/moz.build index 09d2046e1bd7..3f685d3fbbd6 100644 --- a/toolkit/components/enterprisepolicies/moz.build +++ b/toolkit/components/enterprisepolicies/moz.build @@ -19,6 +19,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] != "android": EXTRA_JS_MODULES += [ "EnterprisePolicies.jsm", "EnterprisePoliciesContent.jsm", + ] + + EXTRA_PP_JS_MODULES += [ "EnterprisePoliciesParent.jsm", ]
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 25741 - TBA: Disable GeckoNetworkManager
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit ff0ec87a117064f786d15c60001209bc61328e89 Author: Matthew Finkel <Matthew.Finkel(a)gmail.com> Date: Thu Apr 26 22:22:51 2018 +0000 Bug 25741 - TBA: Disable GeckoNetworkManager The browser should not need information related to the network interface or network state, tor should take care of that. --- .../src/main/java/org/mozilla/geckoview/GeckoRuntime.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java index f084b522ad53..b94d8e803b6b 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java @@ -122,7 +122,9 @@ public final class GeckoRuntime implements Parcelable { mPaused = false; // Monitor network status and send change notifications to Gecko // while active. - GeckoNetworkManager.getInstance().start(GeckoAppShell.getApplicationContext()); + if (BuildConfig.TOR_BROWSER_VERSION == "") { + GeckoNetworkManager.getInstance().start(GeckoAppShell.getApplicationContext()); + } } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @@ -130,7 +132,9 @@ public final class GeckoRuntime implements Parcelable { Log.d(LOGTAG, "Lifecycle: onPause"); mPaused = true; // Stop monitoring network status while inactive. - GeckoNetworkManager.getInstance().stop(); + if (BuildConfig.TOR_BROWSER_VERSION == "") { + GeckoNetworkManager.getInstance().stop(); + } GeckoThread.onPause(); } }
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Orfox: Centralized proxy applied to AbstractCommunicator and BaseResources.
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit c605c1576c1eeb44a290d2ade2f9dc5ff80481f4 Author: Amogh Pradeep <amoghbl1(a)gmail.com> Date: Fri Jun 12 02:07:45 2015 -0400 Orfox: Centralized proxy applied to AbstractCommunicator and BaseResources. See Bug 1357997 for partial uplift. Also: Bug 28051 - Use our Orbot for proxying our connections Bug 31144 - ESR68 Network Code Review --- .../java/org/mozilla/gecko/util/ProxySelector.java | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java index dbd07a069de1..800c7cf96de8 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java @@ -29,6 +29,10 @@ import java.net.URLConnection; import java.util.List; public class ProxySelector { + private static final String TOR_PROXY_ADDRESS = "127.0.0.1"; + private static final int TOR_SOCKS_PROXY_PORT = 9150; + private static final int TOR_HTTP_PROXY_PORT = 8218; + public static URLConnection openConnectionWithProxy(final URI uri) throws IOException { final java.net.ProxySelector ps = java.net.ProxySelector.getDefault(); Proxy proxy = Proxy.NO_PROXY; @@ -39,7 +43,26 @@ public class ProxySelector { } } - return uri.toURL().openConnection(proxy); + /* Ignore the proxy we found from the VM, only use Tor. We can probably + * safely use the logic in this class in the future. */ + return uri.toURL().openConnection(getProxy()); + } + + public static Proxy getProxy() { + // TODO make configurable + return new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(TOR_PROXY_ADDRESS, TOR_SOCKS_PROXY_PORT)); + } + + public static String getProxyHostAddress() { + return TOR_PROXY_ADDRESS; + } + + public static int getSocksProxyPort() { + return TOR_SOCKS_PROXY_PORT; + } + + public static int getHttpProxyPort() { + return TOR_HTTP_PROXY_PORT; } public ProxySelector() {
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 28125 - Prevent non-Necko network connections
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 11b5ade88fa278a29ce23a621cd7ad11b7412b5e Author: Matthew Finkel <Matthew.Finkel(a)gmail.com> Date: Thu Oct 25 19:17:09 2018 +0000 Bug 28125 - Prevent non-Necko network connections --- .../gecko/media/GeckoMediaDrmBridgeV21.java | 49 +--------------------- .../exoplayer2/upstream/DefaultHttpDataSource.java | 47 ++------------------- 2 files changed, 4 insertions(+), 92 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridgeV21.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridgeV21.java index 6e75e6fb4dd5..7faa9bc2821d 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridgeV21.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoMediaDrmBridgeV21.java @@ -490,54 +490,7 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm { @Override protected Void doInBackground(final Void... params) { - HttpURLConnection urlConnection = null; - BufferedReader in = null; - try { - final URI finalURI = new URI(mURL + "&signedRequest=" + URLEncoder.encode(new String(mDrmRequest), "UTF-8")); - urlConnection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(finalURI); - urlConnection.setRequestMethod("POST"); - if (DEBUG) Log.d(LOGTAG, "Provisioning, posting url =" + finalURI.toString()); - - // Add data - urlConnection.setRequestProperty("Accept", "*/*"); - urlConnection.setRequestProperty("User-Agent", getCDMUserAgent()); - urlConnection.setRequestProperty("Content-Type", "application/json"); - - // Execute HTTP Post Request - urlConnection.connect(); - - final int responseCode = urlConnection.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), UTF_8)); - String inputLine; - final StringBuffer response = new StringBuffer(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - mResponseBody = String.valueOf(response).getBytes(UTF_8); - if (DEBUG) Log.d(LOGTAG, "Provisioning, response received."); - if (mResponseBody != null) Log.d(LOGTAG, "response length=" + mResponseBody.length); - } else { - Log.d(LOGTAG, "Provisioning, server returned HTTP error code :" + responseCode); - } - } catch (final IOException e) { - Log.e(LOGTAG, "Got exception during posting provisioning request ...", e); - } catch (final URISyntaxException e) { - Log.e(LOGTAG, "Got exception during creating uri ...", e); - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - try { - if (in != null) { - in.close(); - } - } catch (final IOException e) { - Log.e(LOGTAG, "Exception during closing in ...", e); - } - } + Log.i(LOGTAG, "This is Tor Browser. Skipping."); return null; } diff --git a/mobile/android/geckoview/src/thirdparty/java/org/mozilla/thirdparty/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java b/mobile/android/geckoview/src/thirdparty/java/org/mozilla/thirdparty/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java index 6e5095b0a4c9..a585e283ed4e 100644 --- a/mobile/android/geckoview/src/thirdparty/java/org/mozilla/thirdparty/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java +++ b/mobile/android/geckoview/src/thirdparty/java/org/mozilla/thirdparty/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java @@ -46,6 +46,7 @@ import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import org.mozilla.gecko.util.ProxySelector; + /** * An {@link HttpDataSource} that uses Android's {@link HttpURLConnection}. * @@ -516,50 +517,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou boolean followRedirects, Map<String, String> requestParameters) throws IOException, URISyntaxException { - /** - * Tor Project modified the way the connection object was created. For the sake of - * simplicity, instead of duplicating the whole file we changed the connection object - * to use the ProxySelector. - */ - HttpURLConnection connection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(url.toURI()); - - connection.setConnectTimeout(connectTimeoutMillis); - connection.setReadTimeout(readTimeoutMillis); - - Map<String, String> requestHeaders = new HashMap<>(); - if (defaultRequestProperties != null) { - requestHeaders.putAll(defaultRequestProperties.getSnapshot()); - } - requestHeaders.putAll(requestProperties.getSnapshot()); - requestHeaders.putAll(requestParameters); - - for (Map.Entry<String, String> property : requestHeaders.entrySet()) { - connection.setRequestProperty(property.getKey(), property.getValue()); - } - - if (!(position == 0 && length == C.LENGTH_UNSET)) { - String rangeRequest = "bytes=" + position + "-"; - if (length != C.LENGTH_UNSET) { - rangeRequest += (position + length - 1); - } - connection.setRequestProperty("Range", rangeRequest); - } - connection.setRequestProperty("User-Agent", userAgent); - connection.setRequestProperty("Accept-Encoding", allowGzip ? "gzip" : "identity"); - connection.setInstanceFollowRedirects(followRedirects); - connection.setDoOutput(httpBody != null); - connection.setRequestMethod(DataSpec.getStringForHttpMethod(httpMethod)); - - if (httpBody != null) { - connection.setFixedLengthStreamingMode(httpBody.length); - connection.connect(); - OutputStream os = connection.getOutputStream(); - os.write(httpBody); - os.close(); - } else { - connection.connect(); - } - return connection; + Log.i(TAG, "This is Tor Browser. Skipping."); + throw new IOException(); } /** Creates an {@link HttpURLConnection} that is connected with the {@code url}. */
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 40073: Disable remote Public Suffix List fetching
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit bbcf5b561d5179f798436a83bd9ac0fe9e09ddea Author: Alex Catarineu <acat(a)torproject.org> Date: Thu Aug 13 11:05:03 2020 +0200 Bug 40073: Disable remote Public Suffix List fetching In https://bugzilla.mozilla.org/show_bug.cgi?id=1563246 Firefox implemented fetching the Public Suffix List via RemoteSettings and replacing the default one at runtime, which we do not want. --- browser/components/BrowserGlue.jsm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index c23f926a2de2..e2e710237f47 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -71,7 +71,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { PluralForm: "resource://gre/modules/PluralForm.jsm", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm", - PublicSuffixList: "resource://gre/modules/netwerk-dns/PublicSuffixList.jsm", RemoteSettings: "resource://services-settings/remote-settings.js", RemoteSecuritySettings: "resource://gre/modules/psm/RemoteSecuritySettings.jsm", @@ -2650,10 +2649,6 @@ BrowserGlue.prototype = { this._addBreachesSyncHandler(); }, - () => { - PublicSuffixList.init(); - }, - () => { RemoteSecuritySettings.init(); },
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 33852: Clean up about:logins (LockWise) to avoid mentioning sync, etc.
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit ccef1242747b3f27eccec2a2fe8fead4b2ec9c4e Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Jul 14 11:15:07 2020 -0400 Bug 33852: Clean up about:logins (LockWise) to avoid mentioning sync, etc. Hide elements on about:logins that mention sync, "Firefox LockWise", and Mozilla's LockWise mobile apps. Disable the "Create New Login" button when security.nocertdb is true. --- browser/components/aboutlogins/AboutLoginsParent.jsm | 2 ++ browser/components/aboutlogins/content/aboutLogins.css | 8 +++++++- browser/components/aboutlogins/content/aboutLogins.js | 6 ++++++ .../aboutlogins/content/components/fxaccounts-button.css | 5 +++++ .../components/aboutlogins/content/components/menu-button.css | 10 ++++++++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/browser/components/aboutlogins/AboutLoginsParent.jsm b/browser/components/aboutlogins/AboutLoginsParent.jsm index db0b55d26abc..39fd2356ce99 100644 --- a/browser/components/aboutlogins/AboutLoginsParent.jsm +++ b/browser/components/aboutlogins/AboutLoginsParent.jsm @@ -61,6 +61,7 @@ XPCOMUtils.defineLazyGetter(this, "AboutLoginsL10n", () => { const ABOUT_LOGINS_ORIGIN = "about:logins"; const MASTER_PASSWORD_NOTIFICATION_ID = "master-password-login-required"; +const NOCERTDB_PREF = "security.nocertdb"; // about:logins will always use the privileged content process, // even if it is disabled for other consumers such as about:newtab. @@ -273,6 +274,7 @@ class AboutLoginsParent extends JSWindowActorParent { importVisible: Services.policies.isAllowed("profileImport") && AppConstants.platform != "linux", + canCreateLogins: !Services.prefs.getBoolPref(NOCERTDB_PREF, false), }); await AboutLogins._sendAllLoginRelatedObjects( diff --git a/browser/components/aboutlogins/content/aboutLogins.css b/browser/components/aboutlogins/content/aboutLogins.css index e3528ca49b84..eaa224178487 100644 --- a/browser/components/aboutlogins/content/aboutLogins.css +++ b/browser/components/aboutlogins/content/aboutLogins.css @@ -69,6 +69,11 @@ login-item { grid-area: login; } +/* Do not promote Mozilla Sync in Tor Browser. */ +login-intro { + display: none !important; +} + #branding-logo { flex-basis: var(--sidebar-width); flex-shrink: 0; @@ -83,7 +88,8 @@ login-item { } } -:root:not(.official-branding) #branding-logo { +/* Hide "Firefox LockWise" branding in Tor Browser. */ +#branding-logo { visibility: hidden; } diff --git a/browser/components/aboutlogins/content/aboutLogins.js b/browser/components/aboutlogins/content/aboutLogins.js index a7449f8343b3..f288fb6988fb 100644 --- a/browser/components/aboutlogins/content/aboutLogins.js +++ b/browser/components/aboutlogins/content/aboutLogins.js @@ -22,6 +22,9 @@ const gElements = { ".menuitem-remove-all-logins" ); }, + get createNewLoginButton() { + return this.loginList.shadowRoot.querySelector(".create-login-button"); + }, }; let numberOfLogins = 0; @@ -111,6 +114,9 @@ window.addEventListener("AboutLoginsChromeToContent", event => { gElements.loginList.setSortDirection(event.detail.value.selectedSort); document.documentElement.classList.add("initialized"); gElements.loginList.classList.add("initialized"); + if (!event.detail.value.canCreateLogins) { + gElements.createNewLoginButton.disabled = true; + } break; } case "ShowLoginItemError": { diff --git a/browser/components/aboutlogins/content/components/fxaccounts-button.css b/browser/components/aboutlogins/content/components/fxaccounts-button.css index c8925f6fc75d..55c2a8810fa1 100644 --- a/browser/components/aboutlogins/content/components/fxaccounts-button.css +++ b/browser/components/aboutlogins/content/components/fxaccounts-button.css @@ -8,6 +8,11 @@ align-items: center; } +/* Do not promote Mozilla Sync in Tor Browser. */ +.logged-out-view { + display: none !important; +} + .fxaccounts-extra-text { /* Only show at most 3 lines of text to limit the text from overflowing the header. */ diff --git a/browser/components/aboutlogins/content/components/menu-button.css b/browser/components/aboutlogins/content/components/menu-button.css index 6bc14f7892fa..22a06e3727ed 100644 --- a/browser/components/aboutlogins/content/components/menu-button.css +++ b/browser/components/aboutlogins/content/components/menu-button.css @@ -91,3 +91,13 @@ .menuitem-preferences { background-image: url("chrome://global/skin/icons/settings.svg"); } + +/* + * Do not promote LockWise mobile apps in Tor Browser: hide the menu items + * and the separator line that precedes them. + */ +.menuitem-mobile-android, +.menuitem-mobile-ios, +button[data-event-name="AboutLoginsGetHelp"] + hr { + display: none !important; +}
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 40025: Remove Mozilla add-on install permissions
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 05956dd87eff2b6b232ecd7e7c0b7002b2cd5ad4 Author: Alex Catarineu <acat(a)torproject.org> Date: Mon Jul 27 18:12:55 2020 +0200 Bug 40025: Remove Mozilla add-on install permissions --- browser/app/permissions | 5 ----- 1 file changed, 5 deletions(-) diff --git a/browser/app/permissions b/browser/app/permissions index b75b839e366b..d8439d49346b 100644 --- a/browser/app/permissions +++ b/browser/app/permissions @@ -12,11 +12,6 @@ origin uitour 1 https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ origin uitour 1 about:tor -# XPInstall -origin install 1 https://addons.mozilla.org - # Remote troubleshooting origin remote-troubleshooting 1 https://support.mozilla.org -# addon install -origin install 1 https://fpn.firefox.com
1 0
0 0
[tor-browser/tor-browser-90.0-11.0-1] Bug 40091: Load HTTPS Everywhere as a builtin addon in desktop
by boklm@torproject.org 14 Jul '21

14 Jul '21
commit 808305b9c3cf0b1442d7dd80d0e4f7a720094d9b Author: Alex Catarineu <acat(a)torproject.org> Date: Fri Sep 4 12:34:35 2020 +0200 Bug 40091: Load HTTPS Everywhere as a builtin addon in desktop This loads HTTPS Everywhere as a builtin addon from a hardcoded resource:// URI in desktop. It also ensures that the non-builtin HTTPS Everywhere addon is always uninstalled on browser startup. The reason of making this desktop-only is that there are some issues when installing a builtin extension from geckoview side, making the extension not available on first startup. So, at least for now we handle the Fenix case separately. See #40118 for a followup for investigating these. --- browser/components/BrowserGlue.jsm | 37 ++++++++++++++++++++++ toolkit/components/extensions/Extension.jsm | 10 ++++-- .../mozapps/extensions/internal/XPIProvider.jsm | 13 ++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index e2e710237f47..dd4ba916313d 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -45,6 +45,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { DownloadsViewableInternally: "resource:///modules/DownloadsViewableInternally.jsm", E10SUtils: "resource://gre/modules/E10SUtils.jsm", + ExtensionData: "resource://gre/modules/Extension.jsm", ExtensionsUI: "resource:///modules/ExtensionsUI.jsm", FeatureGate: "resource://featuregates/FeatureGate.jsm", FirefoxMonitor: "resource:///modules/FirefoxMonitor.jsm", @@ -121,6 +122,13 @@ XPCOMUtils.defineLazyServiceGetters(this, { PushService: ["@mozilla.org/push/Service;1", "nsIPushService"], }); +XPCOMUtils.defineLazyServiceGetters(this, { + resProto: [ + "@mozilla.org/network/protocol;1?name=resource", + "nsISubstitutingProtocolHandler", + ], +}); + const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; /** @@ -1383,6 +1391,35 @@ BrowserGlue.prototype = { "resource://builtin-themes/alpenglow/" ); + // Install https-everywhere builtin addon if needed. + (async () => { + const HTTPS_EVERYWHERE_ID = "https-everywhere-eff(a)eff.org"; + const HTTPS_EVERYWHERE_BUILTIN_URL = + "resource://torbutton/content/extensions/https-everywhere/"; + // This does something similar as GeckoViewWebExtension.jsm: it tries + // to load the manifest to retrieve the version of the builtin and + // compares it to the currently installed one to see whether we need + // to install or not. Here we delegate that to + // AddonManager.maybeInstallBuiltinAddon. + try { + const resolvedURI = Services.io.newURI( + resProto.resolveURI(Services.io.newURI(HTTPS_EVERYWHERE_BUILTIN_URL)) + ); + const extensionData = new ExtensionData(resolvedURI); + const manifest = await extensionData.loadManifest(); + + await AddonManager.maybeInstallBuiltinAddon( + HTTPS_EVERYWHERE_ID, + manifest.version, + HTTPS_EVERYWHERE_BUILTIN_URL + ); + } catch (e) { + const log = Log.repository.getLogger("HttpsEverywhereBuiltinLoader"); + log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); + log.error("Could not install https-everywhere extension", e); + } + })(); + if (AppConstants.MOZ_NORMANDY) { Normandy.init(); } diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm index 96054179fc3f..eb85fcf0390a 100644 --- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -226,6 +226,7 @@ const LOGGER_ID_BASE = "addons.webextension."; const UUID_MAP_PREF = "extensions.webextensions.uuids"; const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall"; const LEAVE_UUID_PREF = "extensions.webextensions.keepUuidOnUninstall"; +const PERSISTENT_EXTENSIONS = new Set(["https-everywhere-eff(a)eff.org"]); const COMMENT_REGEXP = new RegExp( String.raw` @@ -372,7 +373,8 @@ var ExtensionAddonObserver = { ); } - if (!Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false)) { + if (!Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false) && + !PERSISTENT_EXTENSIONS.has(addon.id)) { // Clear browser.storage.local backends. AsyncShutdown.profileChangeTeardown.addBlocker( `Clear Extension Storage ${addon.id} (File Backend)`, @@ -420,7 +422,8 @@ var ExtensionAddonObserver = { ExtensionPermissions.removeAll(addon.id); - if (!Services.prefs.getBoolPref(LEAVE_UUID_PREF, false)) { + if (!Services.prefs.getBoolPref(LEAVE_UUID_PREF, false) && + !PERSISTENT_EXTENSIONS.has(addon.id)) { // Clear the entry in the UUID map UUIDMap.remove(addon.id); } @@ -2637,7 +2640,8 @@ class Extension extends ExtensionData { ); } else if ( this.startupReason === "ADDON_INSTALL" && - !Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false) + !Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false) && + !PERSISTENT_EXTENSIONS.has(this.id) ) { // If the extension has been just installed, set it as migrated, // because there will not be any data to migrate. diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index ddf6f0049054..d4858412e486 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -1501,6 +1501,19 @@ var XPIStates = { continue; } + // Uninstall HTTPS Everywhere if it is installed in the user profile. + if ( + id === "https-everywhere-eff(a)eff.org" && + loc.name === KEY_APP_PROFILE + ) { + logger.debug( + "Uninstalling the HTTPS Everywhere extension from user profile." + ); + loc.installer.uninstallAddon(id); + changed = true; + continue; + } + let xpiState = loc.get(id); if (!xpiState) { // If the location is not supported for sideloading, skip new
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • ...
  • 746
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.