Unverified Commit 88be7039 authored by Richard Pospesel's avatar Richard Pospesel Committed by boklm
Browse files

Bug 40416: Add v2 Onion deprecation warnings

- adds new v2 deprecated warning page (js and styling) that piggy-backs
  off of the existing added onion service errors
- updates identity-icon to onionWarning.svg when visiting a v2 onion site adds
  warning tooltip; this warning supersedes all other identity states (including
  mixed-content error)
- we determine whether to show the warning page in nsDocShell::DoURILoad()
- a new synchonous IPC method is added to ContentChild/ContentParent to determine
  if the session has loaded the warning page already; worst case scenario, each
  child process will need to wait on this method to return only once when visiting
  a v2 onion; nothing is permanently cached with regards to this change
- an exception for the new sync method is added to sync-messages.ini (generally,
  in practice adding new blocking methods is probably bad, but the minimial
  overhead and frequency this method is called is worth the simpler code)
parent 7532b694
......@@ -207,7 +207,10 @@
</div>
</div>
</div>
<!-- The onion pattern is disabled by default unless the onionPattern.css is also included; we include onionPattern.css programmatically in the v2Deprecation error page, so the onion pattern will not be visible in all error pages -->
#include ../../themes/shared/onionPattern.inc.xhtml
</body>
<script src="chrome://browser/content/onionservices/netError/v2Deprecated.js"/>
<script src="chrome://browser/content/onionservices/netError/onionNetError.js"/>
<script src="chrome://browser/content/aboutNetError.js"/>
</html>
......@@ -135,6 +135,15 @@ var gIdentityHandler = {
return this._uriHasHost ? this._uri.host.toLowerCase().endsWith(".onion") : false;
},
get _uriIsDeprecatedOnionHost() {
const hostIsV2Onion = function(host) {
// matches on v2 onion domains with any number of subdomains
const pattern = /^(.*\.)*[a-z2-7]{16}\.onion/i;
return pattern.test(host);
};
return this._uriHasHost ? hostIsV2Onion(this._uri.host) : false;
},
// smart getters
get _identityPopup() {
delete this._identityPopup;
......@@ -685,6 +694,9 @@ var gIdentityHandler = {
"identity.extension.label",
[extensionName]
);
} else if (this._uriIsDeprecatedOnionHost) {
this._identityBox.className = "onionServiceDeprecated";
tooltip = TorStrings.onionServices.v2Deprecated.tooltip;
} else if (this._uriHasHost && this._isSecureConnection && this._secInfo) {
// This is a secure connection.
// _isSecureConnection implicitly includes onion services, which may not have an SSL certificate
......
......@@ -22,7 +22,7 @@ browser.jar:
content/browser/logos/send.svg (content/logos/send.svg)
content/browser/logos/tracking-protection.svg (content/logos/tracking-protection.svg)
content/browser/logos/tracking-protection-dark-theme.svg (content/logos/tracking-protection-dark-theme.svg)
content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml)
* content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml)
content/browser/aboutNetError.js (content/aboutNetError.js)
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
content/browser/aboutFrameCrashed.html (content/aboutFrameCrashed.html)
......
......@@ -38,6 +38,12 @@ var OnionServicesAboutNetError = {
const errPrefix = "onionServices.";
const errName = err.substring(errPrefix.length);
// tor-browser#40416 - remove this page and updated onionNetErrors with new error once v2 no longer works at all
if (errName === "v2Deprecated") {
V2DeprecatedAboutNetError.initPage(aDoc);
return;
}
this._strings = RPMGetTorStrings();
const stringsObj = this._strings[errName];
......
%include ../../../../themes/shared/onionPattern.css
:root {
--onion-opacity: 1;
--onion-color: var(--card-outline-color);
--onion-radius: 50px;
}
body {
border: 1.5em solid #FED916;
justify-content: space-between;
}
div.title {
background-image: url("chrome://browser/skin/onion-warning.svg");
}
div#errorPageContainer {
padding-top: 20vh;
width: 66%;
}
div#learnMoreContainer {
display: block;
}
\ No newline at end of file
// Copyright (c) 2021, The Tor Project, Inc.
"use strict";
/* eslint-env mozilla/frame-script */
var V2DeprecatedAboutNetError = {
_selector: {
header: ".title-text",
longDesc: "#errorLongDesc",
learnMoreLink: "#learnMoreLink",
contentContainer: "#errorLongContent",
tryAgainButton: "div#netErrorButtonContainer button.try-again",
},
initPage(aDoc) {
this._insertStylesheet(aDoc);
this._populateStrings(aDoc);
},
_populateStrings(aDoc) {
// populate strings
const TorStrings = RPMGetTorStrings();
aDoc.title = TorStrings.v2Deprecated.pageTitle;
let headerElem = aDoc.querySelector(this._selector.header);
headerElem.textContent = TorStrings.v2Deprecated.header;
let longDescriptionElem = aDoc.querySelector(this._selector.longDesc);
longDescriptionElem.textContent = TorStrings.v2Deprecated.longDescription;
let learnMoreElem = aDoc.querySelector(this._selector.learnMoreLink);
learnMoreElem.setAttribute("href", TorStrings.v2Deprecated.learnMoreURL);
let tryAgainElem = aDoc.querySelector(this._selector.tryAgainButton);
tryAgainElem.textContent = TorStrings.v2Deprecated.tryAgain;
},
_insertStylesheet(aDoc) {
const url =
"chrome://browser/content/onionservices/netError/v2Deprecated.css";
let linkElem = aDoc.createElement("link");
linkElem.rel = "stylesheet";
linkElem.href = url;
linkElem.type = "text/css";
aDoc.head.appendChild(linkElem);
},
};
......@@ -3,7 +3,13 @@ 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/netError/browser.svg (content/netError/browser.svg)
content/browser/onionservices/netError/network.svg (content/netError/network.svg)
content/browser/onionservices/netError/onionNetError.css (content/netError/onionNetError.css)
content/browser/onionservices/netError/onionNetError.js (content/netError/onionNetError.js)
content/browser/onionservices/netError/onionsite.svg (content/netError/onionsite.svg)
* content/browser/onionservices/netError/v2Deprecated.css (content/netError/v2Deprecated.css)
content/browser/onionservices/netError/v2Deprecated.js (content/netError/v2Deprecated.js)
content/browser/onionservices/onionservices.css (content/onionservices.css)
content/browser/onionservices/savedKeysDialog.js (content/savedKeysDialog.js)
content/browser/onionservices/savedKeysDialog.xhtml (content/savedKeysDialog.xhtml)
......
......@@ -502,6 +502,14 @@ var TorStrings = {
header: getString("introTimedOut.header", "Onionsite Circuit Creation Timed Out"),
longDescription: getString("introTimedOut.longDescription", kLongDescFallback),
},
v2Deprecated: { // Deprecation page for v2 Onions
pageTitle: getString("v2Deprecated.pageTitle", "V2 Onion Site Deprecation Warning"),
header: getString("v2Deprecated.header", "Version 2 Onion Sites will be deprecated soon"),
longDescription: getString("v2Deprecated.longDescription", "Tor is ending its support for version 2 onion services beginning in July 2021, and this onion site will no longer be reachable at this address. If you are the site administrator, upgrade to a version 3 onion service soon."),
learnMoreURL: `https://support.torproject.org/${getLocale()}/onionservices/#v2-deprecation`,
tryAgain: getString("v2Deprecated.tryAgain", "Got it"),
tooltip: getString("v2Deprecated.tooltip", "This onion site will not be reachable soon"),
},
authPrompt: {
description:
getString("authPrompt.description2", "%S is requesting that you authenticate."),
......
......@@ -181,7 +181,8 @@ toolbar[brighttext] #identity-box[pageproxystate="valid"].chromeUI > #identity-i
#identity-box[pageproxystate="valid"].onionMixedDisplayContent > #identity-icon,
#identity-box[pageproxystate="valid"].onionMixedDisplayContentLoadedActiveBlocked > #identity-icon,
#identity-box[pageproxystate="valid"].onionCertUserOverridden > #identity-icon {
#identity-box[pageproxystate="valid"].onionCertUserOverridden > #identity-icon,
#identity-box[pageproxystate="valid"].onionServiceDeprecated > #identity-icon {
list-style-image: url(chrome://browser/skin/onion-warning.svg);
visibility: visible;
}
......
......@@ -9,9 +9,11 @@
- most browser windows, typically the two rows of onions will fill the
- bottom of the page. On really wide pages, the onions are centered at
- the bottom of the page.
- The root onion-pattern-container div is hidden by default, and can be
- enabled by including onionPattern.css
-->
<div class="onion-pattern-container">
<div class="onion-pattern-container" style="display: none">
<!-- for some reason, these two elements are focusable, seems related to
- flex css somehow; disable their tabindex to fix
-->
......
......@@ -7,6 +7,7 @@
#include "nsDocShell.h"
#include <algorithm>
#include <regex>
#ifdef XP_WIN
# include <process.h>
......@@ -3645,6 +3646,9 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
case NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT:
error = "onionServices.introTimedOut";
break;
case NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED:
error = "onionServices.v2Deprecated";
break;
default:
break;
}
......@@ -9596,6 +9600,63 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
return NS_OK;
}
// tor-browser#40416
// we only ever want to show the warning page once per session
const auto shouldShouldShowV2DeprecationPage = []() -> bool {
bool retval = false;
if (XRE_IsContentProcess()) {
auto* cc = ContentChild::GetSingleton();
cc->SendShouldShowV2DeprecationPage(&retval);
}
return retval;
};
const auto uriIsV2Onion = [](nsIURI* uri) -> bool {
if (uri) {
nsAutoCString hostString;
uri->GetHost(hostString);
const std::string_view host(hostString.BeginReading(), hostString.Length());
// matches v2 onions with any number of subdomains
const static std::regex v2OnionPattern{
"^(.*\\.)*[a-z2-7]{16}\\.onion",
std::regex::icase | std::regex::optimize
};
// see if the uri refers to v2 onion host
return std::regex_match(
host.begin(),
host.end(),
v2OnionPattern);
}
return false;
};
// only dip in here if this process thinks onion warning page has not been shown
static bool v2DeprecationPageShown = false;
if (!v2DeprecationPageShown) {
// now only advance if the URI we are dealing with
// is a v2 onion address
auto uri = aLoadState->URI();
if (uriIsV2Onion(uri)) {
// Ok, so we are dealing with a v2 onion, now make
// sure the v2 deprecation page has not been shown in
// in another content process
//
// This is a synchrynous call, so we are blocking until
// we hear back from from the parent process. Each child
// process will need to perform this wait at most once,
// since we are locally caching in v2DeprecationPageShown.
v2DeprecationPageShown = true;
if (shouldShouldShowV2DeprecationPage()) {
DisplayLoadError(NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED, uri, nullptr, nullptr);
return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
}
}
}
nsCOMPtr<nsIURILoader> uriLoader = components::URILoader::Service();
if (NS_WARN_IF(!uriLoader)) {
return NS_ERROR_UNEXPECTED;
......
......@@ -6515,6 +6515,17 @@ NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName,
return NS_OK;
}
mozilla::ipc::IPCResult ContentParent::RecvShouldShowV2DeprecationPage(bool* showPage) {
static bool v2DeprecationPageShown = false;
if (v2DeprecationPageShown) {
*showPage = false;
} else {
*showPage = true;
v2DeprecationPageShown = true;
}
return IPC_OK();
}
} // namespace dom
} // namespace mozilla
......
......@@ -1280,6 +1280,8 @@ class ContentParent final
const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
HistoryGoResolver&& aResolveRequestedIndex);
mozilla::ipc::IPCResult RecvShouldShowV2DeprecationPage(bool* showPage);
// Notify the ContentChild to enable the input event prioritization when
// initializing.
void MaybeEnableRemoteInputEventQueue();
......
......@@ -1678,6 +1678,9 @@ child:
// WindowContext is managed using the PWindowGlobal actor's lifecycle.
async CreateWindowContext(WindowContextInitializer aInit);
async DiscardWindowContext(uint64_t aContextId) returns (bool unused);
parent:
sync ShouldShowV2DeprecationPage() returns (bool showPage);
};
}
......
......@@ -1040,6 +1040,9 @@ description = Initialization of WebGL contexts is synchronous by spec.
description = Synchronous RPC to allow WebGL to run graphics commands in compositor process and return results to be used in JS return values.
[PSocketProcess::GetTLSClientCert]
description = Synchronously get client certificate and key from parent process. Once bug 696976 has been fixed, this can be removed.
[PContent::ShouldShowV2DeprecationPage]
description = Synchronously determine whether a client process has already displayed the v2 onion deprecation warning page
#############################################################
# AVOID ADDING NEW MESSAGES TO THIS FILE #
......
......@@ -262,6 +262,7 @@ XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH, "Tor onion service missi
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")
XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED , "Tor v2 onion services are deprecated")
/* Profile manager error codes */
XPC_MSG_DEF(NS_ERROR_DATABASE_CHANGED , "Flushing the profiles to disk would have overwritten changes made elsewhere.")
......@@ -1200,6 +1200,8 @@ with modules["TOR"]:
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)
# Tor v2 onion services are deprecated
errors["NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED"] = FAILURE(9)
# =======================================================================
# 51: NS_ERROR_MODULE_GENERAL
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment