tbb-commits
Threads by month
- ----- 2025 -----
- 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
April 2020
- 4 participants
- 109 discussions

[tor-browser-build/master] Bug 33630: Remove noisebridge01 default bridge.
by boklm@torproject.org 03 Apr '20
by boklm@torproject.org 03 Apr '20
03 Apr '20
commit d479aea502e0ad734f7b31549bdb41a8d20d3251
Author: Philipp Winter <phw(a)nymity.ch>
Date: Mon Mar 16 16:39:33 2020 -0700
Bug 33630: Remove noisebridge01 default bridge.
This bridge has been unmaintained for quite a while, so it's time to
remove it.
This fixes <https://bugs.torproject.org/33630>.
---
.../tor-browser/Bundle-Data/PTConfigs/bridge_prefs.js | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/projects/tor-browser/Bundle-Data/PTConfigs/bridge_prefs.js b/projects/tor-browser/Bundle-Data/PTConfigs/bridge_prefs.js
index a87aa58..282e56f 100644
--- a/projects/tor-browser/Bundle-Data/PTConfigs/bridge_prefs.js
+++ b/projects/tor-browser/Bundle-Data/PTConfigs/bridge_prefs.js
@@ -9,15 +9,14 @@ pref("extensions.torlauncher.default_bridge.obfs4.4", "obfs4 37.218.240.34:40035
pref("extensions.torlauncher.default_bridge.obfs4.5", "obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0");
pref("extensions.torlauncher.default_bridge.obfs4.6", "obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0");
pref("extensions.torlauncher.default_bridge.obfs4.7", "obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.8", "obfs4 216.252.162.21:46089 0DB8799466902192B6C7576D58D4F7F714EC87C1 cert=XPUwcQPxEXExHfJYX58gZXN7mYpos7VNAHbkgERNFg+FCVNzuYo1Wp+uMscl3aR9hO2DRQ iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.9", "obfs4 144.217.20.138:80 FB70B257C162BF1038CA669D568D76F5B7F0BABB cert=vYIV5MgrghGQvZPIi1tJwnzorMgqgmlKaB77Y3Z9Q/v94wZBOAXkW+fdx4aSxLVnKO+xNw iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.10", "obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.11", "obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.12", "obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.13", "obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.14", "obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.15", "obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0");
-pref("extensions.torlauncher.default_bridge.obfs4.16", "obfs4 [2a0c:4d80:42:702::1]:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.8", "obfs4 144.217.20.138:80 FB70B257C162BF1038CA669D568D76F5B7F0BABB cert=vYIV5MgrghGQvZPIi1tJwnzorMgqgmlKaB77Y3Z9Q/v94wZBOAXkW+fdx4aSxLVnKO+xNw iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.9", "obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.10", "obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.11", "obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.12", "obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.13", "obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.14", "obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0");
+pref("extensions.torlauncher.default_bridge.obfs4.15", "obfs4 [2a0c:4d80:42:702::1]:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0");
pref("extensions.torlauncher.default_bridge.meek-azure.1", "meek_lite 0.0.2.0:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com");
1
0
commit bbe307ec654fc9e34c8976ffd373f73c9cd29b94
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 3 02:22:36 2020 +0000
Update ChangeLog
---
projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt b/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt
index 8772d7d..7cb65b8 100644
--- a/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt
+++ b/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt
@@ -1,13 +1,19 @@
Tor Browser 9.5a10 -- April XX 2020
* All Platforms
* Bump Https-Everywhere to 2020.3.16
+ * Bug 33342: Avoid disconnect search addon error after removal
+ * Bug 33482: Update about:tor donate string
* Android
* Translations update
* Windows + OS X + Linux
+ * Bug 19251: Show improved error pages for onion service errors
+ * Bug 21952: Implement Onion-Location
+ * Bug 28005: Implement .onion alias urlbar rewrites
* Bug 33693: Bump Snowflake to ea01bf41c3
- * Bug 33771: Update some existing licenses and add Libevent license
+ * Bug 33707: Swap out onion icon in circuit display with new one
* Bug 33723: Bump openssl version to 1.1.1f
* Bug 33761: Remove unnecessary snowflake dependencies
+ * Bug 33771: Update some existing licenses and add Libevent license
Tor Browser 9.5a9 -- March 25 2020
* All Platforms
1
0

[tor-browser/tor-browser-68.6.0esr-9.5-1] squash! Bug 30237: Add v3 onion services client authentication prompt
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit e3b4a8bf4a19cee4838a5216a3ef5af58bea6e62
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Wed Feb 19 11:20:25 2020 -0500
squash! Bug 30237: Add v3 onion services client authentication prompt
Also fixes bug 19251: use enhanced error pages for onion service errors.
---
browser/actors/NetErrorChild.jsm | 10 +
.../components/onionservices/content/authPrompt.js | 20 +-
.../components/onionservices/content/authUtil.jsm | 16 +-
.../onionservices/content/netError/browser.svg | 3 +
.../onionservices/content/netError/network.svg | 3 +
.../content/netError/onionNetError.css | 65 ++++++
.../content/netError/onionNetError.jsm | 253 +++++++++++++++++++++
.../onionservices/content/netError/onionsite.svg | 7 +
browser/components/onionservices/jar.mn | 1 +
browser/modules/TorStrings.jsm | 48 ++++
docshell/base/nsDocShell.cpp | 47 ++--
dom/ipc/BrowserParent.cpp | 4 +-
dom/ipc/BrowserParent.h | 2 +-
dom/ipc/PBrowser.ipdl | 3 +-
js/xpconnect/src/xpc.msg | 2 +
netwerk/socket/nsSOCKSIOLayer.cpp | 11 +
xpcom/base/ErrorList.py | 4 +
17 files changed, 472 insertions(+), 27 deletions(-)
diff --git a/browser/actors/NetErrorChild.jsm b/browser/actors/NetErrorChild.jsm
index 7834f7168a42..972ca7de7a01 100644
--- a/browser/actors/NetErrorChild.jsm
+++ b/browser/actors/NetErrorChild.jsm
@@ -23,6 +23,11 @@ ChromeUtils.defineModuleGetter(
"WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm"
);
+ChromeUtils.defineModuleGetter(
+ this,
+ "OnionServicesAboutNetError",
+ "chrome://browser/content/onionservices/netError/onionNetError.jsm"
+);
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
@@ -854,6 +859,11 @@ class NetErrorChild extends ActorChild {
let learnMoreLink = win.document.getElementById("learnMoreLink");
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
learnMoreLink.setAttribute("href", baseURL + "connection-not-secure");
+
+ // Initialize the onion services error module, which customizes the
+ // content on the error page when an onion service error is being
+ // displayed.
+ OnionServicesAboutNetError.initPage(win.document);
}
let automatic = Services.prefs.getBoolPref(
diff --git a/browser/components/onionservices/content/authPrompt.js b/browser/components/onionservices/content/authPrompt.js
index f7a10e75158a..24bf7ae28ea2 100644
--- a/browser/components/onionservices/content/authPrompt.js
+++ b/browser/components/onionservices/content/authPrompt.js
@@ -10,9 +10,12 @@ XPCOMUtils.defineLazyModuleGetters(this, {
const OnionAuthPrompt = (function() {
// OnionServicesAuthPrompt objects run within the main/chrome process.
- function OnionServicesAuthPrompt(aBrowser, aFailedURI, aOnionName) {
+ // 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;
}
@@ -196,7 +199,8 @@ const OnionAuthPrompt = (function() {
// Arrange for an error page to be displayed.
this._browser.messageManager.sendAsyncMessage(
OnionAuthUtil.message.authPromptCanceled,
- {failedURI: this._failedURI.spec});
+ {failedURI: this._failedURI.spec,
+ reasonForPrompt: this._reasonForPrompt});
},
_getKeyElement() {
@@ -261,17 +265,20 @@ const OnionAuthPrompt = (function() {
let retval = {
init() {
- Services.obs.addObserver(this, OnionAuthUtil.topic.authPrompt);
+ Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthMissing);
+ Services.obs.addObserver(this, OnionAuthUtil.topic.clientAuthIncorrect);
},
uninit() {
- Services.obs.removeObserver(this, OnionAuthUtil.topic.authPrompt);
+ 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.authPrompt) {
+ if ((aTopic != OnionAuthUtil.topic.clientAuthMissing) &&
+ (aTopic != OnionAuthUtil.topic.clientAuthIncorrect)) {
return;
}
@@ -288,7 +295,8 @@ const OnionAuthPrompt = (function() {
}
let failedURI = browser.currentURI;
- let authPrompt = new OnionServicesAuthPrompt(browser, failedURI, aData);
+ let authPrompt = new OnionServicesAuthPrompt(browser, failedURI,
+ aTopic, aData);
authPrompt.show(undefined);
}
};
diff --git a/browser/components/onionservices/content/authUtil.jsm b/browser/components/onionservices/content/authUtil.jsm
index e9446f51cfcb..c9d83774da1f 100644
--- a/browser/components/onionservices/content/authUtil.jsm
+++ b/browser/components/onionservices/content/authUtil.jsm
@@ -10,7 +10,8 @@ var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const OnionAuthUtil = {
topic: {
- authPrompt: "tor-onion-services-auth-prompt",
+ clientAuthMissing: "tor-onion-services-clientauth-missing",
+ clientAuthIncorrect: "tor-onion-services-clientauth-incorrect",
},
message: {
authPromptCanceled: "Tor:OnionServicesAuthPromptCanceled",
@@ -29,9 +30,18 @@ const OnionAuthUtil = {
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);
- aDocShell.displayLoadError(Cr.NS_ERROR_CONNECTION_REFUSED, failedURI,
- undefined, undefined);
+ 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.jsm b/browser/components/onionservices/content/netError/onionNetError.jsm
new file mode 100644
index 000000000000..34b4806c63da
--- /dev/null
+++ b/browser/components/onionservices/content/netError/onionNetError.jsm
@@ -0,0 +1,253 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["OnionServicesAboutNetError"];
+
+ChromeUtils.defineModuleGetter(
+ this,
+ "TorStrings",
+ "resource:///modules/TorStrings.jsm"
+);
+
+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.";
+ if (!err.startsWith(errPrefix)) {
+ return; // This is not an onion services error; nothing for us to do.
+ }
+
+ const errName = err.substring(errPrefix.length);
+
+ const stringsObj = TorStrings.onionServices[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);
+ // eslint-disable-next-line no-unsanitized/property
+ ld.innerHTML = 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 = TorStrings.onionServices.errorPage.browser;
+ labelDiv = this._createDiv(aDoc, undefined, undefined, container);
+ labelDiv.textContent = TorStrings.onionServices.errorPage.network;
+ labelDiv = this._createDiv(aDoc, undefined, undefined, container);
+ labelDiv.textContent = TorStrings.onionServices.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/jar.mn b/browser/components/onionservices/jar.mn
index 583ab77bc6d8..1272d5dc9b6a 100644
--- a/browser/components/onionservices/jar.mn
+++ b/browser/components/onionservices/jar.mn
@@ -3,6 +3,7 @@ browser.jar:
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.xul (content/savedKeysDialog.xul)
diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm
index e9a8b3969297..a57d17f8361c 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -328,9 +328,57 @@ var TorStrings = {
return tsb.getString(key, fallback);
};
+ const kProblemLoadingSiteFallback = "Problem Loading Onionsite";
+ const kLongDescFallback = "Details: %S";
+
let retval = {
learnMore: getString("learnMore", "Learn more"),
learnMoreURL: `https://2019.www.torproject.org/docs/tor-manual-dev.html.${getLocale()}#_client_authorization`,
+ errorPage: {
+ browser: getString("errorPage.browser", "Browser"),
+ network: getString("errorPage.network", "Network"),
+ onionSite: getString("errorPage.onionSite", "Onionsite"),
+ },
+ descNotFound: { // Tor SOCKS error 0xF0
+ pageTitle: getString("descNotFound.pageTitle", kProblemLoadingSiteFallback),
+ header: getString("descNotFound.header", "Onionsite Not Found"),
+ longDescription: getString("descNotFound.longDescription", kLongDescFallback),
+ },
+ descInvalid: { // Tor SOCKS error 0xF1
+ pageTitle: getString("descInvalid.pageTitle", kProblemLoadingSiteFallback),
+ header: getString("descInvalid.header", "Onionsite Cannot Be Reached"),
+ longDescription: getString("descInvalid.longDescription", kLongDescFallback),
+ },
+ introFailed: { // Tor SOCKS error 0xF2
+ pageTitle: getString("introFailed.pageTitle", kProblemLoadingSiteFallback),
+ header: getString("introFailed.header", "Onionsite Has Disconnected"),
+ longDescription: getString("introFailed.longDescription", kLongDescFallback),
+ },
+ rendezvousFailed: { // Tor SOCKS error 0xF3
+ pageTitle: getString("rendezvousFailed.pageTitle", kProblemLoadingSiteFallback),
+ header: getString("rendezvousFailed.header", "Unable to Connect to Onionsite"),
+ longDescription: getString("rendezvousFailed.longDescription", kLongDescFallback),
+ },
+ clientAuthMissing: { // Tor SOCKS error 0xF4
+ pageTitle: getString("clientAuthMissing.pageTitle", "Authorization Required"),
+ header: getString("clientAuthMissing.header", "Onionsite Requires Authentication"),
+ longDescription: getString("clientAuthMissing.longDescription", kLongDescFallback),
+ },
+ clientAuthIncorrect: { // Tor SOCKS error 0xF5
+ pageTitle: getString("clientAuthIncorrect.pageTitle", "Authorization Failed"),
+ header: getString("clientAuthIncorrect.header", "Onionsite Authentication Failed"),
+ longDescription: getString("clientAuthIncorrect.longDescription", kLongDescFallback),
+ },
+ badAddress: { // Tor SOCKS error 0xF6
+ pageTitle: getString("badAddress.pageTitle", kProblemLoadingSiteFallback),
+ header: getString("badAddress.header", "Invalid Onionsite Address"),
+ longDescription: getString("badAddress.longDescription", kLongDescFallback),
+ },
+ introTimedOut: { // Tor SOCKS error 0xF7
+ pageTitle: getString("introTimedOut.pageTitle", kProblemLoadingSiteFallback),
+ header: getString("introTimedOut.header", "Onionsite Circuit Creation Timed Out"),
+ longDescription: getString("introTimedOut.longDescription", kLongDescFallback),
+ },
authPrompt: {
description:
getString("authPrompt.description", "%S is requesting your private key."),
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index cc329a50c109..4c5352d875dc 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4284,6 +4284,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
@@ -4364,28 +4365,43 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
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:
- // For now, handle these Tor onion service errors the same as
- // NS_ERROR_CONNECTION_REFUSED.
- NS_ENSURE_ARG_POINTER(aURI);
- addHostPort = true;
- error = "connectionFailure";
+ error = "onionServices.rendezvousFailed";
break;
- case NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH:
- // For now, we let this fall through but it should be handled in
- // a special way, e.g., tell the user in our auth prompt that the
- // key they provided was bad. This will be done as part of #30025.
- MOZ_FALLTHROUGH;
case NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH:
error = "onionServices.clientAuthMissing";
- // Display about:blank while the Tor client auth prompt is open.
- errorPage.AssignLiteral("blank");
+ 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");
+ }
}
// Test if the error should be displayed
@@ -8415,17 +8431,20 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType,
(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);
+ ->SendShowOnionServicesAuthPrompt(onionHost, nsCString(topic));
}
} else {
nsCOMPtr<nsPIDOMWindowOuter> browserWin = GetWindow();
nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
if (browserWin && obsSvc) {
- const char* topic = "tor-onion-services-auth-prompt";
obsSvc->NotifyObservers(browserWin, topic,
NS_ConvertUTF8toUTF16(onionHost).get());
}
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
index 88605c949502..ea2bbdc4821f 100644
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -3777,7 +3777,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt(
}
mozilla::ipc::IPCResult BrowserParent::RecvShowOnionServicesAuthPrompt(
- const nsCString& aOnionName) {
+ const nsCString& aOnionName, const nsCString& aTopic) {
nsCOMPtr<nsIBrowser> browser =
mFrameElement ? mFrameElement->AsBrowser() : nullptr;
if (!browser) {
@@ -3791,7 +3791,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvShowOnionServicesAuthPrompt(
}
nsresult rv = os->NotifyObservers(
browser,
- "tor-onion-services-auth-prompt",
+ aTopic.get(),
NS_ConvertUTF8toUTF16(aOnionName).get());
if (NS_FAILED(rv)) {
return IPC_FAIL_NO_REASON(this);
diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h
index 23c189cf6243..5a841a09a48c 100644
--- a/dom/ipc/BrowserParent.h
+++ b/dom/ipc/BrowserParent.h
@@ -719,7 +719,7 @@ class BrowserParent final : public PBrowserParent,
const nsCString& aOrigin, const bool& aHideDoorHanger);
mozilla::ipc::IPCResult RecvShowOnionServicesAuthPrompt(
- const nsCString& aOnionName);
+ 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 b99d7f04fe39..9029bf0abcbe 100644
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -567,8 +567,9 @@ parent:
* 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);
+ async ShowOnionServicesAuthPrompt(nsCString aOnionHost, nsCString aTopic);
child:
async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg
index d9b64fe87fce..b0469d325669 100644
--- a/js/xpconnect/src/xpc.msg
+++ b/js/xpconnect/src/xpc.msg
@@ -253,6 +253,8 @@ XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_INTRO_FAILED , "Tor onion service intro
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/socket/nsSOCKSIOLayer.cpp b/netwerk/socket/nsSOCKSIOLayer.cpp
index 6649056da1e7..56ff4a696845 100644
--- a/netwerk/socket/nsSOCKSIOLayer.cpp
+++ b/netwerk/socket/nsSOCKSIOLayer.cpp
@@ -1042,6 +1042,17 @@ PRStatus nsSOCKSSocketInfo::ReadV5ConnectResponseTop() {
" 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/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py
index 24cabd355b0d..9fe223d3bcca 100755
--- a/xpcom/base/ErrorList.py
+++ b/xpcom/base/ErrorList.py
@@ -1136,6 +1136,10 @@ with modules["TOR"]:
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

[tor-browser/tor-browser-68.6.0esr-9.5-1] Merge remote-tracking branch 'bradetpo/bug19251-04' into tor-browser-68.6.0esr-9.5-1
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit 31200493ae908e01ecbeeb44e0546a354ea8736d
Merge: 7306a08365be e3b4a8bf4a19
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 3 02:03:43 2020 +0000
Merge remote-tracking branch 'bradetpo/bug19251-04' into tor-browser-68.6.0esr-9.5-1
browser/actors/NetErrorChild.jsm | 10 +
.../components/onionservices/content/authPrompt.js | 20 +-
.../components/onionservices/content/authUtil.jsm | 16 +-
.../onionservices/content/netError/browser.svg | 3 +
.../onionservices/content/netError/network.svg | 3 +
.../content/netError/onionNetError.css | 65 ++++++
.../content/netError/onionNetError.jsm | 253 +++++++++++++++++++++
.../onionservices/content/netError/onionsite.svg | 7 +
browser/components/onionservices/jar.mn | 1 +
browser/modules/TorStrings.jsm | 48 ++++
docshell/base/nsDocShell.cpp | 47 ++--
dom/ipc/BrowserParent.cpp | 4 +-
dom/ipc/BrowserParent.h | 2 +-
dom/ipc/PBrowser.ipdl | 3 +-
js/xpconnect/src/xpc.msg | 2 +
netwerk/socket/nsSOCKSIOLayer.cpp | 11 +
xpcom/base/ErrorList.py | 4 +
17 files changed, 472 insertions(+), 27 deletions(-)
1
0

[tor-browser/tor-browser-68.6.0esr-9.5-1] Bug 21952: Implement Onion-Location
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit da5513527e50e7f13e3b1c3206ed75ff8fbd76db
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.xul | 3 +
browser/components/BrowserGlue.jsm | 10 ++
.../onionservices/OnionLocationChild.jsm | 43 ++++++
.../onionservices/OnionLocationParent.jsm | 161 +++++++++++++++++++++
.../content/onionlocation-notification-icons.css | 5 +
.../onionservices/content/onionlocation-urlbar.css | 27 ++++
.../content/onionlocation-urlbar.inc.xul | 10 ++
.../onionservices/content/onionlocation.svg | 3 +
.../content/onionlocationPreferences.inc.xul | 11 ++
.../content/onionlocationPreferences.js | 31 ++++
browser/components/onionservices/jar.mn | 2 +
browser/components/onionservices/moz.build | 5 +
.../components/preferences/in-content/privacy.js | 17 +++
.../components/preferences/in-content/privacy.xul | 2 +
browser/modules/TorStrings.jsm | 39 +++++
browser/themes/shared/notification-icons.inc.css | 2 +
browser/themes/shared/urlbar-searchbar.inc.css | 2 +
dom/base/Document.cpp | 32 +++-
dom/base/Document.h | 2 +
dom/webidl/Document.webidl | 9 ++
modules/libpref/init/StaticPrefList.h | 7 +
xpcom/ds/StaticAtoms.py | 1 +
23 files changed, 435 insertions(+), 1 deletion(-)
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 3f9bf006f562..410c8f62d0ef 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -43,6 +43,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",
@@ -5934,6 +5935,7 @@ var XULBrowserWindow = {
Services.obs.notifyObservers(null, "touchbar-location-change", location);
UpdateBackForwardCommands(gBrowser.webNavigation);
ReaderParent.updateReaderButton(gBrowser.selectedBrowser);
+ OnionLocationParent.updateOnionLocationBadge(gBrowser.selectedBrowser);
if (!gMultiProcessBrowser) {
// Bug 1108553 - Cannot rotate images with e10s
@@ -6581,6 +6583,16 @@ 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.xul b/browser/base/content/browser.xul
index d2f72eea8edb..4309a0b71228 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -992,6 +992,9 @@
onclick="FullZoom.reset();"
tooltip="dynamic-shortcut-tooltip"
hidden="true"/>
+
+#include ../../components/onionservices/content/onionlocation-urlbar.inc.xul
+
<box id="pageActionSeparator" class="urlbar-page-action"/>
<image id="pageActionButton"
class="urlbar-icon urlbar-page-action"
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 4e851289fbe9..fd2cbfe1d64f 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -216,6 +216,14 @@ let LEGACY_ACTORS = {
},
},
+ OnionLocation: {
+ child: {
+ module: "resource:///modules/OnionLocationChild.jsm",
+ events: { pageshow: {} },
+ messages: ["OnionLocation:Refresh"],
+ },
+ },
+
PageInfo: {
child: {
module: "resource:///actors/PageInfoChild.jsm",
@@ -507,6 +515,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ContentClick: "resource:///modules/ContentClick.jsm",
FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
+ OnionLocationParent: "resource:///modules/OnionLocationParent.jsm",
PictureInPicture: "resource://gre/modules/PictureInPicture.jsm",
ReaderParent: "resource:///modules/ReaderParent.jsm",
RemotePrompt: "resource:///modules/RemotePrompt.jsm",
@@ -605,6 +614,7 @@ const listeners = {
ContentSearch: ["ContentSearch"],
"FormValidation:ShowPopup": ["FormValidationHandler"],
"FormValidation:HidePopup": ["FormValidationHandler"],
+ "OnionLocation:Set": ["OnionLocationParent"],
"PictureInPicture:Request": ["PictureInPicture"],
"PictureInPicture:Close": ["PictureInPicture"],
"PictureInPicture:Playing": ["PictureInPicture"],
diff --git a/browser/components/onionservices/OnionLocationChild.jsm b/browser/components/onionservices/OnionLocationChild.jsm
new file mode 100644
index 000000000000..1059eb7d5925
--- /dev/null
+++ b/browser/components/onionservices/OnionLocationChild.jsm
@@ -0,0 +1,43 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["OnionLocationChild"];
+
+const { ActorChild } = ChromeUtils.import(
+ "resource://gre/modules/ActorChild.jsm"
+);
+
+class OnionLocationChild extends ActorChild {
+ handleEvent(event) {
+ this.onPageShow(event);
+ }
+
+ onPageShow(event) {
+ if (event.target != this.content.document) {
+ return;
+ }
+ const onionLocationURI = this.content.document.onionLocationURI;
+ if (onionLocationURI) {
+ this.mm.sendAsyncMessage("OnionLocation:Set");
+ }
+ }
+
+ receiveMessage(aMessage) {
+ if (aMessage.name == "OnionLocation:Refresh") {
+ const doc = this.content.document;
+ const docShell = this.mm.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..1c79fc07d215
--- /dev/null
+++ b/browser/components/onionservices/OnionLocationParent.jsm
@@ -0,0 +1,161 @@
+// 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;
+
+var OnionLocationParent = {
+ // Listeners are added in BrowserGlue.jsm
+ receiveMessage(aMsg) {
+ switch (aMsg.name) {
+ case "OnionLocation:Set":
+ this.setOnionLocation(aMsg.target);
+ break;
+ }
+ },
+
+ buttonClick(event) {
+ if (event.button != 0) {
+ return;
+ }
+ const win = event.target.ownerGlobal;
+ const browser = win.gBrowser.selectedBrowser;
+ this.redirect(browser);
+ },
+
+ redirect(browser) {
+ browser.messageManager.sendAsyncMessage("OnionLocation:Refresh");
+ this.setDisabled(browser);
+ },
+
+ onStateChange(browser) {
+ delete browser._onionLocation;
+ this.hideNotification(browser);
+ },
+
+ setOnionLocation(browser) {
+ const win = browser.ownerGlobal;
+ browser._onionLocation = true;
+ if (browser === win.gBrowser.selectedBrowser) {
+ this.updateOnionLocationBadge(browser);
+ }
+ },
+
+ hideNotification(browser) {
+ const win = browser.ownerGlobal;
+ if (browser._onionLocationPrompt) {
+ win.PopupNotifications.remove(browser._onionLocationPrompt);
+ }
+ },
+
+ 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
+ );
+ },
+
+ 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");
+ },
+
+ setDisabled(browser) {
+ const win = browser.ownerGlobal;
+ const elem = win.document.getElementById(ONIONLOCATION_BOX_ID);
+ elem.setAttribute("hidden", true);
+ },
+
+ updateOnionLocationBadge(browser) {
+ if (browser._onionLocation) {
+ this.setEnabled(browser);
+ this.showNotification(browser);
+ } else {
+ this.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.xul b/browser/components/onionservices/content/onionlocation-urlbar.inc.xul
new file mode 100644
index 000000000000..b612a4236f3c
--- /dev/null
+++ b/browser/components/onionservices/content/onionlocation-urlbar.inc.xul
@@ -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.xul b/browser/components/onionservices/content/onionlocationPreferences.inc.xul
new file mode 100644
index 000000000000..c386316c98dc
--- /dev/null
+++ b/browser/components/onionservices/content/onionlocationPreferences.inc.xul
@@ -0,0 +1,11 @@
+# Copyright (c) 2020, The Tor Project, Inc.
+
+<groupbox id="onionServicesGroup" data-category="panePrivacy" data-subcategory="onionservices">
+ <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 583ab77bc6d8..d536e172721c 100644
--- a/browser/components/onionservices/jar.mn
+++ b/browser/components/onionservices/jar.mn
@@ -6,3 +6,5 @@ browser.jar:
content/browser/onionservices/onionservices.css (content/onionservices.css)
content/browser/onionservices/savedKeysDialog.js (content/savedKeysDialog.js)
content/browser/onionservices/savedKeysDialog.xul (content/savedKeysDialog.xul)
+ 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 7e103239c8d6..bf276c4a3c4c 100644
--- a/browser/components/onionservices/moz.build
+++ b/browser/components/onionservices/moz.build
@@ -1 +1,6 @@
JAR_MANIFESTS += ['jar.mn']
+
+EXTRA_JS_MODULES += [
+ 'OnionLocationChild.jsm',
+ 'OnionLocationParent.jsm',
+]
diff --git a/browser/components/preferences/in-content/privacy.js b/browser/components/preferences/in-content/privacy.js
index ee86b4158d7c..015ee77932b7 100644
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -75,6 +75,12 @@ XPCOMUtils.defineLazyScriptGetter(
"chrome://browser/content/securitylevel/securityLevel.js"
);
+XPCOMUtils.defineLazyScriptGetter(
+ this,
+ ["OnionLocationPreferences"],
+ "chrome://browser/content/onionservices/onionlocationPreferences.js"
+);
+
XPCOMUtils.defineLazyServiceGetter(
this,
"listManager",
@@ -124,6 +130,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" },
@@ -251,6 +260,13 @@ var gPrivacyPane = {
},
/**
+ * Show the OnionLocation preferences UI
+ */
+ _initOnionLocation() {
+ OnionLocationPreferences.init();
+ },
+
+ /**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart: true,
@@ -377,6 +393,7 @@ var gPrivacyPane = {
this._initTrackingProtectionExtensionControl();
OnionServicesAuthPreferences.init();
this._initSecurityLevel();
+ this._initOnionLocation();
Services.telemetry.setEventRecordingEnabled("pwmgr", true);
diff --git a/browser/components/preferences/in-content/privacy.xul b/browser/components/preferences/in-content/privacy.xul
index e807ac69f1f1..05c4966a1e59 100644
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -15,6 +15,8 @@
<html:h1 data-l10n-id="privacy-header"/>
</hbox>
+#include ../../onionservices/content/onionlocationPreferences.inc.xul
+
<!-- Tracking / Content Blocking -->
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" aria-describedby="contentBlockingDescription">
<label id="contentBlockingHeader"><html:h2 data-l10n-id="content-blocking-header"/></label>
diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm
index e9a8b3969297..34b13f33a96a 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -359,6 +359,45 @@ var TorStrings = {
return retval;
})() /* Tor Onion Services Strings */,
+ /*
+ OnionLocation
+ */
+ onionLocation: (function() {
+ const tsb = new TorPropertyStringBundle(
+ ["chrome://torbutton/locale/torbutton.properties"],
+ "onionLocation."
+ );
+ const getString = function(key, fallback) {
+ return tsb.getString(key, fallback);
+ };
+
+ const retval = {
+ alwaysPrioritize: getString(
+ "alwaysPrioritize",
+ "Always Prioritize Onionsites"
+ ),
+ alwaysPrioritizeAccessKey: getString("alwaysPrioritizeAccessKey", "a"),
+ notNow: getString("notNow", "Not Now"),
+ notNowAccessKey: getString("notNowAccessKey", "n"),
+ description: getString(
+ "description",
+ "Website publishers can protect users by adding a security layer. This prevents eavesdroppers from knowing that you are the one visiting that website."
+ ),
+ tryThis: getString("tryThis", "Try this: Onionsite"),
+ onionAvailable: getString("onionAvailable", "Onionsite available"),
+ learnMore: getString("learnMore", "Learn more"),
+ learnMoreURL: `https://tb-manual.torproject.org/${getLocale()}`, // TODO: replace when manual page is available.
+ always: getString("always", "Always"),
+ askEverytime: getString("askEverytime", "Ask you every time"),
+ prioritizeOnionsDescription: getString(
+ "prioritizeOnionsDescription",
+ "Prioritize onionsites when they are available."
+ ),
+ onionServicesTitle: getString("onionServicesTitle", "Onion Services"),
+ };
+
+ return retval;
+ })() /* OnionLocation */,
/*
Tor Deamon Configuration Key Strings
diff --git a/browser/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css
index d35f292a0860..afe67decceaf 100644
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -393,3 +393,5 @@ html|*#webRTC-previewVideo {
background: #FFE900 url(chrome://browser/skin/notification-icons/update.svg) no-repeat center;
border-radius: 50%;
}
+
+%include ../../components/onionservices/content/onionlocation-notification-icons.css
\ No newline at end of file
diff --git a/browser/themes/shared/urlbar-searchbar.inc.css b/browser/themes/shared/urlbar-searchbar.inc.css
index a13d402f17e3..40d42921db30 100644
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -789,3 +789,5 @@
#urlbar.hidden-focus[focused="true"] {
caret-color: transparent;
}
+
+%include ../../components/onionservices/content/onionlocation-urlbar.css
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index 95b95c9fd69e..994f52659265 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -2078,6 +2078,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
// mDocumentURI.
mDocumentBaseURI = nullptr;
mChromeXHRDocBaseURI = nullptr;
+ mOnionLocationURI = nullptr;
if (aLoadGroup) {
mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
@@ -3731,6 +3732,21 @@ void Document::GetHeaderData(nsAtom* aHeaderField, nsAString& aData) const {
}
}
+static bool IsValidOnionLocation(nsIURI* aDocumentURI,
+ nsIURI* aOnionLocationURI) {
+ bool isHttpish;
+ nsAutoCString onionHost;
+ return aDocumentURI && aOnionLocationURI &&
+ NS_SUCCEEDED(aDocumentURI->SchemeIs("https", &isHttpish)) &&
+ isHttpish &&
+ ((NS_SUCCEEDED(aOnionLocationURI->SchemeIs("http", &isHttpish)) &&
+ isHttpish) ||
+ (NS_SUCCEEDED(aOnionLocationURI->SchemeIs("https", &isHttpish)) &&
+ isHttpish)) &&
+ NS_SUCCEEDED(aOnionLocationURI->GetAsciiHost(onionHost)) &&
+ StringEndsWith(onionHost, NS_LITERAL_CSTRING(".onion"));
+}
+
void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) {
if (!aHeaderField) {
NS_ERROR("null headerField");
@@ -3834,6 +3850,20 @@ void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) {
mReferrerPolicySet = true;
}
}
+ 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()) {
+ nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer);
+ if (refresher) {
+ refresher->RefreshURI(onionURI, NodePrincipal(), 0, false, true);
+ }
+ } else {
+ mOnionLocationURI = onionURI;
+ }
+ }
+ }
}
void Document::TryChannelCharset(nsIChannel* aChannel, int32_t& aCharsetSource,
NotNull<const Encoding*>& aEncoding,
@@ -7468,7 +7498,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", "referrer-policy",
+ "x-frame-options", "referrer-policy", "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 58d09afba815..43f8517fcd65 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -3291,6 +3291,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
bool FullscreenEnabled(CallerType aCallerType);
Element* FullscreenStackTop();
@@ -3998,6 +3999,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 0170a17fbf96..a281b04a0960 100644
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -589,3 +589,12 @@ partial interface Document {
[ChromeOnly]
void setRDMPaneOrientation(OrientationType type, float rotationAngle);
};
+
+
+/**
+ * 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.h b/modules/libpref/init/StaticPrefList.h
index 47f4626f7e6b..158952041d3d 100644
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -2555,6 +2555,13 @@ VARCACHE_PREF(
)
#undef PREF_VALUE
+// Automatically redirect to Onion-Location header, disabled by default
+VARCACHE_PREF(
+ "privacy.prioritizeonions.enabled",
+ privacy_prioritizeOnions,
+ RelaxedAtomicBool, false
+)
+
// Anti-fingerprinting, disabled by default
VARCACHE_PREF(
"privacy.resistFingerprinting",
diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py
index 9a182d3bf6d0..71fffc55f1b8 100644
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -803,6 +803,7 @@ STATIC_ATOMS = [
Atom("oninput", "oninput"),
Atom("oninstall", "oninstall"),
Atom("oninvalid", "oninvalid"),
+ Atom("headerOnionLocation", "onion-location"),
Atom("onkeydown", "onkeydown"),
Atom("onkeypress", "onkeypress"),
Atom("onkeyup", "onkeyup"),
1
0

[tor-browser/tor-browser-68.6.0esr-9.5-1] Bug 28005: Implement .onion alias urlbar rewrites
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit 7306a08365be9212f621b396513352d19549c487
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.
---
browser/actors/ClickHandlerChild.jsm | 20 +++
browser/actors/ContextMenuChild.jsm | 4 +
browser/base/content/browser-places.js | 12 +-
browser/base/content/browser.js | 37 +++-
browser/base/content/nsContextMenu.js | 18 ++
browser/base/content/tabbrowser.js | 7 +
browser/base/content/utilityOverlay.js | 2 +
browser/components/BrowserGlue.jsm | 6 +
.../onionservices/ExtensionMessaging.jsm | 86 +++++++++
.../onionservices/HttpsEverywhereControl.jsm | 119 ++++++++++++
.../components/onionservices/OnionAliasStore.jsm | 199 +++++++++++++++++++++
browser/components/onionservices/moz.build | 6 +
browser/components/urlbar/UrlbarInput.jsm | 8 +-
browser/modules/ContentClick.jsm | 1 +
docshell/base/nsDocShell.cpp | 37 ++++
docshell/base/nsDocShell.h | 4 +
docshell/base/nsDocShellLoadState.cpp | 4 +
docshell/base/nsIDocShell.idl | 5 +
docshell/base/nsIWebNavigation.idl | 5 +
docshell/shistory/nsISHEntry.idl | 5 +
docshell/shistory/nsSHEntry.cpp | 18 +-
docshell/shistory/nsSHEntry.h | 1 +
modules/libpref/init/StaticPrefList.h | 7 +
netwerk/dns/effective_tld_names.dat | 2 +
.../remotebrowserutils/RemoteWebNavigation.jsm | 1 +
toolkit/content/widgets/browser-custom-element.js | 9 +
toolkit/modules/RemoteWebProgress.jsm | 2 +
toolkit/modules/WebProgressChild.jsm | 1 +
toolkit/modules/sessionstore/SessionHistory.jsm | 5 +
29 files changed, 622 insertions(+), 9 deletions(-)
diff --git a/browser/actors/ClickHandlerChild.jsm b/browser/actors/ClickHandlerChild.jsm
index 4375be0067ac..263a5fea053e 100644
--- a/browser/actors/ClickHandlerChild.jsm
+++ b/browser/actors/ClickHandlerChild.jsm
@@ -156,6 +156,26 @@ class ClickHandlerChild extends ActorChild {
json.originPrincipal = ownerDoc.nodePrincipal;
json.triggeringPrincipal = ownerDoc.nodePrincipal;
+ // Check if the link needs to be opened with .tor.onion urlbar rewrites
+ // allowed. Only when the owner doc has allowOnionUrlbarRewrites = true
+ // and the same origin we should allow this.
+ json.allowOnionUrlbarRewrites = false;
+ if (this.mm.docShell.allowOnionUrlbarRewrites) {
+ 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.allowOnionUrlbarRewrites = 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/ContextMenuChild.jsm b/browser/actors/ContextMenuChild.jsm
index 546f51e843d6..5915832eae7a 100644
--- a/browser/actors/ContextMenuChild.jsm
+++ b/browser/actors/ContextMenuChild.jsm
@@ -543,6 +543,9 @@ class ContextMenuChild extends ActorChild {
// The same-origin check will be done in nsContextMenu.openLinkInTab.
let parentAllowsMixedContent = !!this.docShell.mixedContentChannel;
+ let parentAllowsOnionUrlbarRewrites = this.docShell
+ .allowOnionUrlbarRewrites;
+
// Get referrer attribute from clicked link and parse it
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(
aEvent.composedTarget.getAttribute("referrerpolicy")
@@ -659,6 +662,7 @@ class ContextMenuChild extends ActorChild {
popupNodeSelectors,
disableSetDesktopBg,
parentAllowsMixedContent,
+ parentAllowsOnionUrlbarRewrites,
};
Services.obs.notifyObservers(
diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index 6aa348c609a4..a2dd38a97514 100755
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -440,7 +440,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;
@@ -544,7 +545,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)) {
@@ -1618,14 +1619,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.js b/browser/base/content/browser.js
index 3f9bf006f562..2c89d658d4ec 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -72,6 +72,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm",
Translation: "resource:///modules/translation/Translation.jsm",
+ OnionAliasStore: "resource:///modules/OnionAliasStore.jsm",
UITour: "resource:///modules/UITour.jsm",
UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
UrlbarInput: "resource:///modules/UrlbarInput.jsm",
@@ -3335,7 +3336,10 @@ function URLBarSetURI(aURI, updatePopupNotifications) {
// bar if the user has deleted the URL and we'd just put the same URL
// back. See bug 304198.
if (value === null) {
- let uri = aURI || gBrowser.currentURI;
+ let uri =
+ aURI ||
+ gBrowser.selectedBrowser.currentOnionAliasURI ||
+ gBrowser.currentURI;
// Strip off usernames and passwords for the location bar
try {
uri = Services.uriFixup.createExposableURI(uri);
@@ -5897,11 +5901,24 @@ var XULBrowserWindow = {
this.reloadCommand.removeAttribute("disabled");
}
+ // The onion memorable alias needs to be used in URLBarSetURI, but also in
+ // other parts of the code (like the bookmarks UI), so we save it.
+ if (gBrowser.selectedBrowser.allowOnionUrlbarRewrites) {
+ 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
- URLBarSetURI(aLocationURI, aIsSimulated);
+ URLBarSetURI(
+ gBrowser.selectedBrowser.currentOnionAliasURI || aLocationURI,
+ aIsSimulated
+ );
BookmarkingUI.onLocationChange();
@@ -7627,6 +7644,21 @@ function handleLinkClick(event, href, linkNode) {
} catch (e) {}
}
+ // Check if the link needs to be opened with .tor.onion urlbar rewrites
+ // allowed. Only when the owner doc has allowOnionUrlbarRewrites = true
+ // and the same origin we should allow this.
+ let persistAllowOnionUrlbarRewritesInChildTab = false;
+ if (where == "tab" && gBrowser.docShell.allowOnionUrlbarRewrites) {
+ const sm = Services.scriptSecurityManager;
+ try {
+ let tURI = makeURI(href);
+ let isPrivateWin =
+ doc.nodePrincipal.originAttributes.privateBrowsingId > 0;
+ sm.checkSameOriginURI(referrerURI, tURI, false, isPrivateWin);
+ persistAllowOnionUrlbarRewritesInChildTab = true;
+ } catch (e) {}
+ }
+
// first get document wide referrer policy, then
// get referrer attribute from clicked link and parse it and
// allow per element referrer to overrule the document wide referrer if enabled
@@ -7659,6 +7691,7 @@ function handleLinkClick(event, href, linkNode) {
triggeringPrincipal: doc.nodePrincipal,
csp,
frameOuterWindowID,
+ allowOnionUrlbarRewrites: persistAllowOnionUrlbarRewritesInChildTab,
};
// The new tab/window must use the same userContextId
diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js
index e7106e5e8fc1..55da2efb7782 100644
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -93,6 +93,7 @@ function openContextMenu(aMessage) {
disableSetDesktopBackground: data.disableSetDesktopBg,
loginFillInfo: data.loginFillInfo,
parentAllowsMixedContent: data.parentAllowsMixedContent,
+ parentAllowsOnionUrlbarRewrites: data.parentAllowsOnionUrlbarRewrites,
userContextId: data.userContextId,
webExtContextData: data.webExtContextData,
};
@@ -1122,9 +1123,26 @@ nsContextMenu.prototype = {
} catch (e) {}
}
+ // Check if the link needs to be opened with .tor.onion urlbar rewrites
+ // allowed. Only when parent has allowOnionUrlbarRewrites = true
+ // and the same origin we should allow this.
+ let persistAllowOnionUrlbarRewrites = false;
+
+ if (gContextMenuContentData.parentAllowsOnionUrlbarRewrites) {
+ const sm = Services.scriptSecurityManager;
+ try {
+ let targetURI = this.linkURI;
+ let isPrivateWin =
+ this.browser.contentPrincipal.originAttributes.privateBrowsingId > 0;
+ sm.checkSameOriginURI(referrerURI, targetURI, false, isPrivateWin);
+ persistAllowOnionUrlbarRewrites = true;
+ } catch (e) {}
+ }
+
let params = {
allowMixedContent: persistAllowMixedContentInChildTab,
userContextId: parseInt(event.target.getAttribute("data-usercontextid")),
+ allowOnionUrlbarRewrites: persistAllowOnionUrlbarRewrites,
};
openLinkIn(this.linkURL, "tab", this._openLinkInParameters(params));
diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js
index 4dd07ff14e7b..53c463fd3263 100644
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1589,6 +1589,7 @@
var aRelatedToCurrent;
var aAllowInheritPrincipal;
var aAllowMixedContent;
+ var aAllowOnionUrlbarRewrites;
var aSkipAnimation;
var aForceNotRemote;
var aPreferredRemoteType;
@@ -1618,6 +1619,7 @@
aRelatedToCurrent = params.relatedToCurrent;
aAllowInheritPrincipal = !!params.allowInheritPrincipal;
aAllowMixedContent = params.allowMixedContent;
+ aAllowOnionUrlbarRewrites = params.allowOnionUrlbarRewrites;
aSkipAnimation = params.skipAnimation;
aForceNotRemote = params.forceNotRemote;
aPreferredRemoteType = params.preferredRemoteType;
@@ -1658,6 +1660,7 @@
relatedToCurrent: aRelatedToCurrent,
skipAnimation: aSkipAnimation,
allowMixedContent: aAllowMixedContent,
+ allowOnionUrlbarRewrites: aAllowOnionUrlbarRewrites,
forceNotRemote: aForceNotRemote,
createLazyBrowser: aCreateLazyBrowser,
preferredRemoteType: aPreferredRemoteType,
@@ -2530,6 +2533,7 @@
{
allowInheritPrincipal,
allowMixedContent,
+ allowOnionUrlbarRewrites,
allowThirdPartyFixup,
bulkOrderedOpen,
charset,
@@ -2902,6 +2906,9 @@
if (allowMixedContent) {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT;
}
+ if (allowOnionUrlbarRewrites) {
+ 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 9a1010b2afa9..cc46b14561b4 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -370,6 +370,7 @@ function openLinkIn(url, where, params) {
var aRelatedToCurrent = params.relatedToCurrent;
var aAllowInheritPrincipal = !!params.allowInheritPrincipal;
var aAllowMixedContent = params.allowMixedContent;
+ var aAllowOnionUrlbarRewrites = params.allowOnionUrlbarRewrites;
var aForceAllowDataURI = params.forceAllowDataURI;
var aInBackground = params.inBackground;
var aInitiatingDoc = params.initiatingDoc;
@@ -680,6 +681,7 @@ function openLinkIn(url, where, params) {
relatedToCurrent: aRelatedToCurrent,
skipAnimation: aSkipTabAnimation,
allowMixedContent: aAllowMixedContent,
+ allowOnionUrlbarRewrites: aAllowOnionUrlbarRewrites,
userContextId: aUserContextId,
originPrincipal: aPrincipal,
triggeringPrincipal: aTriggeringPrincipal,
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 4e851289fbe9..628c6f5db151 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -494,6 +494,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ShellService: "resource:///modules/ShellService.jsm",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
TabUnloader: "resource:///modules/TabUnloader.jsm",
+ OnionAliasStore: "resource:///modules/OnionAliasStore.jsm",
UIState: "resource://services-sync/UIState.jsm",
UITour: "resource:///modules/UITour.jsm",
WebChannel: "resource://gre/modules/WebChannel.jsm",
@@ -1839,6 +1840,7 @@ BrowserGlue.prototype = {
Normandy.uninit();
RFPHelper.uninit();
+ OnionAliasStore.uninit();
},
// Set up a listener to enable/disable the screenshots extension
@@ -2109,6 +2111,10 @@ BrowserGlue.prototype = {
RFPHelper.init();
});
+ Services.tm.idleDispatchToMainThread(() => {
+ OnionAliasStore.init();
+ });
+
ChromeUtils.idleDispatch(() => {
Blocklist.loadBlocklistAsync();
});
diff --git a/browser/components/onionservices/ExtensionMessaging.jsm b/browser/components/onionservices/ExtensionMessaging.jsm
new file mode 100644
index 000000000000..b5d69df93807
--- /dev/null
+++ b/browser/components/onionservices/ExtensionMessaging.jsm
@@ -0,0 +1,86 @@
+// 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"
+);
+
+class ExtensionMessaging {
+ constructor() {
+ this._callback = null;
+ this._handlers = new Map();
+ this._messageManager = Services.cpmm;
+ }
+
+ async sendMessage(msg, extensionId) {
+ this._init();
+
+ const addon = await AddonManager.getAddonByID(extensionId);
+ if (!addon) {
+ throw new Error(`extension '${extensionId} does not exist`);
+ }
+ await addon.startupPromise;
+
+ const channelId = ExtensionUtils.getUniqueId();
+ return new Promise((resolve, reject) => {
+ this._handlers.set(channelId, { resolve, reject });
+ this._messageManager.sendAsyncMessage("MessageChannel:Messages", [
+ {
+ messageName: "Extension:Message",
+ sender: {
+ id: extensionId,
+ extensionId,
+ },
+ recipient: { extensionId },
+ data: new StructuredCloneHolder(msg),
+ channelId,
+ responseType: MessageChannel.RESPONSE_FIRST,
+ },
+ ]);
+ });
+ }
+
+ 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..87954461bab1
--- /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:
+ "y0iWTVev1uYDVhLdc5uSHWke-9JlbxzqIsGkS95Pk5NsxdlkdbHpqaPr-5xL5FspX8QGo3HAT5hrUcPV_kz8x-HwGEm2-p9BQ6-yEPtr5QXQGGzNoizmj7HH-b0y5qx8iUFwAJ__PJWK4IwSgjIQqHMjmkOLc9N4bmRPULi6ZZMb-97FdeZsh34dVy2tpIzZaijRfRQSfeZkwRXZzOY-siGfOAzY_UcrHFli5zroTZAyDaetFm1z2-TdFLOvN8fi0o3mBbCB9SqhOUImPwSTNWTp2D6bHhI91mt7gr6fLnzHMGrTMh2DQ4vjt_98pe7WTUzuRCLa9Awb6JJgbYA4ySV1akAU0_iq6oCAE9PZbUgUw9UAH1ctRFml87F3HORUMMj5ZCLwRIrEXqrCJbV4f-Ius-ZO2wwlYTsEv8TmUzISpMwVjGOIpXwFIb65R_EX3_vIopauSoyZkvk3klly0Qe6KTy_gg1CZ_h2ZXPpLMwqlfFTDBPv2q8gyuzgkYXQes3FX-PbJ9Dsl5QO4icuEjV2NQ7iPwwIPAtj9cpqCD8-p9TqTKaZjOFC9-ryJpWsivGCbvN2JotmJ5Ax9rmnAMvQM09muCetFj_ZIgllcpeahaw6gxVXlSYIhb0J9V878KNuRJ2yPJFlBmgpFexvCcz8Jqs6JUfIrmUAGUXG9nE",
+ },
+ update_path_prefix: "https://redshiftzero.github.io/securedrop-httpse/",
+ 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..7e006e59490b
--- /dev/null
+++ b/browser/components/onionservices/OnionAliasStore.jsm
@@ -0,0 +1,199 @@
+// 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;
+ }
+
+ 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();
+
+ // Install update channel
+ await this.httpsEverywhereControl.installTorOnionUpdateChannel();
+
+ // 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.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, using http observer as fallback");
+ }
+
+ // Setup checker for https-everywhere ruleset updates
+ 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 7e103239c8d6..e4b6d73f8f40 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 131d2ecc8ca8..8fd87bb8b026 100644
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -1022,7 +1022,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.allowOnionUrlbarRewrites
+ ) {
uri = this.window.gBrowser.currentURI;
} else {
// The value could be:
diff --git a/browser/modules/ContentClick.jsm b/browser/modules/ContentClick.jsm
index 767c67880995..872b06488c1a 100644
--- a/browser/modules/ContentClick.jsm
+++ b/browser/modules/ContentClick.jsm
@@ -88,6 +88,7 @@ var ContentClick = {
charset: browser.characterSet,
referrerInfo: E10SUtils.deserializeReferrerInfo(json.referrerInfo),
allowMixedContent: json.allowMixedContent,
+ allowOnionUrlbarRewrites: json.allowOnionUrlbarRewrites,
isContentWindowPrivate: json.isContentWindowPrivate,
originPrincipal: json.originPrincipal,
triggeringPrincipal: json.triggeringPrincipal,
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index cc329a50c109..80678a04e95c 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6543,6 +6543,18 @@ void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
return;
}
+ if (!mAllowOnionUrlbarRewrites) {
+ nsAutoCString oldHost;
+ nsAutoCString newHost;
+ if (NS_SUCCEEDED(oldURI->GetHost(oldHost)) &&
+ StringEndsWith(oldHost, NS_LITERAL_CSTRING(".tor.onion")) &&
+ NS_SUCCEEDED(newURI->GetHost(newHost)) &&
+ StringEndsWith(newHost, NS_LITERAL_CSTRING(".onion")) &&
+ !StringEndsWith(newHost, NS_LITERAL_CSTRING(".tor.onion"))) {
+ mAllowOnionUrlbarRewrites = true;
+ }
+ }
+
// Below a URI visit is saved (see AddURIVisit method doc).
// The visit chain looks something like:
// ...
@@ -9744,6 +9756,10 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
// We're making history navigation or a reload. Make sure our history ID
// points to the same ID as SHEntry's docshell ID.
mHistoryID = aLoadState->SHEntry()->DocshellID();
+ // Loading from session history may not call DoURILoad(), so we set this
+ // flag here.
+ mAllowOnionUrlbarRewrites = aLoadState->HasLoadFlags(
+ INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES);
}
}
@@ -10386,6 +10402,13 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
}
}
+ mAllowOnionUrlbarRewrites =
+ aLoadState->HasLoadFlags(
+ INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES) ||
+ (mAllowOnionUrlbarRewrites && GetCurrentDocChannel() &&
+ NS_SUCCEEDED(
+ nsContentUtils::CheckSameOrigin(GetCurrentDocChannel(), channel)));
+
// hack
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
@@ -11733,6 +11756,7 @@ nsresult nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
triggeringPrincipal, // Channel or provided principal
principalToInherit, csp, mHistoryID, mDynamicallyCreated);
+ entry->SetAllowOnionUrlbarRewrites(mAllowOnionUrlbarRewrites);
entry->SetOriginalURI(originalURI);
entry->SetResultPrincipalURI(resultPrincipalURI);
entry->SetLoadReplace(loadReplace);
@@ -11913,6 +11937,10 @@ nsresult nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) {
srcdoc = VoidString();
}
+ if (aEntry->GetAllowOnionUrlbarRewrites()) {
+ flags |= INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+ }
+
// If there is no valid triggeringPrincipal, we deny the load
MOZ_ASSERT(triggeringPrincipal,
"need a valid triggeringPrincipal to load from history");
@@ -13817,3 +13845,12 @@ nsDocShell::SetWatchedByDevtools(bool aWatched) {
mWatchedByDevtools = aWatched;
return NS_OK;
}
+
+NS_IMETHODIMP
+nsDocShell::GetAllowOnionUrlbarRewrites(bool* aAllowOnionUrlbarRewrites) {
+ NS_ENSURE_ARG(aAllowOnionUrlbarRewrites);
+ *aAllowOnionUrlbarRewrites =
+ StaticPrefs::browser_urlbar_onionRewrites_enabled() &&
+ mAllowOnionUrlbarRewrites;
+ return NS_OK;
+}
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
index 4a81946f7bf4..7de079c0903e 100644
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -153,6 +153,9 @@ class nsDocShell final : public nsDocLoader,
// Whether the load was triggered by user interaction.
INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED = 0x1000,
+
+ // Whether rewriting the urlbar to a short .onion alias is allowed.
+ INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES = 0x2000,
};
// Event type dispatched by RestorePresentation
@@ -1235,6 +1238,7 @@ class nsDocShell final : public nsDocLoader,
bool mCSSErrorReportingEnabled : 1;
bool mAllowAuth : 1;
bool mAllowKeywordFixup : 1;
+ bool mAllowOnionUrlbarRewrites : 1;
bool mIsOffScreenBrowser : 1;
bool mIsActive : 1;
bool mDisableMetaRefreshWhenInactive : 1;
diff --git a/docshell/base/nsDocShellLoadState.cpp b/docshell/base/nsDocShellLoadState.cpp
index d2e21edceeda..80143b49f3fa 100644
--- a/docshell/base/nsDocShellLoadState.cpp
+++ b/docshell/base/nsDocShellLoadState.cpp
@@ -417,6 +417,10 @@ void nsDocShellLoadState::CalculateLoadURIFlags() {
mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
+ if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES) {
+ mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+ }
+
if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
}
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
index 542232892c5b..cc0013e80c10 100644
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -1195,4 +1195,9 @@ interface nsIDocShell : nsIDocShellTreeItem
* Whether developer tools are watching activity in this docshell.
*/
[infallible] attribute boolean watchedByDevtools;
+
+ /**
+ * Whether rewriting the urlbar to a short .onion alias is allowed.
+ */
+ [infallible] readonly attribute boolean allowOnionUrlbarRewrites;
};
diff --git a/docshell/base/nsIWebNavigation.idl b/docshell/base/nsIWebNavigation.idl
index cabae3f31d0f..123129d2c259 100644
--- a/docshell/base/nsIWebNavigation.idl
+++ b/docshell/base/nsIWebNavigation.idl
@@ -227,6 +227,11 @@ interface nsIWebNavigation : nsISupports
const unsigned long LOAD_FLAGS_IS_REDIRECT = 0x800000;
/**
+ * Allow rewriting the urlbar to a short .onion alias.
+ */
+ const unsigned long LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES = 0x1000000;
+
+ /**
* 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
* however, the URI dispatcher will go through its normal process of content
diff --git a/docshell/shistory/nsISHEntry.idl b/docshell/shistory/nsISHEntry.idl
index 12dbf8172262..f5863b532a28 100644
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -230,6 +230,11 @@ interface nsISHEntry : nsISupports
[infallible] attribute boolean persist;
/**
+ * Whether rewriting the urlbar to a short .onion alias is allowed.
+ */
+ [infallible] attribute boolean allowOnionUrlbarRewrites;
+
+ /**
* 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 e39b5888c157..27f21a23d2ba 100644
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -42,7 +42,8 @@ nsSHEntry::nsSHEntry()
mIsSrcdocEntry(false),
mScrollRestorationIsManual(false),
mLoadedInThisProcess(false),
- mPersist(true) {}
+ mPersist(true),
+ mAllowOnionUrlbarRewrites(false) {}
nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
: mShared(aOther.mShared),
@@ -68,7 +69,8 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
mIsSrcdocEntry(aOther.mIsSrcdocEntry),
mScrollRestorationIsManual(false),
mLoadedInThisProcess(aOther.mLoadedInThisProcess),
- mPersist(aOther.mPersist) {}
+ mPersist(aOther.mPersist),
+ mAllowOnionUrlbarRewrites(aOther.mAllowOnionUrlbarRewrites) {}
nsSHEntry::~nsSHEntry() {
// Null out the mParent pointers on all our kids.
@@ -855,3 +857,15 @@ nsSHEntry::SetPersist(bool aPersist) {
mPersist = aPersist;
return NS_OK;
}
+
+NS_IMETHODIMP
+nsSHEntry::GetAllowOnionUrlbarRewrites(bool* aAllowOnionUrlbarRewrites) {
+ *aAllowOnionUrlbarRewrites = mAllowOnionUrlbarRewrites;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetAllowOnionUrlbarRewrites(bool aAllowOnionUrlbarRewrites) {
+ mAllowOnionUrlbarRewrites = aAllowOnionUrlbarRewrites;
+ return NS_OK;
+}
diff --git a/docshell/shistory/nsSHEntry.h b/docshell/shistory/nsSHEntry.h
index 4a9d7e466b22..aeb42b307739 100644
--- a/docshell/shistory/nsSHEntry.h
+++ b/docshell/shistory/nsSHEntry.h
@@ -61,6 +61,7 @@ class nsSHEntry final : public nsISHEntry {
bool mScrollRestorationIsManual;
bool mLoadedInThisProcess;
bool mPersist;
+ bool mAllowOnionUrlbarRewrites;
};
#endif /* nsSHEntry_h */
diff --git a/modules/libpref/init/StaticPrefList.h b/modules/libpref/init/StaticPrefList.h
index 47f4626f7e6b..29732ac3e884 100644
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -2650,6 +2650,13 @@ VARCACHE_PREF(
bool, false
)
+// Whether rewriting the urlbar to a short .onion alias is allowed.
+VARCACHE_PREF(
+ "browser.urlbar.onionRewrites.enabled",
+ browser_urlbar_onionRewrites_enabled,
+ bool, true
+)
+
//---------------------------------------------------------------------------
// ChannelClassifier prefs
//---------------------------------------------------------------------------
diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat
index 70e198aa3712..0c53819d860d 100644
--- a/netwerk/dns/effective_tld_names.dat
+++ b/netwerk/dns/effective_tld_names.dat
@@ -5495,6 +5495,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/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
index 6d971c10180a..76ce03dc6897 100644
--- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
+++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
@@ -60,6 +60,7 @@ RemoteWebNavigation.prototype = {
LOAD_FLAGS_ALLOW_POPUPS: 32768,
LOAD_FLAGS_BYPASS_CLASSIFIER: 65536,
LOAD_FLAGS_FORCE_ALLOW_COOKIES: 131072,
+ LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES: 16777216,
STOP_NETWORK: 1,
STOP_CONTENT: 2,
diff --git a/toolkit/content/widgets/browser-custom-element.js b/toolkit/content/widgets/browser-custom-element.js
index f31058012cbb..d26c8f8f0d1d 100644
--- a/toolkit/content/widgets/browser-custom-element.js
+++ b/toolkit/content/widgets/browser-custom-element.js
@@ -283,6 +283,8 @@
this._mayEnableCharacterEncodingMenu = null;
+ this._allowOnionUrlbarRewrites = false;
+
this._contentPrincipal = null;
this._csp = null;
@@ -677,6 +679,12 @@
: this.docShell.mayEnableCharacterEncodingMenu;
}
+ get allowOnionUrlbarRewrites() {
+ return this.isRemoteBrowser
+ ? this._allowOnionUrlbarRewrites
+ : this.docShell.allowOnionUrlbarRewrites;
+ }
+
get contentPrincipal() {
return this.isRemoteBrowser
? this._contentPrincipal
@@ -1870,6 +1878,7 @@
"_textZoom",
"_isSyntheticDocument",
"_innerWindowID",
+ "_allowOnionUrlbarRewrites",
]
);
}
diff --git a/toolkit/modules/RemoteWebProgress.jsm b/toolkit/modules/RemoteWebProgress.jsm
index 0f3c53a17a8c..558c31515570 100644
--- a/toolkit/modules/RemoteWebProgress.jsm
+++ b/toolkit/modules/RemoteWebProgress.jsm
@@ -281,6 +281,8 @@ class RemoteWebProgressManager {
this._browser._isSyntheticDocument = json.synthetic;
this._browser._innerWindowID = json.innerWindowID;
this._browser._contentRequestContextID = json.requestContextID;
+ this._browser._allowOnionUrlbarRewrites =
+ json.allowOnionUrlbarRewrites;
}
this.onLocationChange(webProgress, request, location, flags);
diff --git a/toolkit/modules/WebProgressChild.jsm b/toolkit/modules/WebProgressChild.jsm
index 60a1aa88e8ef..26250e361bd4 100644
--- a/toolkit/modules/WebProgressChild.jsm
+++ b/toolkit/modules/WebProgressChild.jsm
@@ -167,6 +167,7 @@ class WebProgressChild {
json.requestContextID = this.mm.content.document.documentLoadGroup
? this.mm.content.document.documentLoadGroup.requestContextID
: null;
+ json.allowOnionUrlbarRewrites = this.mm.docShell.allowOnionUrlbarRewrites;
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
let uri = aLocationURI;
diff --git a/toolkit/modules/sessionstore/SessionHistory.jsm b/toolkit/modules/sessionstore/SessionHistory.jsm
index e54ab3369cd8..463f147a9ca4 100644
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -287,6 +287,7 @@ var SessionHistoryInternal = {
}
entry.persist = shEntry.persist;
+ entry.allowOnionUrlbarRewrites = shEntry.allowOnionUrlbarRewrites;
return entry;
},
@@ -559,6 +560,10 @@ var SessionHistoryInternal = {
}
}
+ if (entry.allowOnionUrlbarRewrites) {
+ shEntry.allowOnionUrlbarRewrites = entry.allowOnionUrlbarRewrites;
+ }
+
return shEntry;
},
1
0

[tor-browser/tor-browser-68.6.0esr-9.5-1] Merge commit 'da5513527e50e7f13e3b1c3206ed75ff8fbd76db' into tor-browser-68.6.0esr-9.5-1
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit 2d2c850302274bdf1a506949856c91c5b138983c
Merge: 31200493ae90 da5513527e50
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 3 02:13:56 2020 +0000
Merge commit 'da5513527e50e7f13e3b1c3206ed75ff8fbd76db' into tor-browser-68.6.0esr-9.5-1
browser/base/content/browser.js | 12 ++
browser/base/content/browser.xul | 3 +
browser/components/BrowserGlue.jsm | 10 ++
.../onionservices/OnionLocationChild.jsm | 43 ++++++
.../onionservices/OnionLocationParent.jsm | 161 +++++++++++++++++++++
.../content/onionlocation-notification-icons.css | 5 +
.../onionservices/content/onionlocation-urlbar.css | 27 ++++
.../content/onionlocation-urlbar.inc.xul | 10 ++
.../onionservices/content/onionlocation.svg | 3 +
.../content/onionlocationPreferences.inc.xul | 11 ++
.../content/onionlocationPreferences.js | 31 ++++
browser/components/onionservices/jar.mn | 2 +
browser/components/onionservices/moz.build | 2 +
.../components/preferences/in-content/privacy.js | 17 +++
.../components/preferences/in-content/privacy.xul | 2 +
browser/modules/TorStrings.jsm | 39 +++++
browser/themes/shared/notification-icons.inc.css | 2 +
browser/themes/shared/urlbar-searchbar.inc.css | 2 +
dom/base/Document.cpp | 32 +++-
dom/base/Document.h | 2 +
dom/webidl/Document.webidl | 9 ++
modules/libpref/init/StaticPrefList.h | 7 +
xpcom/ds/StaticAtoms.py | 1 +
23 files changed, 432 insertions(+), 1 deletion(-)
diff --cc browser/components/onionservices/moz.build
index e4b6d73f8f40,bf276c4a3c4c..dfd664df434e
--- a/browser/components/onionservices/moz.build
+++ b/browser/components/onionservices/moz.build
@@@ -1,7 -1,6 +1,9 @@@
JAR_MANIFESTS += ['jar.mn']
EXTRA_JS_MODULES += [
+ 'ExtensionMessaging.jsm',
+ 'HttpsEverywhereControl.jsm',
+ 'OnionAliasStore.jsm',
+ 'OnionLocationChild.jsm',
+ 'OnionLocationParent.jsm',
]
1
0

[tor-browser/tor-browser-68.6.0esr-9.5-1] fixup! Pick up latest Torbutton code
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit 51cf695dd401dc0ce322c32145b207e13904ce65
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 3 02:21:53 2020 +0000
fixup! Pick up latest Torbutton code
---
toolkit/torproject/torbutton | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/toolkit/torproject/torbutton b/toolkit/torproject/torbutton
index ce150c56c02a..dd027529aecd 160000
--- a/toolkit/torproject/torbutton
+++ b/toolkit/torproject/torbutton
@@ -1 +1 @@
-Subproject commit ce150c56c02a3bd48b345d104132b9d4868bd174
+Subproject commit dd027529aecd4f6632c41b2f07bd6519b0e4cbf5
1
0

03 Apr '20
commit 8026b5ea1bff17c30a95df2192b475e569501a2d
Author: Alex Catarineu <acat(a)torproject.org>
Date: Tue Mar 10 19:13:37 2020 +0100
Bug 21952: Add strings for Onion-Location
---
chrome/locale/en-US/torbutton.properties | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/chrome/locale/en-US/torbutton.properties b/chrome/locale/en-US/torbutton.properties
index 375067b3..49c72194 100644
--- a/chrome/locale/en-US/torbutton.properties
+++ b/chrome/locale/en-US/torbutton.properties
@@ -80,3 +80,17 @@ onionServices.authPreferences.remove=Remove
onionServices.authPreferences.removeAll=Remove All
onionServices.authPreferences.failedToGetKeys=Unable to retrieve keys from tor
onionServices.authPreferences.failedToRemoveKey=Unable to remove key
+
+# Onion-Location strings.
+onionLocation.alwaysPrioritize=Always Prioritize Onions
+onionLocation.alwaysPrioritizeAccessKey=a
+onionLocation.notNow=Not Now
+onionLocation.notNowAccessKey=n
+onionLocation.description=There's a more private and secure version of this site available over the Tor network via onion services. Onion services help website publishers and their visitors defeat surveillance and censorship.
+onionLocation.tryThis=Try Onion Services
+onionLocation.onionAvailable=.onion available
+onionLocation.learnMore=Learn more…
+onionLocation.always=Always
+onionLocation.askEverytime=Ask every time
+onionLocation.prioritizeOnionsDescription=Prioritize .onion sites when known.
+onionLocation.onionServicesTitle=Onion Services
1
0

[torbutton/master] Merge remote-tracking branch 'bradetpo/bug19251-03'
by sysrqb@torproject.org 03 Apr '20
by sysrqb@torproject.org 03 Apr '20
03 Apr '20
commit 751a8d02b6ca5e7c8e2a05972c83f2776996f3d8
Merge: d2ca013e 7ce7e376
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 3 01:57:57 2020 +0000
Merge remote-tracking branch 'bradetpo/bug19251-03'
chrome/locale/en-US/torbutton.properties | 49 ++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
1
0