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

Keyboard Shortcuts

Thread View

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

tbb-commits

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

  • 1 participants
  • 19540 discussions
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 27604: Fix addon issues when moving TB directory
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 08f0bdb25b0ac5b0025616807f8ba7149b3c12ef Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Oct 30 10:44:48 2019 +0100 Bug 27604: Fix addon issues when moving TB directory --- toolkit/mozapps/extensions/internal/XPIProvider.jsm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 5bd7cabb0f73..c1cef2814b38 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -475,7 +475,7 @@ class XPIState { // Builds prior to be 1512436 did not include the rootURI property. // If we're updating from such a build, add that property now. - if (!("rootURI" in this) && this.file) { + if (this.file) { this.rootURI = getURIForResourceInFile(this.file, "").spec; } @@ -488,7 +488,10 @@ class XPIState { saved.currentModifiedTime != this.lastModifiedTime ) { this.lastModifiedTime = saved.currentModifiedTime; - } else if (saved.currentModifiedTime === null) { + } else if ( + saved.currentModifiedTime === null && + (!this.file || !this.file.exists()) + ) { this.missing = true; } } @@ -1449,6 +1452,7 @@ var XPIStates = { if (shouldRestoreLocationData && oldState[loc.name]) { loc.restore(oldState[loc.name]); + changed = changed || loc.path != oldState[loc.name].path; } changed = changed || loc.changed;
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 18800: Remove localhost DNS lookup in nsProfileLock.cpp
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 0dfdc4674d30ff19b6bc4101d99c51563df21bc3 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Thu Apr 21 10:40:26 2016 -0400 Bug 18800: Remove localhost DNS lookup in nsProfileLock.cpp Instead of using the local computer's IP address within symlink-based profile lock signatures, always use 127.0.0.1. --- toolkit/profile/nsProfileLock.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/toolkit/profile/nsProfileLock.cpp b/toolkit/profile/nsProfileLock.cpp index 28d38c11684e..a1b3edc54a05 100644 --- a/toolkit/profile/nsProfileLock.cpp +++ b/toolkit/profile/nsProfileLock.cpp @@ -304,18 +304,17 @@ nsresult nsProfileLock::LockWithSymlink(nsIFile* aLockFile, if (!mReplacedLockTime) aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime); + // For Tor Browser, avoid a DNS lookup here so the Tor network is not + // bypassed. Instead, always use 127.0.0.1 for the IP address portion + // of the lock signature, which may cause the browser to refuse to + // start in the rare event that all of the following conditions are met: + // 1. The browser profile is on a network file system. + // 2. The file system does not support fcntl() locking. + // 3. Tor Browser is run from two different computers at the same time. + struct in_addr inaddr; inaddr.s_addr = htonl(INADDR_LOOPBACK); - char hostname[256]; - PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname); - if (status == PR_SUCCESS) { - char netdbbuf[PR_NETDB_BUF_SIZE]; - PRHostEnt hostent; - status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent); - if (status == PR_SUCCESS) memcpy(&inaddr, hostent.h_addr, sizeof inaddr); - } - mozilla::SmprintfPointer signature = mozilla::Smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "", (unsigned long)getpid());
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 16620: Clear window.name when no referrer sent
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 2e41837dcbbee9e8f66cbc09a25883f4402cb4bb Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Fri Oct 30 14:28:13 2015 -0400 Bug 16620: Clear window.name when no referrer sent Convert JS implementation (within Torbutton) to a C++ browser patch. --- docshell/base/nsDocShell.cpp | 60 +++++++ docshell/test/mochitest/mochitest.ini | 5 + docshell/test/mochitest/test_tor_bug16620.html | 211 +++++++++++++++++++++++++ docshell/test/mochitest/tor_bug16620.html | 51 ++++++ docshell/test/mochitest/tor_bug16620_form.html | 51 ++++++ modules/libpref/init/StaticPrefList.yaml | 2 +- 6 files changed, 379 insertions(+), 1 deletion(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index c04a496bdf07..04961ae2d9e0 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -7672,11 +7672,71 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType, aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI)); } FirePageHideNotification(!mSavingOldViewer); + if (mIsBeingDestroyed) { // Force to stop the newly created orphaned viewer. viewer->Stop(); return NS_ERROR_DOCSHELL_DYING; } + + // Tor bug 16620: Clear window.name of top-level documents if + // there is no referrer. We make an exception for new windows, + // e.g., window.open(url, "MyName"). + bool isNewWindowTarget = false; + nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aRequest, &rv)); + if (props) { + props->GetPropertyAsBool(u"docshell.newWindowTarget"_ns, + &isNewWindowTarget); + } + + if (!isNewWindowTarget) { + nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aOpenedChannel)); + nsCOMPtr<nsIURI> httpReferrer; + if (httpChannel) { + nsCOMPtr<nsIReferrerInfo> referrerInfo; + rv = httpChannel->GetReferrerInfo(getter_AddRefs(referrerInfo)); + NS_ENSURE_SUCCESS(rv, rv); + if (referrerInfo) { + // We want GetComputedReferrer() instead of GetOriginalReferrer(), since + // the former takes into consideration referrer policy, protocol + // whitelisting... + httpReferrer = referrerInfo->GetComputedReferrer(); + } + } + + bool isTopFrame = mBrowsingContext->IsTop(); + +#ifdef DEBUG_WINDOW_NAME + printf("DOCSHELL %p CreateContentViewer - possibly clearing window.name:\n", + this); + printf(" current window.name: \"%s\"\n", + NS_ConvertUTF16toUTF8(mName).get()); + + nsAutoCString curSpec, loadingSpec; + if (this->mCurrentURI) mCurrentURI->GetSpec(curSpec); + if (mLoadingURI) mLoadingURI->GetSpec(loadingSpec); + printf(" current URI: %s\n", curSpec.get()); + printf(" loading URI: %s\n", loadingSpec.get()); + printf(" is top document: %s\n", isTopFrame ? "Yes" : "No"); + + if (!httpReferrer) { + printf(" referrer: None\n"); + } else { + nsAutoCString refSpec; + httpReferrer->GetSpec(refSpec); + printf(" referrer: %s\n", refSpec.get()); + } +#endif + + bool clearName = isTopFrame && !httpReferrer; + if (clearName) SetName(u""_ns); + +#ifdef DEBUG_WINDOW_NAME + printf(" action taken: %s window.name\n", + clearName ? "Cleared" : "Preserved"); +#endif + } + mLoadingURI = nullptr; // Set mFiredUnloadEvent = false so that the unload handler for the diff --git a/docshell/test/mochitest/mochitest.ini b/docshell/test/mochitest/mochitest.ini index cea63f080117..efc991ef1eee 100644 --- a/docshell/test/mochitest/mochitest.ini +++ b/docshell/test/mochitest/mochitest.ini @@ -53,6 +53,10 @@ support-files = start_historyframe.html url1_historyframe.html url2_historyframe.html + tor_bug16620.html + tor_bug16620_form.html +prefs = + gfx.font_rendering.fallback.async=false [test_anchor_scroll_after_document_open.html] [test_bfcache_plus_hash.html] @@ -120,6 +124,7 @@ support-files = [test_framedhistoryframes.html] support-files = file_framedhistoryframes.html [test_pushState_after_document_open.html] +[test_tor_bug16620.html] [test_navigate_after_pagehide.html] [test_redirect_history.html] support-files = diff --git a/docshell/test/mochitest/test_tor_bug16620.html b/docshell/test/mochitest/test_tor_bug16620.html new file mode 100644 index 000000000000..46fff5a04711 --- /dev/null +++ b/docshell/test/mochitest/test_tor_bug16620.html @@ -0,0 +1,211 @@ +<!DOCTYPE HTML> +<html> +<!-- + Tor Bug 16620: Clear window.name when no referrer sent. + https://trac.torproject.org/projects/tor/ticket/16620 +--> +<meta charset="utf-8"> +<head> + <title>Test for Tor Bug 16620 - Clear window.name when no referrer sent</title> + <script type="application/javascript" + src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/16620">Tor Bug 16620</a> +<script> +// ## Test constants +const kTestPath = "/tests/docshell/test/mochitest/"; +const kLinkFile = "tor_bug16620.html"; +const kFormFile = "tor_bug16620_form.html"; +const kBaseURL1 = "http://example.com"; +const kBaseURL1_https = "https://example.com"; +const kBaseURL2 = "http://example.net"; +const kSendReferrerPref = "network.http.sendRefererHeader"; +const kSendReferrerNever = 0; +const kSendReferrerForUserAction = 1; +const kSendReferrerAlways = 2; + +let gTests = [ + // Test #1: Same domain; never send referrer. + { startURL: kBaseURL1, destURL: kBaseURL1, + referrerPref: kSendReferrerNever, + expectIsolation: true }, + + // Test #2: Same domain; send referrer upon user action. + { startURL: kBaseURL1, destURL: kBaseURL1, + referrerPref: kSendReferrerForUserAction, + expectIsolation: false }, + + // Test #3: Same domain; always send referrer. + { startURL: kBaseURL1, destURL: kBaseURL1, + referrerPref: kSendReferrerAlways, + expectIsolation: false }, + + // Test #4: Different top-level domains; never send referrer. + { startURL: kBaseURL1, destURL: kBaseURL2, + referrerPref: kSendReferrerNever, + expectIsolation: true }, + + // Test #5: Different top-level domains; send referrer upon user action. + { startURL: kBaseURL1, destURL: kBaseURL2, + referrerPref: kSendReferrerForUserAction, + expectIsolation: false }, + + // Test #6: Different top-level domains; always send referrer. + { startURL: kBaseURL1, destURL: kBaseURL2, + referrerPref: kSendReferrerAlways, + expectIsolation: false }, + + // Test #7: https -> http transition. + { startURL: kBaseURL1_https, destURL: kBaseURL1, + referrerPref: kSendReferrerForUserAction, + expectIsolation: true }, + + // Test #8: Same domain, rel="noreferrer" on link. + { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerOnLink: true, + referrerPref: kSendReferrerAlways, + expectIsolation: true }, + + // Test #9: Same domain, "no-referrer" meta tag in document. + { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true, + referrerPref: kSendReferrerAlways, + expectIsolation: true }, + + // Test #10: Like test #9, but reset window.name during unload. + // (similar to http://www.thomasfrank.se/sessvarsTestPage1.html) + { startURL: kBaseURL1, destURL: kBaseURL1, noReferrerInMetaTag: true, + resetInUnload: true, + referrerPref: kSendReferrerAlways, + expectIsolation: true }, + + // Test #11: Data URL as destination (no referrer). + { startURL: kBaseURL1, + referrerPref: kSendReferrerAlways, + expectIsolation: true }, + + // Test #12: Ensure that window.name is preserved when a dynamically loaded + // iframe is used to perform a form post (regression test for Tor bug 18168). + { startURL: kBaseURL1, + isFormTest: true, + referrerPref: kSendReferrerAlways, + expectIsolation: false }, +]; + +let gCurTest = 0; +let gCurWinName, gChildWin, gDataURL; + +// ## Utility functions +function generateRandomName() +{ + // Generate a random 6 character string using 0-9 and a-z. + return ((1 + Math.random()).toString(36) + '000000').substr(2, 6); +} + +function startNextTest() { + ++gCurTest; + if (gCurTest > gTests.length) { + SimpleTest.finish(); + } else { + let curTest = gTests[gCurTest - 1]; + if ("referrerPref" in curTest) + SpecialPowers.setIntPref(kSendReferrerPref, curTest.referrerPref); + else + SpecialPowers.setIntPref(kSendReferrerPref, kSendReferrerForUserAction); + gCurWinName = generateRandomName(); + let url = curTest.startURL + kTestPath; + if (curTest.isFormTest === true) { + url += kFormFile + "?" + gCurWinName; + gChildWin = window.open(url, undefined); + } else { + url += kLinkFile + "?firstDocLoaded"; + gChildWin = window.open(url, gCurWinName); + } + } +} + +// ## Add a message event listener. +window.addEventListener("message", function(aEvent) { + if (aEvent.source !== gChildWin) + return; + +// console.log("parent received message:" + JSON.stringify(aEvent.data)); + + let proceedToNextTest = false; + let curTest = gTests[gCurTest - 1]; + let state = aEvent.data.state; + let winName = aEvent.data.winName; + if ("firstDocLoaded" == state) { + // Process response from step one of the link-based tests. + let step1Passed = (winName === gCurWinName); + if (!step1Passed) { + ok(step1Passed, "Test #" + gCurTest + + " - first document's name matches window.open parameter"); + proceedToNextTest = true; + } + + // Send an "openURL" message to the loaded document. + let url2 = (curTest.destURL) + ? curTest.destURL + kTestPath + kLinkFile + "?secondDocLoaded" + : gDataURL; + let noReferrerOnLink = (curTest.noReferrerOnLink === true); + let noReferrerInMetaTag = (curTest.noReferrerInMetaTag === true); + let resetInUnload = (curTest.resetInUnload === true); + aEvent.source.postMessage({ action: "openURL", url: url2, + noReferrerOnLink: noReferrerOnLink, + noReferrerInMetaTag: noReferrerInMetaTag, + resetInUnload: resetInUnload }, + "*"); + } else if ("secondDocLoaded" == state) { + // Process response from step two of the link-based tests. + if (curTest.expectIsolation) { + ok(winName === "", + "Test #" + gCurTest + " - second document: name was cleared"); + } else { + ok(winName === gCurWinName, + "Test #" + gCurTest + " - second document: name was preserved"); + } + proceedToNextTest = true; + } else if ("formPostDone" == state) { + // Process response from the form post tests. + if (curTest.expectIsolation) { + ok(winName === "", + "Test #" + gCurTest + " - iframe form post: name was cleared"); + } else { + ok(winName === gCurWinName, + "Test #" + gCurTest + " - iframe form post: name was preserved"); + } + proceedToNextTest = true; + + } + + if (proceedToNextTest) { + gChildWin.close(); + startNextTest(); + } + }, false); + + SimpleTest.waitForExplicitFinish(); + + if (SpecialPowers.getBoolPref("security.nocertdb")) { + // Mochitests don't simulate https correctly with "security.nocertdb" + // enabled. See https://bugs.torproject.org/18087 + ok(false, "Please disable the pref `security.nocertdb` before running this test."); + SimpleTest.finish(); + } else { + + // Read file contents, construct a data URL (used by some tests), and + // then start the first test. + let url = kTestPath + kLinkFile; + let xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = function() { + gDataURL = "data:text/html;charset=utf-8," + + encodeURIComponent(this.responseText); + startNextTest(); + } + xhr.send(); + } +</script> +</body> +</html> diff --git a/docshell/test/mochitest/tor_bug16620.html b/docshell/test/mochitest/tor_bug16620.html new file mode 100644 index 000000000000..26b8e406bbff --- /dev/null +++ b/docshell/test/mochitest/tor_bug16620.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- + Tor Bug 16620: Clear window.name when no referrer sent. + https://trac.torproject.org/projects/tor/ticket/16620 +--> +<head> + <meta charset="UTF-8"> + <title>Supporting Doc for Tor Bug 16620 Tests</title> +</head> +<body> +<a id="link" href="">secondDoc</a> + +<script> +// Extract test state from our query string, defaulting to +// "secondDocLoaded" to support use of this HTML content within +// a data URI (where query strings are not supported). +let state = (location.search.length > 0) ? location.search.substr(1) + : "secondDocLoaded"; + +// Notify the test driver. +opener.postMessage({ state: state, winName: window.name }, "*"); + +// Add a message event listener to process "openURL" actions. +window.addEventListener("message", function(aEvent) { + if (aEvent.data.action == "openURL") { + if (aEvent.data.noReferrerInMetaTag) { + let metaElem = document.createElement("meta"); + metaElem.name = "referrer"; + metaElem.content = "no-referrer"; + document.head.appendChild(metaElem); + } + + let linkElem = document.getElementById("link"); + linkElem.href = aEvent.data.url; + if (aEvent.data.noReferrerOnLink) + linkElem.rel = "noreferrer"; + + if (aEvent.data.resetInUnload) { + let tmpName = window.name; + window.addEventListener("unload", function() { + window.name = tmpName; + }, false); + } + + linkElem.click(); + } +}, false); +</script> +</body> +</html> diff --git a/docshell/test/mochitest/tor_bug16620_form.html b/docshell/test/mochitest/tor_bug16620_form.html new file mode 100644 index 000000000000..279f62e63fab --- /dev/null +++ b/docshell/test/mochitest/tor_bug16620_form.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- + Tor Bug 16620: Clear window.name when no referrer sent. + https://trac.torproject.org/projects/tor/ticket/16620 + + Regression test for bug 18168: iframe-based AJAX call opening in new tab +--> +<head> + <meta charset="UTF-8"> + <title>Supporting Form-based Doc for Tor Bug 16620 Tests</title> +</head> +<body> + +<script> +document.addEventListener("DOMContentLoaded", function () { + addPostTarget(); +}, false); + + +function addPostTarget() +{ + let frameName = location.search.substr(1); + let form = document.getElementById("postform"); + let iframe = document.createElement("iframe"); + iframe.style.border = "1px solid red"; + iframe.src = "about:blank"; + form.target = iframe.name = iframe.id = frameName; + document.body.appendChild(iframe); + + let didSubmit = false; + iframe.onload = function() { + if (!didSubmit) { + didSubmit = true; + let submitButton = document.getElementById("submitButton"); + submitButton.click(); + } else { + // Form submission complete. Report iframe's name to test driver. + opener.postMessage({ state: "formPostDone", winName: iframe.name }, "*"); + } + }; +} + +</script> +<form name="postform" id="postform" + action="data:text/plain;charset=utf-8,Hello%20world" + method="POST" enctype="multipart/form-data"> + <input type="hidden" name="field1" value="value1"><br> + <input id="submitButton" type="submit" value="Post It"> +</body> +</html> diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 058df55a189d..3f578a7d37bc 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -10436,7 +10436,7 @@ - name: privacy.window.name.update.enabled type: bool - value: true + value: false mirror: always # By default, the network state isolation is not active when there is a proxy
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 13028: Prevent potential proxy bypass cases.
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 20677ad10e3f73d4dd41a6ebf890e44b6e5d2a4e Author: Mike Perry <mikeperry-git(a)torproject.org> Date: Mon Sep 29 14:30:19 2014 -0700 Bug 13028: Prevent potential proxy bypass cases. It looks like these cases should only be invoked in the NSS command line tools, and not the browser, but I decided to patch them anyway because there literally is a maze of network function pointers being passed around, and it's very hard to tell if some random code might not pass in the proper proxied versions of the networking code here by accident. --- security/nss/lib/certhigh/ocsp.c | 8 ++++++++ .../lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/security/nss/lib/certhigh/ocsp.c b/security/nss/lib/certhigh/ocsp.c index cea8456606bf..86fa971cfbef 100644 --- a/security/nss/lib/certhigh/ocsp.c +++ b/security/nss/lib/certhigh/ocsp.c @@ -2932,6 +2932,14 @@ ocsp_ConnectToHost(const char *host, PRUint16 port) PRNetAddr addr; char *netdbbuf = NULL; + // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but + // we want to ensure nothing can ever hit this code in production. +#if 1 + printf("Tor Browser BUG: Attempted OSCP direct connect to %s, port %u\n", host, + port); + goto loser; +#endif + sock = PR_NewTCPSocket(); if (sock == NULL) goto loser; diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c index e8698376b5be..85791d84a932 100644 --- a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c @@ -1334,6 +1334,13 @@ pkix_pl_Socket_Create( plContext), PKIX_COULDNOTCREATESOCKETOBJECT); + // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but + // we want to ensure nothing can ever hit this code in production. +#if 1 + printf("Tor Browser BUG: Attempted pkix direct socket connect\n"); + PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); +#endif + socket->isServer = isServer; socket->timeout = timeout; socket->clientSock = NULL; @@ -1433,6 +1440,13 @@ pkix_pl_Socket_CreateByName( localCopyName = PL_strdup(serverName); + // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but + // we want to ensure nothing can ever hit this code in production. +#if 1 + printf("Tor Browser BUG: Attempted pkix direct connect to %s\n", serverName); + PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); +#endif + sepPtr = strchr(localCopyName, ':'); /* First strip off the portnum, if present, from the end of the name */ if (sepPtr) { @@ -1582,6 +1596,13 @@ pkix_pl_Socket_CreateByHostAndPort( PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort"); PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket); + // XXX: Do we need a unittest ifdef here? We don't want to break the tests, but + // we want to ensure nothing can ever hit this code in production. +#if 1 + printf("Tor Browser BUG: Attempted pkix direct connect to %s, port %u\n", hostname, + portnum); + PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); +#endif prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 23104: Add a default line height compensation
by richard@torproject.org 09 Feb '22

09 Feb '22
commit e3a740c51b61988c6360d3dbfed888da653b5cfa Author: Igor Oliveira <igor.oliveira(a)posteo.net> Date: Sun Dec 10 18:16:59 2017 -0200 Bug 23104: Add a default line height compensation Many fonts have issues with their vertical metrics. they are used to influence the height of ascenders and depth of descenders. Gecko uses it to calculate the line height (font height + ascender + descender), however because of that idiosyncratic behavior across multiple operating systems, it can be used to identify the user's OS. The solution proposed in the patch uses a default factor to be multiplied with the font size, simulating the concept of ascender and descender. This way all operating systems will have the same line height only and only if the frame is outside the chrome. --- layout/generic/ReflowInput.cpp | 19 +++++++++--- layout/generic/test/mochitest.ini | 1 + layout/generic/test/test_tor_bug23104.html | 50 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index 2c56afd2e02a..4d30c7762c14 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -31,6 +31,7 @@ #include "mozilla/SVGUtils.h" #include "mozilla/dom/HTMLInputElement.h" #include "nsGridContainerFrame.h" +#include "nsContentUtils.h" using namespace mozilla; using namespace mozilla::css; @@ -2642,7 +2643,8 @@ void ReflowInput::CalculateBlockSideMargins() { // For risk management, we use preference to control the behavior, and // eNoExternalLeading is the old behavior. -static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) { +static nscoord GetNormalLineHeight(nsIContent* aContent, + nsFontMetrics* aFontMetrics) { MOZ_ASSERT(nullptr != aFontMetrics, "no font metrics"); nscoord normalLineHeight; @@ -2650,6 +2652,12 @@ static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) { nscoord externalLeading = aFontMetrics->ExternalLeading(); nscoord internalLeading = aFontMetrics->InternalLeading(); nscoord emHeight = aFontMetrics->EmHeight(); + + if (nsContentUtils::ShouldResistFingerprinting() && + !aContent->IsInChromeDocument()) { + return NSToCoordRound(emHeight * NORMAL_LINE_HEIGHT_FACTOR); + } + switch (GetNormalLineHeightCalcControl()) { case eIncludeExternalLeading: normalLineHeight = emHeight + internalLeading + externalLeading; @@ -2667,7 +2675,8 @@ static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) { return normalLineHeight; } -static inline nscoord ComputeLineHeight(ComputedStyle* aComputedStyle, +static inline nscoord ComputeLineHeight(nsIContent* aContent, + ComputedStyle* aComputedStyle, nsPresContext* aPresContext, nscoord aBlockBSize, float aFontSizeInflation) { @@ -2696,7 +2705,7 @@ static inline nscoord ComputeLineHeight(ComputedStyle* aComputedStyle, RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle( aComputedStyle, aPresContext, aFontSizeInflation); - return GetNormalLineHeight(fm); + return GetNormalLineHeight(aContent, fm); } nscoord ReflowInput::CalcLineHeight() const { @@ -2718,7 +2727,7 @@ nscoord ReflowInput::CalcLineHeight(nsIContent* aContent, float aFontSizeInflation) { MOZ_ASSERT(aComputedStyle, "Must have a ComputedStyle"); - nscoord lineHeight = ComputeLineHeight(aComputedStyle, aPresContext, + nscoord lineHeight = ComputeLineHeight(aContent, aComputedStyle, aPresContext, aBlockBSize, aFontSizeInflation); NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up"); @@ -2731,7 +2740,7 @@ nscoord ReflowInput::CalcLineHeight(nsIContent* aContent, if (!lh.IsNormal()) { RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle( aComputedStyle, aPresContext, aFontSizeInflation); - nscoord normal = GetNormalLineHeight(fm); + nscoord normal = GetNormalLineHeight(aContent, fm); if (lineHeight < normal) { lineHeight = normal; } diff --git a/layout/generic/test/mochitest.ini b/layout/generic/test/mochitest.ini index bde689457ebc..af9dbe3c0444 100644 --- a/layout/generic/test/mochitest.ini +++ b/layout/generic/test/mochitest.ini @@ -145,3 +145,4 @@ skip-if = debug == true || tsan # the test is slow. tsan: bug 1612707 support-files = file_reframe_for_lazy_load_image.html [test_bug1655135.html] +[test_tor_bug23104.html] diff --git a/layout/generic/test/test_tor_bug23104.html b/layout/generic/test/test_tor_bug23104.html new file mode 100644 index 000000000000..8ff1d2190c45 --- /dev/null +++ b/layout/generic/test/test_tor_bug23104.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<meta charset="UTF-8"> +<html> +<head> + <title>Test for Tor Bug #23104: CSS line-height reveals the platform Tor browser is running</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <style type="text/css"> + span { + background-color: #000; + color: #fff; + font-size: 16.5px; + } + </style> +</head> +<body> +<span id="test1">Test1</span> +<span id="test2">كلمة</span> +<span id="test3">ação</span> +<script> + +let setPref = async function (key, value) { + await SpecialPowers.pushPrefEnv({"set": [[key, value]]}); +} + +function getStyle(el, styleprop) { + el = document.getElementById(el); + return document.defaultView.getComputedStyle(el, null).getPropertyValue(styleprop); +} + +function validateElement(elementName, isFingerprintResistent) { + var fontSize = getStyle(elementName, 'font-size'); + var lineHeight = getStyle(elementName, 'line-height'); + var validationCb = isFingerprintResistent ? is : isnot; + validationCb(parseFloat(lineHeight), Math.round(parseFloat(fontSize)) * 1.2, 'Line Height validation'); +} + +add_task(async function() { + await setPref("layout.css.line-height.normal-as-resolved-value.enabled", false); + for (let resistFingerprintingValue of [true, false]) { + await setPref("privacy.resistFingerprinting", resistFingerprintingValue); + for (let elementId of ['test1', 'test2', 'test3']) { + validateElement(elementId, resistFingerprintingValue); + } + } +}); + +</script> +</body> +</html>
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 21830: Copying large text from web console leaks to /tmp
by richard@torproject.org 09 Feb '22

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

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

09 Feb '22
commit 39d02164c2d77fe4c51a33924437d626a2ef568c Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Apr 29 13:08:24 2014 -0400 Bug 11641: change TBB command line flags to be more like Firefox's Unless the -osint command line flag is used, the browser now defaults to the equivalent of -no-remote. There is a new -allow-remote flag that may be used to restore the original (Firefox-like) default behavior. --- toolkit/xre/nsAppRunner.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 75c381724deb..d11e586d7096 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1837,8 +1837,10 @@ static void DumpHelp() { " --migration Start with migration wizard.\n" " --ProfileManager Start with ProfileManager.\n" #ifdef MOZ_HAS_REMOTE - " --no-remote Do not accept or send remote commands; implies\n" + " --no-remote (default) Do not accept or send remote commands; " + "implies\n" " --new-instance.\n" + " --allow-remote Accept and send remote commands.\n" " --new-instance Open new instance, not a new window in running " "instance.\n" #endif @@ -3985,16 +3987,25 @@ int XREMain::XRE_mainInit(bool* aExitFlag) { gSafeMode); #if defined(MOZ_HAS_REMOTE) + // In Tor Browser, remoting is disabled by default unless -osint is used. + bool allowRemote = (CheckArg("allow-remote") == ARG_FOUND); + bool isOsint = (CheckArg("osint", nullptr, CheckArgFlag::None) == ARG_FOUND); + if (!allowRemote && !isOsint) { + SaveToEnv("MOZ_NO_REMOTE=1"); + } // Handle --no-remote and --new-instance command line arguments. Setup // the environment to better accommodate other components and various // restart scenarios. ar = CheckArg("no-remote"); - if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) { + if ((ar == ARG_FOUND) && allowRemote) { + PR_fprintf(PR_STDERR, + "Error: argument --no-remote is invalid when argument " + "--allow-remote is specified\n"); + return 1; + } + if (EnvHasValue("MOZ_NO_REMOTE")) { mDisableRemoteClient = true; mDisableRemoteServer = true; - if (!EnvHasValue("MOZ_NO_REMOTE")) { - SaveToEnv("MOZ_NO_REMOTE=1"); - } } ar = CheckArg("new-instance");
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 40432: Prevent probing installed applications
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 7d4820ae7c54a5b8f9cf046d77ee04c7b7e34d62 Author: Matthew Finkel <sysrqb(a)torproject.org> Date: Mon May 17 18:09:09 2021 +0000 Bug 40432: Prevent probing installed applications --- .../exthandler/nsExternalHelperAppService.cpp | 30 ++++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 021246211a26..0d697b3bec33 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -956,8 +956,33 @@ nsresult nsExternalHelperAppService::GetFileTokenForPath( ////////////////////////////////////////////////////////////////////////////////////////////////////// // begin external protocol service default implementation... ////////////////////////////////////////////////////////////////////////////////////////////////////// + +static const char kExternalProtocolPrefPrefix[] = + "network.protocol-handler.external."; +static const char kExternalProtocolDefaultPref[] = + "network.protocol-handler.external-default"; + NS_IMETHODIMP nsExternalHelperAppService::ExternalProtocolHandlerExists( const char* aProtocolScheme, bool* aHandlerExists) { + + // Replicate the same check performed in LoadURI. + // Deny load if the prefs say to do so + nsAutoCString externalPref(kExternalProtocolPrefPrefix); + externalPref += aProtocolScheme; + bool allowLoad = false; + *aHandlerExists = false; + if (NS_FAILED(Preferences::GetBool(externalPref.get(), &allowLoad))) { + // no scheme-specific value, check the default + if (NS_FAILED( + Preferences::GetBool(kExternalProtocolDefaultPref, &allowLoad))) { + return NS_OK; // missing default pref + } + } + + if (!allowLoad) { + return NS_OK; // explicitly denied + } + nsCOMPtr<nsIHandlerInfo> handlerInfo; nsresult rv = GetProtocolHandlerInfo(nsDependentCString(aProtocolScheme), getter_AddRefs(handlerInfo)); @@ -1000,11 +1025,6 @@ NS_IMETHODIMP nsExternalHelperAppService::IsExposedProtocol( return NS_OK; } -static const char kExternalProtocolPrefPrefix[] = - "network.protocol-handler.external."; -static const char kExternalProtocolDefaultPref[] = - "network.protocol-handler.external-default"; - // static nsresult nsExternalHelperAppService::EscapeURI(nsIURI* aURI, nsIURI** aResult) { MOZ_ASSERT(aURI);
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 40309: Avoid using regional OS locales
by richard@torproject.org 09 Feb '22

09 Feb '22
commit f47256b90d43ea57e8d650c9064ca23920af57c2 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Jan 27 11:28:05 2021 +0100 Bug 40309: Avoid using regional OS locales Only use regional OS locales if the pref `intl.regional_prefs.use_os_locales` is set to true. --- intl/locale/LocaleService.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp index 022d41cab2e2..ac001ee98991 100644 --- a/intl/locale/LocaleService.cpp +++ b/intl/locale/LocaleService.cpp @@ -452,31 +452,6 @@ LocaleService::GetRegionalPrefsLocales(nsTArray<nsCString>& aRetVal) { OSPreferences::GetInstance()->GetRegionalPrefsLocales(aRetVal))) { return NS_OK; } - - // If we fail to retrieve them, return the app locales. - GetAppLocalesAsBCP47(aRetVal); - return NS_OK; - } - - // Otherwise, fetch OS Regional Preferences locales and compare the first one - // to the app locale. If the language subtag matches, we can safely use - // the OS Regional Preferences locale. - // - // This facilitates scenarios such as Firefox in "en-US" and User sets - // regional prefs to "en-GB". - nsAutoCString appLocale; - AutoTArray<nsCString, 10> regionalPrefsLocales; - LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale); - - if (NS_FAILED(OSPreferences::GetInstance()->GetRegionalPrefsLocales( - regionalPrefsLocales))) { - GetAppLocalesAsBCP47(aRetVal); - return NS_OK; - } - - if (LocaleService::LanguagesMatch(appLocale, regionalPrefsLocales[0])) { - aRetVal = regionalPrefsLocales.Clone(); - return NS_OK; } // Otherwise use the app locales.
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 40069: Add helpers for message passing with extensions
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 7959d9346ffe892ed78f9b93964a584186ddd6c9 Author: Alex Catarineu <acat(a)torproject.org> Date: Sun Aug 2 19:12:25 2020 +0200 Bug 40069: Add helpers for message passing with extensions --- toolkit/components/extensions/ExtensionParent.jsm | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/toolkit/components/extensions/ExtensionParent.jsm b/toolkit/components/extensions/ExtensionParent.jsm index 39ce6d608b86..32d264ed6a4f 100644 --- a/toolkit/components/extensions/ExtensionParent.jsm +++ b/toolkit/components/extensions/ExtensionParent.jsm @@ -263,6 +263,8 @@ const ProxyMessenger = { /** @type Map<number, ParentPort> */ ports: new Map(), + _torRuntimeMessageListeners: [], + init() { this.conduit = new BroadcastConduit(ProxyMessenger, { id: "ProxyMessenger", @@ -328,6 +330,10 @@ const ProxyMessenger = { }, async recvRuntimeMessage(arg, { sender }) { + // We need to listen to some extension messages in Tor Browser + for (const listener of this._torRuntimeMessageListeners) { + listener(arg); + } arg.firstResponse = true; let kind = await this.normalizeArgs(arg, sender); let result = await this.conduit.castRuntimeMessage(kind, arg); @@ -1881,6 +1887,45 @@ for (let name of StartupCache.STORE_NAMES) { StartupCache[name] = new CacheStore(name); } +async function torSendExtensionMessage(extensionId, message) { + // This should broadcast the message to all children "conduits" + // listening for a "RuntimeMessage". Those children conduits + // will either be extension background pages or other extension + // pages listening to browser.runtime.onMessage. + const result = await ProxyMessenger.conduit.castRuntimeMessage("messenger", { + extensionId, + holder: new StructuredCloneHolder(message), + firstResponse: true, + sender: { + id: extensionId, + envType: "addon_child", + }, + }); + return result + ? result.value + : Promise.reject({ message: ERROR_NO_RECEIVERS }); +} + +async function torWaitForExtensionMessage(extensionId, checker) { + return new Promise(resolve => { + const msgListener = msg => { + try { + if (msg && msg.extensionId === extensionId) { + const deserialized = msg.holder.deserialize({}); + if (checker(deserialized)) { + const idx = ProxyMessenger._torRuntimeMessageListeners.indexOf( + msgListener + ); + ProxyMessenger._torRuntimeMessageListeners.splice(idx, 1); + resolve(deserialized); + } + } + } catch (e) {} + }; + ProxyMessenger._torRuntimeMessageListeners.push(msgListener); + }); +} + var ExtensionParent = { GlobalManager, HiddenExtensionPage, @@ -1892,6 +1937,8 @@ var ExtensionParent = { promiseExtensionViewLoaded, watchExtensionProxyContextLoad, DebugUtils, + torSendExtensionMessage, + torWaitForExtensionMessage, }; // browserPaintedPromise and browserStartupPromise are promises that
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 40562: Added Tor-related preferences to 000-tor-browser.js
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 78a4472e46486b9ea61ab0fed03786ac3c1dcd51 Author: Pier Angelo Vendrame <pierov(a)torproject.org> Date: Tue Jan 18 19:18:48 2022 +0100 Bug 40562: Added Tor-related preferences to 000-tor-browser.js Before reordering patches, we used to keep the Tor-related patches (torbutton and tor-launcher) at the beginning. After that issue, we decided to move them towards the end, however we kept TB4: Tor Browser's Firefox preference overrides at the beginning because it influcences many other features. As a result, to keep bisect working, we split that commit, and moved all the preferences related to Tor (such as network.proxy.*) here. --- browser/app/profile/000-tor-browser.js | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js index 10e1d0730bbb..aac1da85e24e 100644 --- a/browser/app/profile/000-tor-browser.js +++ b/browser/app/profile/000-tor-browser.js @@ -211,6 +211,17 @@ pref("network.predictor.enabled", false); // Temporarily disabled. See https://b // Bug 40177: Make sure tracker cookie purging is disabled pref("privacy.purge_trackers.enabled", false); +// Proxy and proxy security +pref("network.proxy.socks", "127.0.0.1"); +pref("network.proxy.socks_port", 9150); +pref("network.proxy.socks_remote_dns", true); +pref("network.proxy.no_proxies_on", ""); // For fingerprinting and local service vulns (#10419) +pref("network.proxy.allow_hijacking_localhost", true); // Allow proxies for localhost (#31065) +pref("network.proxy.type", 1); +// Bug 40548: Disable proxy-bypass +pref("network.proxy.failover_direct", false); +pref("network.security.ports.banned", "9050,9051,9150,9151"); +pref("network.dns.disabled", true); // This should cover the #5741 patch for DNS leaks pref("network.dns.disablePrefetch", true); pref("network.protocol-handler.external-default", false); pref("network.protocol-handler.external.mailto", false); @@ -373,6 +384,64 @@ pref("dom.audiochannel.mediaControl", false); #expand pref("torbrowser.version", __TOR_BROWSER_VERSION_QUOTED__); +// Old torbutton prefs + +// debug prefs +pref("extensions.torbutton.loglevel",4); +pref("extensions.torbutton.logmethod",1); // 0=stdout, 1=errorconsole, 2=debuglog + +// Display prefs +pref("extensions.torbutton.display_circuit", true); +pref("extensions.torbutton(a)torproject.org.description", "chrome://torbutton/locale/torbutton.properties"); +pref("extensions.torbutton.updateNeeded", false); + +// Tor check and proxy prefs +pref("extensions.torbutton.test_enabled",true); +pref("extensions.torbutton.test_url","https://check.torproject.org/?TorButton=true"); +pref("extensions.torbutton.local_tor_check",true); +pref("extensions.torbutton.versioncheck_url","https://www.torproject.org/projects/torbrowser/RecommendedTBBVersions"); +pref("extensions.torbutton.versioncheck_enabled",true); +pref("extensions.torbutton.use_nontor_proxy",false); + +// State prefs: +pref("extensions.torbutton.startup",false); +pref("extensions.torbutton.inserted_button",false); +pref("extensions.torbutton.inserted_security_level",false); + +// This is only used when letterboxing is disabled. +// See #7255 for details. We display the warning three times to make sure the +// user did not click on it by accident. +pref("extensions.torbutton.maximize_warnings_remaining", 3); + +// Security prefs: +pref("extensions.torbutton.clear_http_auth",true); +pref("extensions.torbutton.close_newnym",true); +pref("extensions.torbutton.resize_new_windows",false); +pref("extensions.torbutton.startup_state", 2); // 0=non-tor, 1=tor, 2=last +pref("extensions.torbutton.tor_memory_jar",false); +pref("extensions.torbutton.nontor_memory_jar",false); +pref("extensions.torbutton.launch_warning",true); + +// Opt out of Firefox addon pings: +// https://developer.mozilla.org/en/Addons/Working_with_AMO +pref("extensions.torbutton(a)torproject.org.getAddons.cache.enabled", false); + +// Security Slider +pref("extensions.torbutton.security_slider", 4); +pref("extensions.torbutton.security_custom", false); + +pref("extensions.torbutton.confirm_plugins", true); +pref("extensions.torbutton.confirm_newnym", true); + +pref("extensions.torbutton.noscript_inited", false); +pref("extensions.torbutton.noscript_persist", false); + +// Browser home page: +pref("browser.startup.homepage", "about:tor"); + +// This pref specifies an ad-hoc "version" for various pref update hacks we need to do +pref("extensions.torbutton.pref_fixup_version", 0); + // If we are bundling fonts, whitelist those bundled fonts, and restrict system fonts to a selection. #ifdef MOZ_BUNDLED_FONTS
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Orfox: Centralized proxy applied to AbstractCommunicator and BaseResources.
by richard@torproject.org 09 Feb '22

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

09 Feb '22
commit 7350c524fcfdbea065398fc462d71161e9ab557a Author: Mike Perry <mikeperry-git(a)torproject.org> Date: Mon May 6 15:51:06 2013 -0700 TB3: Tor Browser's official .mozconfigs. Also: Bug #9829.1: new .mozconfig file for the new cross-compiler and ESR24 Changes needed to build Mac in 64bit Bug 10715: Enable Webgl for mingw-w64 again. Disable ICU when cross-compiling; clean-up. Bug 15773: Enable ICU on OS X Bug 15990: Don't build the sandbox with mingw-w64 Bug 12761: Switch to ESR 38 for OS X Updating .mozconfig-asan Bug 12516: Compile hardenend Tor Browser with -fwrapv Bug 18331: Switch to Mozilla's toolchain for building Tor Browser for OS X Bug 17858: Cannot create incremental MARs for hardened builds. Define HOST_CFLAGS, etc. to avoid compiling programs such as mbsdiff (which is part of mar-tools and is not distributed to end-users) with ASan. Bug 13419: Add back ICU for Windows Bug 21239: Use GTK2 for ESR52 Linux builds Bug 23025: Add hardening flags for macOS Bug 24478: Enable debug assertions and tests in our ASan builds --enable-proxy-bypass-protection Bug 27597: ASan build option in tor-browser-build is broken Bug 27623 - Export MOZILLA_OFFICIAL during desktop builds This fixes a problem where some preferences had the wrong default value. Also see bug 27472 where we made a similar fix for Android. Bug 30463: Explicitly disable MOZ_TELEMETRY_REPORTING Bug 31450: Set proper BINDGEN_CFLAGS for ASan builds Add an --enable-tor-browser-data-outside-app-dir configure option Add --with-tor-browser-version configure option Bug 21849: Don't allow SSL key logging. Bug 31457: disable per-installation profiles The dedicated profiles (per-installation) feature does not interact well with our bundled profiles on Linux and Windows, and it also causes multiple profiles to be created on macOS under TorBrowser-Data. Bug 31935: Disable profile downgrade protection. Since Tor Browser does not support more than one profile, disable the prompt and associated code that offers to create one when a version downgrade situation is detected. Bug 32493: Disable MOZ_SERVICES_HEALTHREPORT Bug 25741 - TBA: Disable features at compile-time MOZ_NATIVE_DEVICES for casting and the media player MOZ_TELEMETRY_REPORTING for telemetry MOZ_DATA_REPORTING for all data reporting preferences (crashreport, telemetry, geo) Bug 25741 - TBA: Add default configure options in dedicated file Define MOZ_ANDROID_NETWORK_STATE and MOZ_ANDROID_LOCATION Bug 29859: Disable HLS support for now Add --disable-tor-launcher build option Add --enable-tor-browser-update build option Bug 33734: Set MOZ_NORMANDY to False Bug 33851: Omit Parental Controls. Bug 40061: Omit the Windows default browser agent from the build Bug 40107: Adapt .mozconfig-asan for ESR 78 Bug 40252: Add --enable-rust-simd to our tor-browser mozconfig files Bug 40793: moved Tor configuration options from old-configure.in to moz.configure --- .mozconfig | 39 ++++++++++++++++ .mozconfig-android | 36 +++++++++++++++ .mozconfig-asan | 45 +++++++++++++++++++ .mozconfig-mac | 56 +++++++++++++++++++++++ .mozconfig-mingw | 31 +++++++++++++ browser/app/profile/000-tor-browser.js | 2 + browser/base/moz.build | 3 ++ browser/installer/Makefile.in | 8 ++++ browser/moz.configure | 8 ++-- mobile/android/confvars.sh | 9 ++++ mobile/android/geckoview/build.gradle | 1 + mobile/android/moz.configure | 21 ++++++++- mobile/android/torbrowser.configure | 30 +++++++++++++ moz.configure | 81 ++++++++++++++++++++++++++++++++++ security/moz.build | 2 +- security/nss/lib/ssl/Makefile | 2 +- toolkit/modules/AppConstants.jsm | 15 +++++++ toolkit/modules/moz.build | 3 ++ 18 files changed, 384 insertions(+), 8 deletions(-) diff --git a/.mozconfig b/.mozconfig new file mode 100755 index 000000000000..18cd1f9b6487 --- /dev/null +++ b/.mozconfig @@ -0,0 +1,39 @@ +. $topsrcdir/browser/config/mozconfig + +# This mozconfig file is not used in official Tor Browser builds. +# It is only intended to be used when doing incremental Linux builds +# during development. The platform-specific mozconfig configuration +# files used in official Tor Browser releases can be found in the +# tor-browser-build repo: +# https://gitweb.torproject.org/builders/tor-browser-build.git/ +# under: +# tor-browser-build/projects/firefox/mozconfig-$OS-$ARCH + +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@ +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-official-branding + +# Let's support GTK3 for ESR60 +ac_add_options --enable-default-toolkit=cairo-gtk3 + +ac_add_options --disable-strip +ac_add_options --disable-install-strip +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +# Let's make sure no preference is enabling either Adobe's or Google's CDM. +ac_add_options --disable-eme +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= + +ac_add_options --disable-tor-launcher +ac_add_options --with-tor-browser-version=dev-build +ac_add_options --disable-tor-browser-update diff --git a/.mozconfig-android b/.mozconfig-android new file mode 100755 index 000000000000..50015ec615ef --- /dev/null +++ b/.mozconfig-android @@ -0,0 +1,36 @@ +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-arm-linux-androideabi +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-official-branding + +# Android +ac_add_options --enable-application=mobile/android +ac_add_options --target=arm-linux-androideabi +ac_add_options --with-android-ndk="$NDK_BASE" #Enter the android ndk location(ndk r17b) +ac_add_options --with-android-sdk="$SDK_BASE" #Enter the android sdk location +ac_add_options --with-branding=mobile/android/branding/alpha + +# Use Mozilla's Clang blobs +CC="$HOME/.mozbuild/clang/bin/clang" +CXX="$HOME/.mozbuild/clang/bin/clang++" + +#enable ccache to set amount of cache assigned for build. +ac_add_options --with-ccache + +ac_add_options --enable-strip +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-rust-debug + +ac_add_options --disable-updater +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls + +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= diff --git a/.mozconfig-asan b/.mozconfig-asan new file mode 100644 index 000000000000..98ea6ac6f3fe --- /dev/null +++ b/.mozconfig-asan @@ -0,0 +1,45 @@ +. $topsrcdir/browser/config/mozconfig + +export CFLAGS="-fsanitize=address -Dxmalloc=myxmalloc" +export CXXFLAGS="-fsanitize=address -Dxmalloc=myxmalloc" +# We need to add -ldl explicitely due to bug 1213698 +export LDFLAGS="-fsanitize=address -ldl" + +# Define HOST_CFLAGS, etc. to avoid compiling programs such as mbsdiff +# (which is part of mar-tools and is not distributed to end-users) with +# ASan. See bug 17858. +export HOST_CFLAGS="" +export HOST_CXXFLAGS="" +export HOST_LDFLAGS="-ldl" + +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@ +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 +export BINDGEN_CFLAGS='--gcc-toolchain=/var/tmp/dist/gcc' + +ac_add_options --enable-address-sanitizer +ac_add_options --disable-jemalloc +ac_add_options --disable-elf-hack +ac_add_options --with-clang-path=/var/tmp/dist/clang/bin/clang + +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-official-branding + +# Let's support GTK3 for ESR60 +ac_add_options --enable-default-toolkit=cairo-gtk3 + +ac_add_options --enable-tor-browser-update + +ac_add_options --disable-strip +ac_add_options --disable-install-strip +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +ac_add_options --disable-eme +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= diff --git a/.mozconfig-mac b/.mozconfig-mac new file mode 100644 index 000000000000..26e2b6b92fdb --- /dev/null +++ b/.mozconfig-mac @@ -0,0 +1,56 @@ +# ld needs libLTO.so from llvm +mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/clang/lib" + +CROSS_CCTOOLS_PATH=$topsrcdir/cctools +CROSS_SYSROOT=$topsrcdir/MacOSX10.7.sdk +CROSS_PRIVATE_FRAMEWORKS=$CROSS_SYSROOT/System/Library/PrivateFrameworks +HARDENING_FLAGS="-Werror=format -Werror=format-security -fstack-protector-strong -D_FORTIFY_SOURCE=2" +FLAGS="-target x86_64-apple-darwin10 -mlinker-version=136 -B $CROSS_CCTOOLS_PATH/bin -isysroot $CROSS_SYSROOT $HARDENING_FLAGS" + +export CC="$topsrcdir/clang/bin/clang $FLAGS" +export CXX="$topsrcdir/clang/bin/clang++ $FLAGS" +export CPP="$topsrcdir/clang/bin/clang $FLAGS -E" +export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config +export LDFLAGS="-Wl,-syslibroot,$CROSS_SYSROOT -Wl,-dead_strip -Wl,-pie" +export TOOLCHAIN_PREFIX=$CROSS_CCTOOLS_PATH/bin/x86_64-apple-darwin10- +#TODO: bug 1184202 - would be nice if these could be detected with TOOLCHAIN_PREFIX automatically +export AR=${TOOLCHAIN_PREFIX}ar +export RANLIB=${TOOLCHAIN_PREFIX}ranlib +export STRIP=${TOOLCHAIN_PREFIX}strip +export OTOOL=${TOOLCHAIN_PREFIX}otool +export DSYMUTIL=$topsrcdir/clang/bin/llvm-dsymutil + +export HOST_CC="$topsrcdir/clang/bin/clang" +export HOST_CXX="$topsrcdir/clang/bin/clang++" +export HOST_CPP="$topsrcdir/clang/bin/clang -E" +export HOST_CFLAGS="-g" +export HOST_CXXFLAGS="-g" +export HOST_LDFLAGS="-g" + +ac_add_options --target=x86_64-apple-darwin +ac_add_options --with-macos-private-frameworks=$CROSS_PRIVATE_FRAMEWORKS + +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-macos +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-application=browser +ac_add_options --enable-strip +ac_add_options --enable-official-branding +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --disable-debug + +ac_add_options --enable-tor-browser-data-outside-app-dir +ac_add_options --enable-tor-browser-update + +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +ac_add_options --disable-tests +# Let's make sure no preference is enabling either Adobe's or Google's CDM. +ac_add_options --disable-eme +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= diff --git a/.mozconfig-mingw b/.mozconfig-mingw new file mode 100644 index 000000000000..3ec6ff18a3e9 --- /dev/null +++ b/.mozconfig-mingw @@ -0,0 +1,31 @@ +CROSS_COMPILE=1 + +ac_add_options --enable-application=browser +ac_add_options --target=i686-w64-mingw32 +ac_add_options --with-toolchain-prefix=i686-w64-mingw32- +ac_add_options --enable-default-toolkit=cairo-windows +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-mingw +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --disable-debug +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-strip +ac_add_options --enable-official-branding + +ac_add_options --enable-tor-browser-update +ac_add_options --disable-bits-download + +# Let's make sure no preference is enabling either Adobe's or Google's CDM. +ac_add_options --disable-eme +ac_add_options --disable-crashreporter +ac_add_options --disable-maintenance-service +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +ac_add_options --disable-tests +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= +ac_add_options --disable-default-browser-agent diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js index a0520be072f2..10e1d0730bbb 100644 --- a/browser/app/profile/000-tor-browser.js +++ b/browser/app/profile/000-tor-browser.js @@ -371,6 +371,8 @@ pref("dom.presentation.receiver.enabled", false); pref("dom.audiochannel.audioCompeting", false); pref("dom.audiochannel.mediaControl", false); +#expand pref("torbrowser.version", __TOR_BROWSER_VERSION_QUOTED__); + // If we are bundling fonts, whitelist those bundled fonts, and restrict system fonts to a selection. #ifdef MOZ_BUNDLED_FONTS diff --git a/browser/base/moz.build b/browser/base/moz.build index 4058d6d86fea..ee3bc8028b9e 100644 --- a/browser/base/moz.build +++ b/browser/base/moz.build @@ -81,6 +81,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("windows", "gtk", "cocoa"): if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("windows", "gtk"): DEFINES["MENUBAR_CAN_AUTOHIDE"] = 1 +if CONFIG["TOR_BROWSER_UPDATE"]: + DEFINES["TOR_BROWSER_UPDATE"] = 1 + JAR_MANIFESTS += ["jar.mn"] GeneratedFile( diff --git a/browser/installer/Makefile.in b/browser/installer/Makefile.in index f98964d8a9eb..d55b373ff488 100644 --- a/browser/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -82,6 +82,14 @@ endif endif endif +ifdef TOR_BROWSER_DISABLE_TOR_LAUNCHER +DEFINES += -DTOR_BROWSER_DISABLE_TOR_LAUNCHER +endif + +ifdef TOR_BROWSER_UPDATE +DEFINES += -DTOR_BROWSER_UPDATE +endif + ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET))) DEFINES += -DMOZ_SHARED_MOZGLUE=1 endif diff --git a/browser/moz.configure b/browser/moz.configure index 8653bcbb165d..5a0b722b915e 100644 --- a/browser/moz.configure +++ b/browser/moz.configure @@ -5,11 +5,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. imply_option("MOZ_PLACES", True) -imply_option("MOZ_SERVICES_HEALTHREPORT", True) +imply_option("MOZ_SERVICES_HEALTHREPORT", False) imply_option("MOZ_SERVICES_SYNC", True) -imply_option("MOZ_DEDICATED_PROFILES", True) -imply_option("MOZ_BLOCK_PROFILE_DOWNGRADE", True) -imply_option("MOZ_NORMANDY", True) +imply_option("MOZ_DEDICATED_PROFILES", False) +imply_option("MOZ_BLOCK_PROFILE_DOWNGRADE", False) +imply_option("MOZ_NORMANDY", False) with only_when(target_is_linux & compile_environment): option(env="MOZ_NO_PIE_COMPAT", help="Enable non-PIE wrapper") diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh index 70e13c85b258..b2670451ed91 100644 --- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -29,6 +29,15 @@ MOZ_ANDROID_BROWSER_INTENT_CLASS=org.mozilla.gecko.BrowserApp MOZ_NO_SMART_CARDS=1 +# Adds MIME-type support for raw video MOZ_RAW=1 MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110} + +### Tor Browser for Android ### + +# Disable telemetry at compile-time +unset MOZ_TELEMETRY_REPORTING + +# Disable data reporting at compile-time +unset MOZ_DATA_REPORTING diff --git a/mobile/android/geckoview/build.gradle b/mobile/android/geckoview/build.gradle index f60ea1730d5c..bdee206175db 100644 --- a/mobile/android/geckoview/build.gradle +++ b/mobile/android/geckoview/build.gradle @@ -93,6 +93,7 @@ android { buildConfigField 'String', "MOZ_APP_DISPLAYNAME", "\"${mozconfig.substs.MOZ_APP_DISPLAYNAME}\""; buildConfigField 'String', "MOZ_APP_UA_NAME", "\"${mozconfig.substs.MOZ_APP_UA_NAME}\""; buildConfigField 'String', "MOZ_UPDATE_CHANNEL", "\"${mozconfig.substs.MOZ_UPDATE_CHANNEL}\""; + buildConfigField 'String', "TOR_BROWSER_VERSION", "\"${mozconfig.substs.TOR_BROWSER_VERSION}\""; // MOZILLA_VERSION is oddly quoted from autoconf, but we don't have to handle it specially in Gradle. buildConfigField 'String', "MOZILLA_VERSION", "\"${mozconfig.substs.MOZILLA_VERSION}\""; diff --git a/mobile/android/moz.configure b/mobile/android/moz.configure index 106f6c816814..96a014bb28e8 100644 --- a/mobile/android/moz.configure +++ b/mobile/android/moz.configure @@ -13,7 +13,7 @@ project_flag( project_flag( "MOZ_ANDROID_HLS_SUPPORT", help="Enable HLS (HTTP Live Streaming) support (currently using the ExoPlayer library)", - default=True, + default=False, ) option( @@ -51,7 +51,10 @@ set_config( ) imply_option("MOZ_NORMANDY", False) -imply_option("MOZ_SERVICES_HEALTHREPORT", True) +# Comment this so we can imply |False| in torbrowser.configure +# The Build system doesn't allow multiple imply_option() +# calls with the same key. +# imply_option("MOZ_SERVICES_HEALTHREPORT", True) imply_option("MOZ_ANDROID_HISTORY", True) imply_option("--enable-small-chunk-size", True) @@ -70,6 +73,8 @@ def check_target(target): ) +include("torbrowser.configure") + include("../../toolkit/moz.configure") include("../../build/moz.configure/android-sdk.configure") include("../../build/moz.configure/java.configure") @@ -87,3 +92,15 @@ set_config( "MOZ_ANDROID_FAT_AAR_ARCHITECTURES", depends("MOZ_ANDROID_FAT_AAR_ARCHITECTURES")(lambda x: x), ) + +project_flag( + "MOZ_ANDROID_NETWORK_STATE", + help="Include permission for accessing WiFi/network state on Android", + default=False, +) + +project_flag( + "MOZ_ANDROID_LOCATION", + help="Include permission for accessing fine and course-grain Location on Android", + default=False, +) diff --git a/mobile/android/torbrowser.configure b/mobile/android/torbrowser.configure new file mode 100644 index 000000000000..bcb725cae121 --- /dev/null +++ b/mobile/android/torbrowser.configure @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Set Tor Browser default config + +imply_option("MOZ_ANDROID_EXCLUDE_FONTS", False) + +# Disable uploading crash reports and dump files to an external server +# This is still configured in old-configure. Uncomment when this moves +# to the python config +# imply_option("MOZ_CRASHREPORTER", False) + +# Disable uploading information about the browser configuration and +# performance to an external server +imply_option("MOZ_SERVICES_HEALTHREPORT", False) + +# Disable creating telemetry and data reports that are uploaded to an +# external server +# These aren't actually configure options. These are disabled in +# confvars.sh, but they look like configure options so we'll document +# them here, as well. +# XXX: no confvars.sh here +# imply_option("MOZ_TELEMETRY_REPORTING", False) +# imply_option("MOZ_DATA_REPORTING", False) + +imply_option("MOZ_ANDROID_NETWORK_STATE", False) +imply_option("MOZ_ANDROID_LOCATION", False) diff --git a/moz.configure b/moz.configure index 089b5489ffcd..0cd28fd02681 100755 --- a/moz.configure +++ b/moz.configure @@ -1117,6 +1117,87 @@ set_config("MOZ_SYSTEM_ZLIB", True, when="--with-system-zlib") add_old_configure_assignment("MOZ_SYSTEM_ZLIB", True, when="--with-system-zlib") +# Tor additions. + +option( + "--with-tor-browser-version", + nargs=1, + help="Set Tor Browser version, e.g., 7.0a1" +) + + +@depends("--with-tor-browser-version") +def tor_browser_version(value): + if not value: + die("--with-tor-browser-version is required for Tor Browser.") + return value[0] + + +@depends("--with-tor-browser-version") +def tor_browser_version_quoted(value): + if not value: + die("--with-tor-browser-version is required for Tor Browser.") + return '"{}"'.format(value[0]) + + +set_config("TOR_BROWSER_VERSION", tor_browser_version) +set_define("TOR_BROWSER_VERSION", tor_browser_version) +set_define("TOR_BROWSER_VERSION_QUOTED", tor_browser_version_quoted) + + +option( + "--enable-tor-browser-update", + help="Enable Tor Browser update" +) + + +@depends("--enable-tor-browser-update") +def tor_browser_update(value): + if value: + return True + + +set_config("TOR_BROWSER_UPDATE", tor_browser_update) +set_define("TOR_BROWSER_UPDATE", tor_browser_update) +add_old_configure_assignment("TOR_BROWSER_UPDATE", tor_browser_update) + + +option( + "--enable-tor-browser-data-outside-app-dir", + help="Enable Tor Browser data outside of app directory" +) + + +@depends("--enable-tor-browser-data-outside-app-dir") +def tor_browser_data_outside_app_dir(value): + if value: + return True + + +set_define( + "TOR_BROWSER_DATA_OUTSIDE_APP_DIR", tor_browser_data_outside_app_dir) +add_old_configure_assignment( + "TOR_BROWSER_DATA_OUTSIDE_APP_DIR", tor_browser_data_outside_app_dir) + + +option( + "--disable-tor-launcher", + help="Do not include Tor Launcher" +) + + +@depends("--disable-tor-launcher") +def tor_browser_disable_launcher(value): + if not value: + return True + + +set_config("TOR_BROWSER_DISABLE_TOR_LAUNCHER", tor_browser_disable_launcher) +set_define("TOR_BROWSER_DISABLE_TOR_LAUNCHER", tor_browser_disable_launcher) +add_old_configure_assignment( + "TOR_BROWSER_DISABLE_TOR_LAUNCHER", tor_browser_disable_launcher) + + # Please do not add configure checks from here on. # Fallthrough to autoconf-based configure diff --git a/security/moz.build b/security/moz.build index 18e50f9dcc37..8d0427525487 100644 --- a/security/moz.build +++ b/security/moz.build @@ -85,7 +85,7 @@ gyp_vars["nss_dist_obj_dir"] = "$PRODUCT_DIR/dist/bin" gyp_vars["disable_tests"] = 1 gyp_vars["disable_dbm"] = 1 gyp_vars["disable_libpkix"] = 1 -gyp_vars["enable_sslkeylogfile"] = 1 +gyp_vars["enable_sslkeylogfile"] = 0 # pkg-config won't reliably find zlib on our builders, so just force it. # System zlib is only used for modutil and signtool unless # SSL zlib is enabled, which we are disabling immediately below this. diff --git a/security/nss/lib/ssl/Makefile b/security/nss/lib/ssl/Makefile index 8a8b06f4b508..90571bb3e256 100644 --- a/security/nss/lib/ssl/Makefile +++ b/security/nss/lib/ssl/Makefile @@ -41,7 +41,7 @@ endif # Enable key logging by default in debug builds, but not opt builds. # Logging still needs to be enabled at runtime through env vars. -NSS_ALLOW_SSLKEYLOGFILE ?= $(if $(BUILD_OPT),0,1) +NSS_ALLOW_SSLKEYLOGFILE ?= 0 ifeq (1,$(NSS_ALLOW_SSLKEYLOGFILE)) DEFINES += -DNSS_ALLOW_SSLKEYLOGFILE=1 endif diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 9b3acf6ecc30..ea10dc97535d 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -354,6 +354,14 @@ this.AppConstants = Object.freeze({ MOZ_WIDGET_TOOLKIT: "@MOZ_WIDGET_TOOLKIT@", ANDROID_PACKAGE_NAME: "@ANDROID_PACKAGE_NAME@", + TOR_BROWSER_VERSION: "@TOR_BROWSER_VERSION@", + TOR_BROWSER_DATA_OUTSIDE_APP_DIR: +#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR + true, +#else + false, +#endif + DEBUG_JS_MODULES: "@DEBUG_JS_MODULES@", MOZ_BING_API_CLIENTID: "@MOZ_BING_API_CLIENTID@", @@ -431,4 +439,11 @@ this.AppConstants = Object.freeze({ #else false, #endif + + TOR_BROWSER_UPDATE: +#ifdef TOR_BROWSER_UPDATE + true, +#else + false, +#endif }); diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 3fb050b5d18b..9d349d9f3394 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -302,6 +302,9 @@ for var in ( if CONFIG[var]: DEFINES[var] = True +if CONFIG["TOR_BROWSER_UPDATE"]: + DEFINES["TOR_BROWSER_UPDATE"] = 1 + JAR_MANIFESTS += ["jar.mn"] DEFINES["TOPOBJDIR"] = TOPOBJDIR
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 14631: Improve profile access error messages.
by richard@torproject.org 09 Feb '22

09 Feb '22
commit f296d17874308ce928970355a628998bfad88262 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Feb 24 13:50:23 2015 -0500 Bug 14631: Improve profile access error messages. Instead of always reporting that the profile is locked, display specific messages for "access denied" and "read-only file system". To allow for localization, get profile-related error strings from Torbutton. Use app display name ("Tor Browser") in profile-related error alerts. --- .../mozapps/profile/profileSelection.properties | 5 + toolkit/profile/nsToolkitProfileService.cpp | 57 +++++++- toolkit/profile/nsToolkitProfileService.h | 13 +- toolkit/xre/nsAppRunner.cpp | 157 ++++++++++++++++++--- 4 files changed, 208 insertions(+), 24 deletions(-) diff --git a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties index d326083202b2..aa38bda24347 100644 --- a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties +++ b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties @@ -12,6 +12,11 @@ restartMessageUnlocker=%S is already running, but is not responding. The old %S restartMessageNoUnlockerMac=A copy of %S is already open. Only one copy of %S can be open at a time. restartMessageUnlockerMac=A copy of %S is already open. The running copy of %S will quit in order to open this one. +# LOCALIZATION NOTE (profileProblemTitle, profileReadOnly, profileReadOnlyMac, profileAccessDenied): Messages displayed when the browser profile cannot be accessed or written to. %S is the application name. +profileProblemTitle=%S Profile Problem +profileReadOnly=You cannot run %S from a read-only file system. Please copy %S to another location before trying to use it. +profileReadOnlyMac=You cannot run %S from a read-only file system. Please copy %S to your Desktop or Applications folder before trying to use it. +profileAccessDenied=%S does not have permission to access the profile. Please adjust your file system permissions and try again. # Profile manager # LOCALIZATION NOTE (profileTooltip): First %S is the profile name, second %S is the path to the profile folder. profileTooltip=Profile: ‘%S’ — Path: ‘%S’ diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp index 154806ebbccf..9f8168c07a4f 100644 --- a/toolkit/profile/nsToolkitProfileService.cpp +++ b/toolkit/profile/nsToolkitProfileService.cpp @@ -1248,9 +1248,10 @@ nsToolkitProfileService::SelectStartupProfile( } bool wasDefault; + ProfileStatus profileStatus; nsresult rv = SelectStartupProfile(&argc, argv.get(), aIsResetting, aRootDir, aLocalDir, - aProfile, aDidCreate, &wasDefault); + aProfile, aDidCreate, &wasDefault, profileStatus); // Since we were called outside of the normal startup path complete any // startup tasks. @@ -1283,7 +1284,8 @@ nsToolkitProfileService::SelectStartupProfile( nsresult nsToolkitProfileService::SelectStartupProfile( int* aArgc, char* aArgv[], bool aIsResetting, nsIFile** aRootDir, nsIFile** aLocalDir, nsIToolkitProfile** aProfile, bool* aDidCreate, - bool* aWasDefaultSelection) { + bool* aWasDefaultSelection, ProfileStatus& aProfileStatus) { + aProfileStatus = PROFILE_STATUS_OK; if (mStartupProfileSelected) { return NS_ERROR_ALREADY_INITIALIZED; } @@ -1376,6 +1378,13 @@ nsresult nsToolkitProfileService::SelectStartupProfile( rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf)); NS_ENSURE_SUCCESS(rv, rv); + aProfileStatus = CheckProfileWriteAccess(lf); + if (PROFILE_STATUS_OK != aProfileStatus) { + NS_ADDREF(*aRootDir = lf); + NS_ADDREF(*aLocalDir = lf); + return NS_ERROR_FAILURE; + } + // Make sure that the profile path exists and it's a directory. bool exists; rv = lf->Exists(&exists); @@ -2170,3 +2179,47 @@ nsresult XRE_GetFileFromPath(const char* aPath, nsIFile** aResult) { # error Platform-specific logic needed here. #endif } + +// Check for write permission to the profile directory by trying to create a +// new file (after ensuring that no file with the same name exists). +ProfileStatus nsToolkitProfileService::CheckProfileWriteAccess( + nsIFile* aProfileDir) { +#if defined(XP_UNIX) + constexpr auto writeTestFileName = u".parentwritetest"_ns; +#else + constexpr auto writeTestFileName = u"parent.writetest"_ns; +#endif + + nsCOMPtr<nsIFile> writeTestFile; + nsresult rv = aProfileDir->Clone(getter_AddRefs(writeTestFile)); + if (NS_SUCCEEDED(rv)) rv = writeTestFile->Append(writeTestFileName); + + if (NS_SUCCEEDED(rv)) { + bool doesExist = false; + rv = writeTestFile->Exists(&doesExist); + if (NS_SUCCEEDED(rv) && doesExist) rv = writeTestFile->Remove(true); + } + + if (NS_SUCCEEDED(rv)) { + rv = writeTestFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666); + (void)writeTestFile->Remove(true); + } + + ProfileStatus status = + NS_SUCCEEDED(rv) ? PROFILE_STATUS_OK : PROFILE_STATUS_OTHER_ERROR; + if (NS_ERROR_FILE_ACCESS_DENIED == rv) + status = PROFILE_STATUS_ACCESS_DENIED; + else if (NS_ERROR_FILE_READ_ONLY == rv) + status = PROFILE_STATUS_READ_ONLY; + + return status; +} + +ProfileStatus nsToolkitProfileService::CheckProfileWriteAccess( + nsIToolkitProfile* aProfile) { + nsCOMPtr<nsIFile> profileDir; + nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir)); + if (NS_FAILED(rv)) return PROFILE_STATUS_OTHER_ERROR; + + return CheckProfileWriteAccess(profileDir); +} diff --git a/toolkit/profile/nsToolkitProfileService.h b/toolkit/profile/nsToolkitProfileService.h index d281d39ebe59..5c97c906df49 100644 --- a/toolkit/profile/nsToolkitProfileService.h +++ b/toolkit/profile/nsToolkitProfileService.h @@ -16,6 +16,14 @@ #include "nsProfileLock.h" #include "nsINIParser.h" +enum ProfileStatus { + PROFILE_STATUS_OK, + PROFILE_STATUS_ACCESS_DENIED, + PROFILE_STATUS_READ_ONLY, + PROFILE_STATUS_IS_LOCKED, + PROFILE_STATUS_OTHER_ERROR +}; + class nsToolkitProfile final : public nsIToolkitProfile, public mozilla::LinkedListElement<RefPtr<nsToolkitProfile>> { @@ -80,10 +88,13 @@ class nsToolkitProfileService final : public nsIToolkitProfileService { nsresult SelectStartupProfile(int* aArgc, char* aArgv[], bool aIsResetting, nsIFile** aRootDir, nsIFile** aLocalDir, nsIToolkitProfile** aProfile, bool* aDidCreate, - bool* aWasDefaultSelection); + bool* aWasDefaultSelection, + ProfileStatus& aProfileStatus); nsresult CreateResetProfile(nsIToolkitProfile** aNewProfile); nsresult ApplyResetProfile(nsIToolkitProfile* aOldProfile); void CompleteStartup(); + static ProfileStatus CheckProfileWriteAccess(nsIToolkitProfile* aProfile); + static ProfileStatus CheckProfileWriteAccess(nsIFile* aProfileDir); private: friend class nsToolkitProfile; diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index d11e586d7096..6d6238feda46 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -2283,6 +2283,91 @@ nsresult LaunchChild(bool aBlankCommandLine, bool aTryExec) { return NS_ERROR_LAUNCHED_CHILD_PROCESS; } +static nsresult GetOverrideStringBundleForLocale(nsIStringBundleService* aSBS, + const char* aTorbuttonURI, + const char* aLocale, + nsIStringBundle** aResult) { + NS_ENSURE_ARG(aSBS); + NS_ENSURE_ARG(aTorbuttonURI); + NS_ENSURE_ARG(aLocale); + NS_ENSURE_ARG(aResult); + + const char* kFormatStr = + "jar:%s!/chrome/torbutton/locale/%s/torbutton.properties"; + nsPrintfCString strBundleURL(kFormatStr, aTorbuttonURI, aLocale); + nsresult rv = aSBS->CreateBundle(strBundleURL.get(), aResult); + NS_ENSURE_SUCCESS(rv, rv); + + // To ensure that we have a valid string bundle, try to retrieve a string + // that we know exists. + nsAutoString val; + rv = (*aResult)->GetStringFromName("profileProblemTitle", val); + if (!NS_SUCCEEDED(rv)) *aResult = nullptr; // No good. Discard it. + + return rv; +} + +static void GetOverrideStringBundle(nsIStringBundleService* aSBS, + nsIStringBundle** aResult) { + if (!aSBS || !aResult) return; + + *aResult = nullptr; + + // Build Torbutton file URI string by starting from GREDir. + RefPtr<nsXREDirProvider> dirProvider = nsXREDirProvider::GetSingleton(); + if (!dirProvider) return; + + nsCOMPtr<nsIFile> greDir = dirProvider->GetGREDir(); + if (!greDir) return; + + // Create file URI, extract as string, and append omni.ja relative path. + nsCOMPtr<nsIURI> uri; + nsAutoCString uriString; + if (NS_FAILED(NS_NewFileURI(getter_AddRefs(uri), greDir)) || + NS_FAILED(uri->GetSpec(uriString))) { + return; + } + + uriString.Append("omni.ja"); + + nsAutoCString userAgentLocale; + if (!NS_SUCCEEDED( + Preferences::GetCString("intl.locale.requested", userAgentLocale))) { + return; + } + + nsresult rv = GetOverrideStringBundleForLocale( + aSBS, uriString.get(), userAgentLocale.get(), aResult); + if (NS_FAILED(rv)) { + // Try again using base locale, e.g., "en" vs. "en-US". + int16_t offset = userAgentLocale.FindChar('-', 1); + if (offset > 0) { + nsAutoCString shortLocale(Substring(userAgentLocale, 0, offset)); + rv = GetOverrideStringBundleForLocale(aSBS, uriString.get(), + shortLocale.get(), aResult); + } + } +} + +static nsresult GetFormattedString(nsIStringBundle* aOverrideBundle, + nsIStringBundle* aMainBundle, + const char* aName, + const nsTArray<nsString>& aParams, + nsAString& aResult) { + NS_ENSURE_ARG(aName); + + nsresult rv = NS_ERROR_FAILURE; + if (aOverrideBundle) { + rv = aOverrideBundle->FormatStringFromName(aName, aParams, aResult); + } + + // If string was not found in override bundle, use main (browser) bundle. + if (NS_FAILED(rv) && aMainBundle) + rv = aMainBundle->FormatStringFromName(aName, aParams, aResult); + + return rv; +} + static const char kProfileProperties[] = "chrome://mozapps/locale/profile/profileSelection.properties"; @@ -2348,7 +2433,7 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) { sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb)); NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE); - NS_ConvertUTF8toUTF16 appName(gAppData->name); + NS_ConvertUTF8toUTF16 appName(MOZ_APP_DISPLAYNAME); AutoTArray<nsString, 2> params = {appName, appName}; // profileMissing @@ -2372,11 +2457,12 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) { // If aUnlocker is NULL, it is also OK for the following arguments to be NULL: // aProfileDir, aProfileLocalDir, aResult. -static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir, - nsIFile* aProfileLocalDir, - nsIProfileUnlocker* aUnlocker, - nsINativeAppSupport* aNative, - nsIProfileLock** aResult) { +static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir, + nsIFile* aProfileLocalDir, + ProfileStatus aStatus, + nsIProfileUnlocker* aUnlocker, + nsINativeAppSupport* aNative, + nsIProfileLock** aResult) { nsresult rv; if (aProfileDir) { @@ -2406,24 +2492,39 @@ static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir, sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb)); NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE); - NS_ConvertUTF8toUTF16 appName(gAppData->name); + nsCOMPtr<nsIStringBundle> overrideSB; + GetOverrideStringBundle(sbs, getter_AddRefs(overrideSB)); + + NS_ConvertUTF8toUTF16 appName(MOZ_APP_DISPLAYNAME); AutoTArray<nsString, 3> params = {appName, appName, appName}; nsAutoString killMessage; #ifndef XP_MACOSX - rv = sb->FormatStringFromName( - aUnlocker ? "restartMessageUnlocker" : "restartMessageNoUnlocker2", - params, killMessage); + static const char kRestartUnlocker[] = "restartMessageUnlocker"; + static const char kRestartNoUnlocker[] = "restartMessageNoUnlocker2"; + static const char kReadOnly[] = "profileReadOnly"; #else - rv = sb->FormatStringFromName( - aUnlocker ? "restartMessageUnlockerMac" : "restartMessageNoUnlockerMac", - params, killMessage); -#endif + static const char kRestartUnlocker[] = "restartMessageUnlockerMac"; + static const char kRestartNoUnlocker[] = "restartMessageNoUnlockerMac"; + static const char kReadOnly[] = "profileReadOnlyMac"; +#endif + static const char kAccessDenied[] = "profileAccessDenied"; + + const char* errorKey = aUnlocker ? kRestartUnlocker : kRestartNoUnlocker; + if (PROFILE_STATUS_READ_ONLY == aStatus) + errorKey = kReadOnly; + else if (PROFILE_STATUS_ACCESS_DENIED == aStatus) + errorKey = kAccessDenied; + rv = GetFormattedString(overrideSB, sb, errorKey, params, killMessage); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + const char* titleKey = ((PROFILE_STATUS_READ_ONLY == aStatus) || + (PROFILE_STATUS_ACCESS_DENIED == aStatus)) + ? "profileProblemTitle" + : "restartTitle"; params.SetLength(1); nsAutoString killTitle; - rv = sb->FormatStringFromName("restartTitle", params, killTitle); + rv = sb->FormatStringFromName(titleKey, params, killTitle); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); #ifdef MOZ_BACKGROUNDTASKS @@ -2611,6 +2712,13 @@ static nsCOMPtr<nsIToolkitProfile> gResetOldProfile; static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir, nsIFile* aLocalDir, nsIToolkitProfile* aProfile, nsIProfileLock** aResult) { + ProfileStatus status = + (aProfile ? nsToolkitProfileService::CheckProfileWriteAccess(aProfile) + : nsToolkitProfileService::CheckProfileWriteAccess(aRootDir)); + if (PROFILE_STATUS_OK != status) + return ProfileErrorDialog(aRootDir, aLocalDir, status, nullptr, aNative, + aResult); + // If you close Firefox and very quickly reopen it, the old Firefox may // still be closing down. Rather than immediately showing the // "Firefox is running but is not responding" message, we spend a few @@ -2637,7 +2745,8 @@ static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir, } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds)); - return ProfileLockedDialog(aRootDir, aLocalDir, unlocker, aNative, aResult); + return ProfileErrorDialog(aRootDir, aLocalDir, PROFILE_STATUS_IS_LOCKED, + unlocker, aNative, aResult); } // Pick a profile. We need to end up with a profile root dir, local dir and @@ -2652,7 +2761,8 @@ static nsresult LockProfile(nsINativeAppSupport* aNative, nsIFile* aRootDir, static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative, nsIFile** aRootDir, nsIFile** aLocalDir, nsIToolkitProfile** aProfile, - bool* aWasDefaultSelection) { + bool* aWasDefaultSelection, + nsIProfileLock** aResult) { StartupTimeline::Record(StartupTimeline::SELECT_PROFILE); nsresult rv; @@ -2698,9 +2808,14 @@ static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc, // Ask the profile manager to select the profile directories to use. bool didCreate = false; - rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset, - aRootDir, aLocalDir, aProfile, - &didCreate, aWasDefaultSelection); + ProfileStatus profileStatus = PROFILE_STATUS_OK; + rv = aProfileSvc->SelectStartupProfile( + &gArgc, gArgv, gDoProfileReset, aRootDir, aLocalDir, aProfile, &didCreate, + aWasDefaultSelection, profileStatus); + if (PROFILE_STATUS_OK != profileStatus) { + return ProfileErrorDialog(*aRootDir, *aLocalDir, profileStatus, nullptr, + aNative, aResult); + } if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) { return ShowProfileManager(aProfileSvc, aNative); @@ -4530,7 +4645,7 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) { nsCOMPtr<nsIToolkitProfile> profile; rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD), getter_AddRefs(mProfLD), getter_AddRefs(profile), - &wasDefaultSelection); + &wasDefaultSelection, getter_AddRefs(mProfileLock)); if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) { *aExitFlag = true; return 0;
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 10760: Integrate TorButton to TorBrowser core
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 5bea6d9e4a1c2178205e71016dfabb42cf67fa32 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Feb 19 23:05:08 2020 +0100 Bug 10760: Integrate TorButton to TorBrowser core Because of the non-restartless nature of Torbutton, it required a two-stage installation process. On mobile, it was a problem, because it was not loading when the user opened the browser for the first time. Moving it to tor-browser and making it a system extension allows it to load when the user opens the browser for first time. Additionally, this patch also fixes Bug 27611. Bug 26321: New Circuit and New Identity menu items Bug 14392: Make about:tor behave like other initial pages. Bug 25013: Add torbutton as a tor-browser submodule Bug 31575: Replace Firefox Home (newtab) with about:tor Avoid loading AboutNewTab in BrowserGlue.jsm in order to avoid several network requests that we do not need. Besides, about:newtab will now point to about:blank or about:tor (depending on browser.newtabpage.enabled) and about:home will point to about:tor. --- .gitmodules | 3 ++ browser/base/content/aboutDialog.xhtml | 38 +++++++++++------- browser/base/content/appmenu-viewcache.inc.xhtml | 28 +++++++++++++- browser/base/content/browser-doctype.inc | 6 +++ browser/base/content/browser-menubar.inc | 45 ++++++++++++++++------ browser/base/content/browser-sets.inc | 2 + browser/base/content/browser.js | 1 + browser/base/content/browser.xhtml | 9 +++++ browser/components/BrowserGlue.jsm | 33 +--------------- .../controlcenter/content/identityPanel.inc.xhtml | 22 +++++++++++ browser/components/newtab/AboutNewTabService.jsm | 15 +------- browser/components/preferences/home.inc.xhtml | 4 +- browser/components/preferences/preferences.xhtml | 5 ++- browser/installer/package-manifest.in | 2 + browser/modules/HomePage.jsm | 2 +- docshell/base/nsAboutRedirector.cpp | 6 ++- docshell/build/components.conf | 1 + mobile/android/installer/package-manifest.in | 4 ++ toolkit/moz.build | 1 + .../mozapps/extensions/internal/XPIProvider.jsm | 9 +++++ toolkit/torproject/torbutton | 1 + .../lib/environments/browser-window.js | 6 ++- 22 files changed, 166 insertions(+), 77 deletions(-) diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000000..2f03bd8e22df --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "toolkit/torproject/torbutton"] + path = toolkit/torproject/torbutton + url = https://git.torproject.org/torbutton.git diff --git a/browser/base/content/aboutDialog.xhtml b/browser/base/content/aboutDialog.xhtml index 55c8b1c2c5f7..4eb122b0b2d8 100644 --- a/browser/base/content/aboutDialog.xhtml +++ b/browser/base/content/aboutDialog.xhtml @@ -7,11 +7,11 @@ <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/aboutDialog.css" type="text/css"?> <?xml-stylesheet href="chrome://branding/content/aboutDialog.css" type="text/css"?> +<?xml-stylesheet href="chrome://torbutton/skin/aboutDialog.css" type="text/css"?> +<!-- We need to include the localization DTDs until we migrate to Fluent --> <!DOCTYPE window [ -#ifdef XP_MACOSX #include browser-doctype.inc -#endif ]> <window xmlns:html="http://www.w3.org/1999/xhtml" @@ -28,7 +28,7 @@ data-l10n-id="aboutDialog-title" #endif role="dialog" - aria-describedby="version distribution distributionId communityDesc contributeDesc trademark" + aria-describedby="version distribution distributionId projectDesc helpDesc trademark trademarkTor" > #ifdef XP_MACOSX #include macWindow.inc.xhtml @@ -146,24 +146,36 @@ <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-exp-creditsLink"/> </description> </vbox> - <description class="text-blurb" id="communityDesc" data-l10n-id="community-2"> - <label is="text-link" href="https://www.mozilla.org/?utm_source=firefox-browser&#38;utm_medium=firefox-…" data-l10n-name="community-mozillaLink"/> - <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-creditsLink"/> + <!-- Keep communityDesc and contributeDesc to avoid JS errors trying to hide them --> + <description class="text-blurb" id="communityDesc" data-l10n-id="community-2" hidden="true"></description> + <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus" hidden="true"></description> + <description class="text-blurb" id="projectDesc"> + &project.start; + <label is="text-link" href="https://www.torproject.org/"> + &project.tpoLink; + </label>&project.end; </description> - <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus"> - <label is="text-link" href="https://donate.mozilla.org/?utm_source=firefox&#38;utm_medium=referral&#38;…" data-l10n-name="helpus-donateLink"/> - <label is="text-link" href="https://www.mozilla.org/contribute/?utm_source=firefox-browser&#38;utm_medi…" data-l10n-name="helpus-getInvolvedLink"/> + <description class="text-blurb" id="helpDesc"> + &help.start; + <label is="text-link" href="https://donate.torproject.org/"> + &help.donateLink; + </label> + &help.or; + <label is="text-link" href="https://community.torproject.org/"> + &help.getInvolvedLink; + </label>&help.end; </description> </vbox> </vbox> </hbox> <vbox id="bottomBox"> - <hbox pack="center"> - <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="bottomLinks-license"/> - <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:rights" data-l10n-id="bottomLinks-rights"/> - <label is="text-link" class="bottom-link" href="https://www.mozilla.org/privacy/?utm_source=firefox-browser&#38;utm_medium=…" data-l10n-id="bottomLinks-privacy"/> + <hbox id="newBottom" pack="center" position="1"> + <label is="text-link" class="bottom-link" href="https://support.torproject.org/">&bottomLinks.questions;</label> + <label is="text-link" class="bottom-link" href="https://community.torproject.org/relay/">&bottomLinks.grow;</label> + <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license">&bottomLinks.license;</label> </hbox> <description id="trademark" data-l10n-id="trademarkInfo"></description> + <description id="trademarkTor">&tor.TrademarkStatement;</description> </vbox> </vbox> diff --git a/browser/base/content/appmenu-viewcache.inc.xhtml b/browser/base/content/appmenu-viewcache.inc.xhtml index 895ef976fc23..a473509f1647 100644 --- a/browser/base/content/appmenu-viewcache.inc.xhtml +++ b/browser/base/content/appmenu-viewcache.inc.xhtml @@ -45,7 +45,8 @@ class="subviewbutton subviewbutton-iconic" data-l10n-id="appmenuitem-new-private-window" key="key_privatebrowsing" - command="Tools:PrivateBrowsing"/> + command="Tools:PrivateBrowsing" + hidden="true"/> #ifdef NIGHTLY_BUILD <toolbarbutton id="appMenu-fission-window-button" class="subviewbutton subviewbutton-iconic" @@ -61,7 +62,19 @@ <toolbarbutton id="appMenuRestoreLastSession" data-l10n-id="appmenu-restore-session" class="subviewbutton subviewbutton-iconic" - command="Browser:RestoreLastSession"/> + command="Browser:RestoreLastSession" + hidden="true"/> + <toolbarseparator/> + <toolbarbutton id="appMenuNewIdentity" + class="subviewbutton subviewbutton-iconic" + key="torbutton-new-identity-key" + label="&torbutton.context_menu.new_identity;" + oncommand="torbutton_new_identity();"/> + <toolbarbutton id="appMenuNewCircuit" + class="subviewbutton subviewbutton-iconic" + key="torbutton-new-circuit-key" + label="&torbutton.context_menu.new_circuit;" + oncommand="torbutton_new_circuit();"/> <toolbarseparator/> <toolbaritem id="appMenu-zoom-controls" class="toolbaritem-combined-buttons" closemenu="none"> <!-- Use a spacer, because panel sizing code gets confused when using CSS methods. --> @@ -256,6 +269,17 @@ key="key_privatebrowsing" command="Tools:PrivateBrowsing"/> <toolbarseparator/> + <toolbarbutton id="appMenuNewIdentity" + class="subviewbutton" + key="torbutton-new-identity-key" + label="&torbutton.context_menu.new_identity_sentence_case;" + oncommand="torbutton_new_identity();"/> + <toolbarbutton id="appMenuNewCircuit" + class="subviewbutton" + key="torbutton-new-circuit-key" + label="&torbutton.context_menu.new_circuit_sentence_case;" + oncommand="torbutton_new_circuit();"/> + <toolbarseparator/> <toolbarbutton id="appMenu-bookmarks-button" class="subviewbutton subviewbutton-nav" data-l10n-id="library-bookmarks-menu" diff --git a/browser/base/content/browser-doctype.inc b/browser/base/content/browser-doctype.inc index cea0382acde2..691d16a7b2e5 100644 --- a/browser/base/content/browser-doctype.inc +++ b/browser/base/content/browser-doctype.inc @@ -6,3 +6,9 @@ %textcontextDTD; <!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd"> %placesDTD; +<!ENTITY % torbuttonDTD SYSTEM "chrome://torbutton/locale/torbutton.dtd"> +%torbuttonDTD; +<!ENTITY % aboutTorDTD SYSTEM "chrome://torbutton/locale/aboutTor.dtd"> +%aboutTorDTD; +<!ENTITY % aboutDialogDTD SYSTEM "chrome://torbutton/locale/aboutDialog.dtd"> +%aboutDialogDTD; diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index cd348e8e7817..4b7564cea087 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -38,6 +38,18 @@ command="Tools:NonFissionWindow" accesskey="s" label="New Non-Fission Window"/> #endif + <menuseparator/> + <menuitem id="menu_newIdentity" + accesskey="&torbutton.context_menu.new_identity_key;" + key="torbutton-new-identity-key" + label="&torbutton.context_menu.new_identity;" + oncommand="torbutton_new_identity();"/> + <menuitem id="menu_newCircuit" + accesskey="&torbutton.context_menu.new_circuit_key;" + key="torbutton-new-circuit-key" + label="&torbutton.context_menu.new_circuit;" + oncommand="torbutton_new_circuit();"/> + <menuseparator/> <menuitem id="menu_openLocation" hidden="true" command="Browser:OpenLocation" @@ -463,23 +475,34 @@ <menupopup id="menu_HelpPopup" onpopupshowing="buildHelpMenu();"> <!-- Note: Items under here are cloned to the AppMenu Help submenu. The cloned items have their strings defined by appmenu-data-l10n-id. --> - <menuitem id="menu_openHelp" + <!-- dummy elements to avoid 'getElementById' errors --> + <box id="feedbackPage"/> + <box id="helpSafeMode"/> + <box id="menu_HelpPopup_reportPhishingtoolmenu"/> + <box id="menu_HelpPopup_reportPhishingErrortoolmenu"/> + <!-- Add Tor Browser manual link --> + <menuitem id="torBrowserUserManual" + oncommand="gBrowser.selectedTab = gBrowser.addTab('https://tb-manual.torproject.org/' + Services.locale.requestedLocale, {triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});" + label="&aboutTor.torbrowser_user_manual.label;" + accesskey="&aboutTor.torbrowser_user_manual.accesskey;"/> + <!-- Bug 18905: Hide unused help menu items --> + <!-- <menuitem id="menu_openHelp" oncommand="openHelpLink('firefox-help')" data-l10n-id="menu-get-help" appmenu-data-l10n-id="appmenu-get-help" #ifdef XP_MACOSX - key="key_openHelpMac"/> + key="key_openHelpMac"/> --> #else - /> + /> --> #endif - <menuitem id="feedbackPage" + <!-- <menuitem id="feedbackPage" oncommand="openFeedbackPage()" data-l10n-id="menu-help-feedback-page" - appmenu-data-l10n-id="appmenu-help-feedback-page"/> - <menuitem id="helpSafeMode" + appmenu-data-l10n-id="appmenu-help-feedback-page"/> --> + <!-- <menuitem id="helpSafeMode" oncommand="safeModeRestart();" data-l10n-id="menu-help-enter-troubleshoot-mode2" - appmenu-data-l10n-id="appmenu-help-enter-troubleshoot-mode2"/> + appmenu-data-l10n-id="appmenu-help-enter-troubleshoot-mode2"/> --> <menuitem id="troubleShooting" oncommand="openTroubleshootingPage()" data-l10n-id="menu-help-more-troubleshooting-info" @@ -489,18 +512,18 @@ data-l10n-id="menu-help-report-site-issue" appmenu-data-l10n-id="appmenu-help-report-site-issue" hidden="true"/> - <menuitem id="menu_HelpPopup_reportPhishingtoolmenu" + <!-- <menuitem id="menu_HelpPopup_reportPhishingtoolmenu" disabled="true" oncommand="openUILink(gSafeBrowsing.getReportURL('Phish'), event, {triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})});" hidden="true" data-l10n-id="menu-help-report-deceptive-site" - appmenu-data-l10n-id="appmenu-help-report-deceptive-site"/> - <menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu" + appmenu-data-l10n-id="appmenu-help-report-deceptive-site"/> --> + <!-- <menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu" disabled="true" oncommand="ReportFalseDeceptiveSite();" data-l10n-id="menu-help-not-deceptive" appmenu-data-l10n-id="appmenu-help-not-deceptive" - hidden="true"/> + hidden="true"/> --> <menuseparator id="aboutSeparator"/> <menuitem id="aboutName" oncommand="openAboutDialog();" diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index fdd83f64896e..c3129d6aae07 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -383,4 +383,6 @@ data-l10n-id="hide-other-apps-shortcut" modifiers="accel,alt"/> #endif + <key id="torbutton-new-identity-key" modifiers="accel shift" key="U" oncommand="torbutton_new_identity()"/> + <key id="torbutton-new-circuit-key" modifiers="accel shift" key="L" oncommand="torbutton_new_circuit()"/> </keyset> diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index dab26aeeb179..566976b6d7aa 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -632,6 +632,7 @@ var gPageIcons = { }; var gInitialPages = [ + "about:tor", "about:blank", "about:newtab", "about:home", diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 82fd0d32d670..8efb544918b8 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -29,6 +29,8 @@ <?xml-stylesheet href="chrome://browser/skin/searchbar.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css" type="text/css"?> +<?xml-stylesheet href="chrome://torbutton/skin/tor-circuit-display.css" type="text/css"?> +<?xml-stylesheet href="chrome://torbutton/skin/torbutton.css" type="text/css"?> # All DTD information is stored in a separate file so that it can be shared by # hiddenWindowMac.xhtml. @@ -106,11 +108,18 @@ Services.scriptloader.loadSubScript("chrome://browser/content/places/places-menupopup.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/search/autocomplete-popup.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this); + Services.scriptloader.loadSubScript("chrome://torbutton/content/tor-circuit-display.js", this); + Services.scriptloader.loadSubScript("chrome://torbutton/content/torbutton.js", this); window.onload = gBrowserInit.onLoad.bind(gBrowserInit); window.onunload = gBrowserInit.onUnload.bind(gBrowserInit); window.onclose = WindowIsClosing; + //onLoad Handler + try { + window.addEventListener("load", torbutton_init, false); + } catch (e) {} + window.addEventListener("MozBeforeInitialXULLayout", gBrowserInit.onBeforeInitialXULLayout.bind(gBrowserInit), { once: true }); diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 2170fe472a95..58db8ff37ce9 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -20,7 +20,6 @@ const { AppConstants } = ChromeUtils.import( Cu.importGlobalProperties(["Glean"]); XPCOMUtils.defineLazyModuleGetters(this, { - AboutNewTab: "resource:///modules/AboutNewTab.jsm", ActorManagerParent: "resource://gre/modules/ActorManagerParent.jsm", AddonManager: "resource://gre/modules/AddonManager.jsm", AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm", @@ -211,28 +210,6 @@ let JSWINDOWACTORS = { matches: ["about:logins", "about:logins?*", "about:loginsimportreport"], }, - AboutNewTab: { - parent: { - moduleURI: "resource:///actors/AboutNewTabParent.jsm", - }, - child: { - moduleURI: "resource:///actors/AboutNewTabChild.jsm", - events: { - DOMContentLoaded: {}, - pageshow: {}, - visibilitychange: {}, - }, - }, - // The wildcard on about:newtab is for the ?endpoint query parameter - // that is used for snippets debugging. The wildcard for about:home - // is similar, and also allows for falling back to loading the - // about:home document dynamically if an attempt is made to load - // about:home?jscache from the AboutHomeStartupCache as a top-level - // load. - matches: ["about:home*", "about:welcome", "about:newtab*"], - remoteTypes: ["privilegedabout"], - }, - AboutPlugins: { parent: { moduleURI: "resource:///actors/AboutPluginsParent.jsm", @@ -1617,8 +1594,6 @@ BrowserGlue.prototype = { // the first browser window has finished initializing _onFirstWindowLoaded: function BG__onFirstWindowLoaded(aWindow) { - AboutNewTab.init(); - TabCrashHandler.init(); ProcessHangMonitor.init(); @@ -5319,12 +5294,8 @@ var AboutHomeStartupCache = { return { pageInputStream: null, scriptInputStream: null }; } - let state = AboutNewTab.activityStream.store.getState(); - return new Promise(resolve => { - this._cacheDeferred = resolve; - this.log.trace("Parent is requesting cache streams."); - this._procManager.sendAsyncMessage(this.CACHE_REQUEST_MESSAGE, { state }); - }); + this.log.error("Activity Stream is disabled in Tor Browser."); + return { pageInputStream: null, scriptInputStream: null }; }, /** diff --git a/browser/components/controlcenter/content/identityPanel.inc.xhtml b/browser/components/controlcenter/content/identityPanel.inc.xhtml index 9a41ac1f33cc..06511866ae29 100644 --- a/browser/components/controlcenter/content/identityPanel.inc.xhtml +++ b/browser/components/controlcenter/content/identityPanel.inc.xhtml @@ -92,6 +92,28 @@ </vbox> </hbox> + <!-- Circuit display section --> + + <vbox id="circuit-display-container" class="identity-popup-section"> + <toolbarseparator/> + <vbox id="circuit-display-header" flex="1" role="group" + aria-labelledby="circuit-display-headline"> + <hbox flex="1"> + <label id="circuit-display-headline" + role="heading" aria-level="2">&torbutton.circuit_display.title;</label> + </hbox> + </vbox> + <vbox id="circuit-display-content"> + <html:ul id="circuit-display-nodes" dir="auto"/> + <hbox id="circuit-guard-note-container"/> + <hbox id="circuit-reload-button-container"> + <html:button id="circuit-reload-button" + onclick="torbutton_new_circuit()" + default="true">&torbutton.circuit_display.new_circuit;</html:button> + </hbox> + </vbox> + </vbox> + <!-- Clear Site Data Button --> <vbox hidden="true" id="identity-popup-clear-sitedata-footer"> diff --git a/browser/components/newtab/AboutNewTabService.jsm b/browser/components/newtab/AboutNewTabService.jsm index 44308daa2b2d..d98c014e3f9e 100644 --- a/browser/components/newtab/AboutNewTabService.jsm +++ b/browser/components/newtab/AboutNewTabService.jsm @@ -420,20 +420,7 @@ class BaseAboutNewTabService { * the newtab page has no effect on the result of this function. */ get defaultURL() { - // Generate the desired activity stream resource depending on state, e.g., - // "resource://activity-stream/prerendered/activity-stream.html" - // "resource://activity-stream/prerendered/activity-stream-debug.html" - // "resource://activity-stream/prerendered/activity-stream-noscripts.html" - return [ - "resource://activity-stream/prerendered/", - "activity-stream", - // Debug version loads dev scripts but noscripts separately loads scripts - this.activityStreamDebug && !this.privilegedAboutProcessEnabled - ? "-debug" - : "", - this.privilegedAboutProcessEnabled ? "-noscripts" : "", - ".html", - ].join(""); + return "about:tor"; } get welcomeURL() { diff --git a/browser/components/preferences/home.inc.xhtml b/browser/components/preferences/home.inc.xhtml index 5bb936782ed9..e812d969837e 100644 --- a/browser/components/preferences/home.inc.xhtml +++ b/browser/components/preferences/home.inc.xhtml @@ -33,7 +33,7 @@ class="check-home-page-controlled" data-preference-related="browser.startup.homepage"> <menupopup> - <menuitem value="0" data-l10n-id="home-mode-choice-default" /> + <menuitem value="0" label="&aboutTor.title;" /> <menuitem value="2" data-l10n-id="home-mode-choice-custom" /> <menuitem value="1" data-l10n-id="home-mode-choice-blank" /> </menupopup> @@ -84,7 +84,7 @@ Preferences so we need to handle setting the pref manually.--> <menulist id="newTabMode" flex="1" data-preference-related="browser.newtabpage.enabled"> <menupopup> - <menuitem value="0" data-l10n-id="home-mode-choice-default" /> + <menuitem value="0" label="&aboutTor.title;" /> <menuitem value="1" data-l10n-id="home-mode-choice-blank" /> </menupopup> </menulist> diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml index aab4a9e558bc..32184867ac17 100644 --- a/browser/components/preferences/preferences.xhtml +++ b/browser/components/preferences/preferences.xhtml @@ -13,7 +13,10 @@ <?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?> -<!DOCTYPE html> +<!DOCTYPE html [ +<!ENTITY % aboutTorDTD SYSTEM "chrome://torbutton/locale/aboutTor.dtd"> + %aboutTorDTD; +]> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 8f52da54f7b9..d4068cabb4ae 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -239,6 +239,8 @@ @RESPATH@/browser/chrome/browser.manifest @RESPATH@/chrome/pdfjs.manifest @RESPATH@/chrome/pdfjs/* +@RESPATH@/chrome/torbutton.manifest +@RESPATH@/chrome/torbutton/* @RESPATH@/chrome/toolkit@JAREXT@ @RESPATH@/chrome/toolkit.manifest @RESPATH@/chrome/recording.manifest diff --git a/browser/modules/HomePage.jsm b/browser/modules/HomePage.jsm index f73b0f3e6c8c..26618374df3a 100644 --- a/browser/modules/HomePage.jsm +++ b/browser/modules/HomePage.jsm @@ -21,7 +21,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { }); const kPrefName = "browser.startup.homepage"; -const kDefaultHomePage = "about:home"; +const kDefaultHomePage = "about:tor"; const kExtensionControllerPref = "browser.startup.homepage_override.extensionControlled"; const kHomePageIgnoreListId = "homepage-urls"; diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index a320b4ebd431..6ab1a57f92cf 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -158,7 +158,11 @@ static const RedirEntry kRedirMap[] = { {"crashcontent", "about:blank", nsIAboutModule::HIDE_FROM_ABOUTABOUT | nsIAboutModule::URI_CAN_LOAD_IN_CHILD | - nsIAboutModule::URI_MUST_LOAD_IN_CHILD}}; + nsIAboutModule::URI_MUST_LOAD_IN_CHILD}, + {"tor", "chrome://torbutton/content/aboutTor/aboutTor.xhtml", + nsIAboutModule::URI_MUST_LOAD_IN_CHILD | + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::ALLOW_SCRIPT}}; static const int kRedirTotal = mozilla::ArrayLength(kRedirMap); NS_IMETHODIMP diff --git a/docshell/build/components.conf b/docshell/build/components.conf index 9987b60fa2ec..475546757fd4 100644 --- a/docshell/build/components.conf +++ b/docshell/build/components.conf @@ -29,6 +29,7 @@ about_pages = [ 'srcdoc', 'support', 'telemetry', + 'tor', 'url-classifier', 'webrtc', ] diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index f0664be7b6ee..dc65078b7014 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -132,6 +132,10 @@ @BINPATH@/chrome/devtools@JAREXT@ @BINPATH@/chrome/devtools.manifest +; Torbutton +@BINPATH@/chrome/torbutton@JAREXT@ +@BINPATH@/chrome/torbutton.manifest + ; [Default Preferences] ; All the pref files must be part of base to prevent migration bugs #ifndef MOZ_ANDROID_FAT_AAR_ARCHITECTURES diff --git a/toolkit/moz.build b/toolkit/moz.build index 14f4638b693e..4edccfac6d62 100644 --- a/toolkit/moz.build +++ b/toolkit/moz.build @@ -22,6 +22,7 @@ DIRS += [ "mozapps/preferences", "profile", "themes", + "torproject/torbutton", ] if CONFIG["OS_ARCH"] == "WINNT" and CONFIG["MOZ_DEFAULT_BROWSER_AGENT"]: diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index c1cef2814b38..8e16e236b238 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -1476,6 +1476,15 @@ var XPIStates = { for (let [id, file] of loc.readAddons()) { knownIds.delete(id); + // Uninstall torbutton if it is installed in the user profile + if (id === "torbutton(a)torproject.org" && + loc.name === KEY_APP_PROFILE) { + logger.debug("Uninstalling torbutton from user profile."); + loc.installer.uninstallAddon(id); + changed = true; + continue; + } + let xpiState = loc.get(id); if (!xpiState) { // If the location is not supported for sideloading, skip new diff --git a/toolkit/torproject/torbutton b/toolkit/torproject/torbutton new file mode 160000 index 000000000000..a7f607351517 --- /dev/null +++ b/toolkit/torproject/torbutton @@ -0,0 +1 @@ +Subproject commit a7f6073515175a1f2d7a2bca1eaec2bfaff03c0c diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js index 76e03f2d49bb..2ff107b553b2 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js @@ -75,7 +75,11 @@ function getGlobalScriptIncludes(scriptPath) { "browser/components/search/content/" ) .replace("chrome://browser/content/", "browser/base/content/") - .replace("chrome://global/content/", "toolkit/content/"); + .replace("chrome://global/content/", "toolkit/content/") + .replace( + "chrome://torbutton/content/", + "toolkit/torproject/torbutton/chrome/content/" + ); for (let mapping of Object.getOwnPropertyNames(MAPPINGS)) { if (sourceFile.includes(mapping)) {
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Add TorStrings module for localization
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 25d45ad7d49a8b8e3d3ccd5e45a36628e483d585 Author: Alex Catarineu <acat(a)torproject.org> Date: Fri Jul 24 21:15:20 2020 +0200 Add TorStrings module for localization --- browser/modules/TorStrings.jsm | 490 +++++++++++++++++++++++++++++++++++++++++ browser/modules/moz.build | 1 + 2 files changed, 491 insertions(+) diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm new file mode 100644 index 000000000000..e8a8d37ae373 --- /dev/null +++ b/browser/modules/TorStrings.jsm @@ -0,0 +1,490 @@ +"use strict"; + +var EXPORTED_SYMBOLS = ["TorStrings"]; + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +const { Services } = ChromeUtils.import( + "resource://gre/modules/Services.jsm" +); +const { getLocale } = ChromeUtils.import( + "resource://torbutton/modules/utils.js" +); + +XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser"]); +XPCOMUtils.defineLazyGetter(this, "domParser", () => { + const parser = new DOMParser(); + parser.forceEnableDTD(); + return parser; +}); + +/* + Tor DTD String Bundle + + DTD strings loaded from torbutton/tor-launcher, but provide a fallback in case they aren't available +*/ +class TorDTDStringBundle { + constructor(aBundleURLs, aPrefix) { + let locations = []; + for (const [index, url] of aBundleURLs.entries()) { + locations.push(`<!ENTITY % dtd_${index} SYSTEM "${url}">%dtd_${index};`); + } + this._locations = locations; + this._prefix = aPrefix; + } + + // copied from testing/marionette/l10n.js + localizeEntity(urls, id) { + // Use the DOM parser to resolve the entity and extract its real value + let header = `<?xml version="1.0"?><!DOCTYPE elem [${this._locations.join( + "" + )}]>`; + let elem = `<elem id="elementID">&${id};</elem>`; + let doc = domParser.parseFromString(header + elem, "text/xml"); + let element = doc.querySelector("elem[id='elementID']"); + + if (element === null) { + throw new Error(`Entity with id='${id}' hasn't been found`); + } + + return element.textContent; + } + + getString(key, fallback) { + if (key) { + try { + return this.localizeEntity(this._bundleURLs, `${this._prefix}${key}`); + } catch (e) {} + } + + // on failure, assign the fallback if it exists + if (fallback) { + return fallback; + } + // otherwise return string key + return `$(${key})`; + } +} + +/* + Tor Property String Bundle + + Property strings loaded from torbutton/tor-launcher, but provide a fallback in case they aren't available +*/ +class TorPropertyStringBundle { + constructor(aBundleURL, aPrefix) { + try { + this._bundle = Services.strings.createBundle(aBundleURL); + } catch (e) {} + + this._prefix = aPrefix; + } + + getString(key, fallback) { + if (key) { + try { + return this._bundle.GetStringFromName(`${this._prefix}${key}`); + } catch (e) {} + } + + // on failure, assign the fallback if it exists + if (fallback) { + return fallback; + } + // otherwise return string key + return `$(${key})`; + } +} + +/* + Security Level Strings +*/ +var TorStrings = { + /* + Tor Browser Security Level Strings + */ + securityLevel: (function() { + let tsb = new TorDTDStringBundle( + ["chrome://torbutton/locale/torbutton.dtd"], + "torbutton.prefs.sec_" + ); + let getString = function(key, fallback) { + return tsb.getString(key, fallback); + }; + + // read localized strings from torbutton; but use hard-coded en-US strings as fallbacks in case of error + let retval = { + securityLevel: getString("caption", "Security Level"), + customWarning: getString("custom_warning", "Custom"), + overview: getString( + "overview", + "Disable certain web features that can be used to attack your security and anonymity." + ), + standard: { + level: getString("standard_label", "Standard"), + tooltip: getString("standard_tooltip", "Security Level : Standard"), + summary: getString( + "standard_description", + "All Tor Browser and website features are enabled." + ), + }, + safer: { + level: getString("safer_label", "Safer"), + tooltip: getString("safer_tooltip", "Security Level : Safer"), + summary: getString( + "safer_description", + "Disables website features that are often dangerous, causing some sites to lose functionality." + ), + description1: getString( + "js_on_https_sites_only", + "JavaScript is disabled on non-HTTPS sites." + ), + description2: getString( + "limit_typography", + "Some fonts and math symbols are disabled." + ), + description3: getString( + "click_to_play_media", + "Audio and video (HTML5 media), and WebGL are click-to-play." + ), + }, + safest: { + level: getString("safest_label", "Safest"), + tooltip: getString("safest_tooltip", "Security Level : Safest"), + summary: getString( + "safest_description", + "Only allows website features required for static sites and basic services. These changes affect images, media, and scripts." + ), + description1: getString( + "js_disabled", + "JavaScript is disabled by default on all sites." + ), + description2: getString( + "limit_graphics_and_typography", + "Some fonts, icons, math symbols, and images are disabled." + ), + description3: getString( + "click_to_play_media", + "Audio and video (HTML5 media), and WebGL are click-to-play." + ), + }, + custom: { + summary: getString( + "custom_summary", + "Your custom browser preferences have resulted in unusual security settings. For security and privacy reasons, we recommend you choose one of the default security levels." + ), + }, + learnMore: getString("learn_more_label", "Learn more"), + learnMoreURL: `https://tb-manual.torproject.org/${getLocale()}/security-settings/`, + restoreDefaults: getString("restore_defaults", "Restore Defaults"), + advancedSecuritySettings: getString( + "advanced_security_settings", + "Advanced Security Settings\u2026" + ), + }; + return retval; + })() /* Security Level Strings */, + + /* + Tor about:preferences#tor Strings + */ + settings: (function() { + let tsb = new TorDTDStringBundle( + ["chrome://torlauncher/locale/network-settings.dtd"], + "" + ); + let getString = function(key, fallback) { + return tsb.getString(key, fallback); + }; + + let retval = { + categoryTitle: getString("torPreferences.categoryTitle", "Tor"), + torPreferencesHeading: getString( + "torPreferences.torSettings", + "Tor Settings" + ), + torPreferencesDescription: getString( + "torPreferences.torSettingsDescription", + "Tor Browser routes your traffic over the Tor Network, run by thousands of volunteers around the world." + ), + learnMore: getString("torPreferences.learnMore", "Learn More"), + bridgesHeading: getString("torPreferences.bridges", "Bridges"), + bridgesDescription: getString( + "torPreferences.bridgesDescription", + "Bridges help you access the Tor Network in places where Tor is blocked. Depending on where you are, one bridge may work better than another." + ), + useBridge: getString("torPreferences.useBridge", "Use a bridge"), + selectBridge: getString( + "torsettings.useBridges.default", + "Select a bridge" + ), + requestBridgeFromTorProject: getString( + "torsettings.useBridges.bridgeDB", + "Request a bridge from torproject.org" + ), + requestNewBridge: getString( + "torPreferences.requestNewBridge", + "Request a New Bridge\u2026" + ), + provideBridge: getString( + "torPreferences.provideBridge", + "Provide a bridge" + ), + provideBridgeDirections: getString( + "torsettings.useBridges.label", + "Enter bridge information from a trusted source." + ), + provideBridgePlaceholder: getString( + "torsettings.useBridges.placeholder", + "type address:port (one per line)" + ), + advancedHeading: getString("torPreferences.advanced", "Advanced"), + advancedDescription: getString( + "torPreferences.advancedDescription", + "Configure how Tor Browser connects to the internet." + ), + useLocalProxy: getString("torsettings.useProxy.checkbox", "I use a proxy to connect to the Internet"), + proxyType: getString("torsettings.useProxy.type", "Proxy Type"), + proxyTypeSOCKS4: getString("torsettings.useProxy.type.socks4", "SOCKS4"), + proxyTypeSOCKS5: getString("torsettings.useProxy.type.socks5", "SOCKS5"), + proxyTypeHTTP: getString("torsettings.useProxy.type.http", "HTTP/HTTPS"), + proxyAddress: getString("torsettings.useProxy.address", "Address"), + proxyAddressPlaceholder: getString( + "torsettings.useProxy.address.placeholder", + "IP address or hostname" + ), + proxyPort: getString("torsettings.useProxy.port", "Port"), + proxyUsername: getString("torsettings.useProxy.username", "Username"), + proxyPassword: getString("torsettings.useProxy.password", "Password"), + proxyUsernamePasswordPlaceholder: getString( + "torsettings.optional", + "Optional" + ), + useFirewall: getString( + "torsettings.firewall.checkbox", + "This computer goes through a firewall that only allows connections to certain ports" + ), + allowedPorts: getString( + "torsettings.firewall.allowedPorts", + "Allowed Ports" + ), + allowedPortsPlaceholder: getString( + "torPreferences.firewallPortsPlaceholder", + "Comma-seperated values" + ), + requestBridgeDialogTitle: getString( + "torPreferences.requestBridgeDialogTitle", + "Request Bridge" + ), + submitCaptcha: getString( + "torsettings.useBridges.captchaSubmit", + "Submit" + ), + contactingBridgeDB: getString( + "torPreferences.requestBridgeDialogWaitPrompt", + "Contacting BridgeDB. Please Wait." + ), + solveTheCaptcha: getString( + "torPreferences.requestBridgeDialogSolvePrompt", + "Solve the CAPTCHA to request a bridge." + ), + captchaTextboxPlaceholder: getString( + "torsettings.useBridges.captchaSolution.placeholder", + "Enter the characters from the image" + ), + incorrectCaptcha: getString( + "torPreferences.requestBridgeErrorBadSolution", + "The solution is not correct. Please try again." + ), + showTorDaemonLogs: getString( + "torPreferences.viewTorLogs", + "View the Tor logs." + ), + showLogs: getString("torPreferences.viewLogs", "View Logs\u2026"), + torLogDialogTitle: getString( + "torPreferences.torLogsDialogTitle", + "Tor Logs" + ), + copyLog: getString("torsettings.copyLog", "Copy Tor Log to Clipboard"), + + learnMoreTorBrowserURL: `https://tb-manual.torproject.org/${getLocale()}/about/`, + learnMoreBridgesURL: `https://tb-manual.torproject.org/${getLocale()}/bridges/`, + learnMoreNetworkSettingsURL: `about:blank`, + }; + + return retval; + })() /* Tor Network Settings Strings */, + + /* + Tor Onion Services Strings, e.g., for the authentication prompt. + */ + onionServices: (function() { + let tsb = new TorPropertyStringBundle( + "chrome://torbutton/locale/torbutton.properties", + "onionServices." + ); + let getString = function(key, fallback) { + return tsb.getString(key, fallback); + }; + + const kProblemLoadingSiteFallback = "Problem Loading Onionsite"; + const kLongDescFallback = "Details: %S"; + + let retval = { + learnMore: getString("learnMore", "Learn more"), + learnMoreURL: `https://support.torproject.org/${getLocale()}/onionservices/client-auth/`, + 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.description2", "%S is requesting that you authenticate."), + keyPlaceholder: getString("authPrompt.keyPlaceholder", "Enter your key"), + done: getString("authPrompt.done", "Done"), + doneAccessKey: getString("authPrompt.doneAccessKey", "d"), + invalidKey: getString("authPrompt.invalidKey", "Invalid key"), + failedToSetKey: + getString("authPrompt.failedToSetKey", "Failed to set key"), + }, + authPreferences: { + header: getString("authPreferences.header", "Onion Services Authentication"), + overview: getString("authPreferences.overview", "Some onion services require that you identify yourself with a key"), + savedKeys: getString("authPreferences.savedKeys", "Saved Keys"), + dialogTitle: getString("authPreferences.dialogTitle", "Onion Services Keys"), + dialogIntro: getString("authPreferences.dialogIntro", "Keys for the following onionsites are stored on your computer"), + onionSite: getString("authPreferences.onionSite", "Onionsite"), + onionKey: getString("authPreferences.onionKey", "Key"), + remove: getString("authPreferences.remove", "Remove"), + removeAll: getString("authPreferences.removeAll", "Remove All"), + failedToGetKeys: getString("authPreferences.failedToGetKeys", "Failed to get keys"), + failedToRemoveKey: getString("authPreferences.failedToRemoveKey", "Failed to remove key"), + }, + }; + + 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()}/onion-services/`, + 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 + */ + + // TODO: proper camel case + configKeys: { + /* Bridge Conf Settings */ + useBridges: "UseBridges", + bridgeList: "Bridge", + /* Proxy Conf Strings */ + socks4Proxy: "Socks4Proxy", + socks5Proxy: "Socks5Proxy", + socks5ProxyUsername: "Socks5ProxyUsername", + socks5ProxyPassword: "Socks5ProxyPassword", + httpsProxy: "HTTPSProxy", + httpsProxyAuthenticator: "HTTPSProxyAuthenticator", + /* Firewall Conf Strings */ + reachableAddresses: "ReachableAddresses", + + /* BridgeDB Strings */ + clientTransportPlugin: "ClientTransportPlugin", + }, + + /* + about:config preference keys + */ + + preferenceKeys: { + defaultBridgeType: "extensions.torlauncher.default_bridge_type", + recommendedBridgeType: + "extensions.torlauncher.default_bridge_recommended_type", + }, + + /* + about:config preference branches + */ + preferenceBranches: { + defaultBridge: "extensions.torlauncher.default_bridge.", + bridgeDBBridges: "extensions.torlauncher.bridgedb_bridge.", + }, +}; diff --git a/browser/modules/moz.build b/browser/modules/moz.build index 646784690c9a..bc543283d887 100644 --- a/browser/modules/moz.build +++ b/browser/modules/moz.build @@ -156,6 +156,7 @@ EXTRA_JS_MODULES += [ "ThemeVariableMap.jsm", "TorProtocolService.jsm", "TorSettings.jsm", + "TorStrings.jsm", "TransientPrefs.jsm", "webrtcUI.jsm", "ZoomUI.jsm",
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 28044: Integrate Tor Launcher into tor-browser
by richard@torproject.org 09 Feb '22

09 Feb '22
commit dbd3af6e7564b23cdf19ae6d013c5e781ed54ae7 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Feb 26 10:07:17 2019 -0500 Bug 28044: Integrate Tor Launcher into tor-browser Build and package Tor Launcher as part of the browser (similar to how pdfjs is handled). If a Tor Launcher extension is present in the user's profile, it is removed. --- .mozconfig | 2 +- browser/extensions/moz.build | 3 +++ browser/installer/package-manifest.in | 5 +++++ toolkit/mozapps/extensions/internal/XPIProvider.jsm | 10 ++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.mozconfig b/.mozconfig index 18cd1f9b6487..7fe8633a9ef4 100755 --- a/.mozconfig +++ b/.mozconfig @@ -34,6 +34,6 @@ ac_add_options --enable-proxy-bypass-protection # Disable telemetry ac_add_options MOZ_TELEMETRY_REPORTING= -ac_add_options --disable-tor-launcher +ac_add_options --enable-tor-launcher ac_add_options --with-tor-browser-version=dev-build ac_add_options --disable-tor-browser-update diff --git a/browser/extensions/moz.build b/browser/extensions/moz.build index 339702b90a8a..d76a9f93d9af 100644 --- a/browser/extensions/moz.build +++ b/browser/extensions/moz.build @@ -10,3 +10,6 @@ if CONFIG["NIGHTLY_BUILD"]: DIRS += [ "translations", ] + +if not CONFIG["TOR_BROWSER_DISABLE_TOR_LAUNCHER"]: + DIRS += ["tor-launcher"] diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index d4068cabb4ae..d46707ca8720 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -239,6 +239,11 @@ @RESPATH@/browser/chrome/browser.manifest @RESPATH@/chrome/pdfjs.manifest @RESPATH@/chrome/pdfjs/* +#ifndef TOR_BROWSER_DISABLE_TOR_LAUNCHER +@RESPATH@/browser/chrome/torlauncher.manifest +@RESPATH@/browser/chrome/torlauncher/* +@RESPATH@/browser/@PREF_DIR@/torlauncher-prefs.js +#endif @RESPATH@/chrome/torbutton.manifest @RESPATH@/chrome/torbutton/* @RESPATH@/chrome/toolkit@JAREXT@ diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 8e16e236b238..04d57a42348e 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -1485,6 +1485,16 @@ var XPIStates = { continue; } + // Since it is now part of the browser, uninstall the Tor Launcher + // extension. This will remove the Tor Launcher .xpi from user + // profiles on macOS. + if (id === "tor-launcher(a)torproject.org") { + logger.debug("Uninstalling the Tor Launcher extension."); + loc.installer.uninstallAddon(id); + changed = true; + continue; + } + let xpiState = loc.get(id); if (!xpiState) { // If the location is not supported for sideloading, skip new
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] 40209: Implement Basic Crypto Safety
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 70ed67349a18625c176b9b622ce6804a7f545463 Author: sanketh <me(a)snkth.com> Date: Mon Feb 8 20:12:44 2021 -0500 40209: Implement Basic Crypto Safety Adds a CryptoSafety actor which detects when you've copied a crypto address from a HTTP webpage and shows a warning. Closes #40209. Bug 40428: Fix string attribute names --- browser/actors/CryptoSafetyChild.jsm | 87 ++++++++++++++++ browser/actors/CryptoSafetyParent.jsm | 142 +++++++++++++++++++++++++++ browser/actors/moz.build | 2 + browser/base/content/popup-notifications.inc | 14 +++ browser/components/BrowserGlue.jsm | 18 ++++ browser/modules/TorStrings.jsm | 48 +++++++++ browser/themes/shared/browser.inc.css | 5 + toolkit/content/license.html | 32 ++++++ toolkit/modules/Bech32Decode.jsm | 103 +++++++++++++++++++ toolkit/modules/moz.build | 1 + 10 files changed, 452 insertions(+) diff --git a/browser/actors/CryptoSafetyChild.jsm b/browser/actors/CryptoSafetyChild.jsm new file mode 100644 index 000000000000..87ff261d4915 --- /dev/null +++ b/browser/actors/CryptoSafetyChild.jsm @@ -0,0 +1,87 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* Copyright (c) 2020, The Tor Project, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var EXPORTED_SYMBOLS = ["CryptoSafetyChild"]; + +const { Bech32Decode } = ChromeUtils.import( + "resource://gre/modules/Bech32Decode.jsm" +); + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +const kPrefCryptoSafety = "security.cryptoSafety"; + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "isCryptoSafetyEnabled", + kPrefCryptoSafety, + true /* defaults to true */ +); + +function looksLikeCryptoAddress(s) { + // P2PKH and P2SH addresses + // https://stackoverflow.com/a/24205650 + const bitcoinAddr = /^[13][a-km-zA-HJ-NP-Z1-9]{25,39}$/; + if (bitcoinAddr.test(s)) { + return true; + } + + // Bech32 addresses + if (Bech32Decode(s) !== null) { + return true; + } + + // regular addresses + const etherAddr = /^0x[a-fA-F0-9]{40}$/; + if (etherAddr.test(s)) { + return true; + } + + // t-addresses + // https://www.reddit.com/r/zec/comments/8mxj6x/simple_regex_to_validate_a_zca… + const zcashAddr = /^t1[a-zA-Z0-9]{33}$/; + if (zcashAddr.test(s)) { + return true; + } + + // Standard, Integrated, and 256-bit Integrated addresses + // https://monero.stackexchange.com/a/10627 + const moneroAddr = /^4(?:[0-9AB]|[1-9A-HJ-NP-Za-km-z]{12}(?:[1-9A-HJ-NP-Za-km-z]{30})?)[1-9A-HJ-NP-Za-km-z]{93}$/; + if (moneroAddr.test(s)) { + return true; + } + + return false; +} + +class CryptoSafetyChild extends JSWindowActorChild { + handleEvent(event) { + if (isCryptoSafetyEnabled) { + // Ignore non-HTTP addresses + if (!this.document.documentURIObject.schemeIs("http")) { + return; + } + // Ignore onion addresses + if (this.document.documentURIObject.host.endsWith(".onion")) { + return; + } + + if (event.type == "copy" || event.type == "cut") { + this.contentWindow.navigator.clipboard.readText().then(clipText => { + const selection = clipText.trim(); + if (looksLikeCryptoAddress(selection)) { + this.sendAsyncMessage("CryptoSafety:CopiedText", { + selection, + }); + } + }); + } + } + } +} diff --git a/browser/actors/CryptoSafetyParent.jsm b/browser/actors/CryptoSafetyParent.jsm new file mode 100644 index 000000000000..bac151df5511 --- /dev/null +++ b/browser/actors/CryptoSafetyParent.jsm @@ -0,0 +1,142 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* Copyright (c) 2020, The Tor Project, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var EXPORTED_SYMBOLS = ["CryptoSafetyParent"]; + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +XPCOMUtils.defineLazyModuleGetters(this, { + TorStrings: "resource:///modules/TorStrings.jsm", +}); + +const kPrefCryptoSafety = "security.cryptoSafety"; + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "isCryptoSafetyEnabled", + kPrefCryptoSafety, + true /* defaults to true */ +); + +class CryptoSafetyParent extends JSWindowActorParent { + getBrowser() { + return this.browsingContext.top.embedderElement; + } + + receiveMessage(aMessage) { + if (isCryptoSafetyEnabled) { + if (aMessage.name == "CryptoSafety:CopiedText") { + showPopup(this.getBrowser(), aMessage.data.selection); + } + } + } +} + +function trimAddress(cryptoAddr) { + if (cryptoAddr.length <= 32) { + return cryptoAddr; + } + return cryptoAddr.substring(0, 32) + "..."; +} + +function showPopup(aBrowser, cryptoAddr) { + const chromeDoc = aBrowser.ownerDocument; + if (chromeDoc) { + const win = chromeDoc.defaultView; + const cryptoSafetyPrompt = new CryptoSafetyPrompt( + aBrowser, + win, + cryptoAddr + ); + cryptoSafetyPrompt.show(); + } +} + +class CryptoSafetyPrompt { + constructor(aBrowser, aWin, cryptoAddr) { + this._browser = aBrowser; + this._win = aWin; + this._cryptoAddr = cryptoAddr; + } + + show() { + const primaryAction = { + label: TorStrings.cryptoSafetyPrompt.primaryAction, + accessKey: TorStrings.cryptoSafetyPrompt.primaryActionAccessKey, + callback: () => { + this._win.torbutton_new_circuit(); + }, + }; + + const secondaryAction = { + label: TorStrings.cryptoSafetyPrompt.secondaryAction, + accessKey: TorStrings.cryptoSafetyPrompt.secondaryActionAccessKey, + callback: () => {}, + }; + + let _this = this; + const options = { + popupIconURL: "chrome://browser/skin/cert-error.svg", + eventCallback(aTopic) { + if (aTopic === "showing") { + _this._onPromptShowing(); + } + }, + }; + + const cryptoWarningText = TorStrings.cryptoSafetyPrompt.cryptoWarning.replace( + "%S", + trimAddress(this._cryptoAddr) + ); + + if (this._win.PopupNotifications) { + this._prompt = this._win.PopupNotifications.show( + this._browser, + "crypto-safety-warning", + cryptoWarningText, + null /* anchor ID */, + primaryAction, + [secondaryAction], + options + ); + } + } + + _onPromptShowing() { + let xulDoc = this._browser.ownerDocument; + + let whatCanHeading = xulDoc.getElementById( + "crypto-safety-warning-notification-what-can-heading" + ); + if (whatCanHeading) { + whatCanHeading.textContent = TorStrings.cryptoSafetyPrompt.whatCanHeading; + } + + let whatCanBody = xulDoc.getElementById( + "crypto-safety-warning-notification-what-can-body" + ); + if (whatCanBody) { + whatCanBody.textContent = TorStrings.cryptoSafetyPrompt.whatCanBody; + } + + let learnMoreElem = xulDoc.getElementById( + "crypto-safety-warning-notification-learnmore" + ); + if (learnMoreElem) { + learnMoreElem.setAttribute( + "value", + TorStrings.cryptoSafetyPrompt.learnMore + ); + learnMoreElem.setAttribute( + "href", + TorStrings.cryptoSafetyPrompt.learnMoreURL + ); + } + } +} diff --git a/browser/actors/moz.build b/browser/actors/moz.build index 626ee52d34f2..b329f3cfb8ff 100644 --- a/browser/actors/moz.build +++ b/browser/actors/moz.build @@ -56,6 +56,8 @@ FINAL_TARGET_FILES.actors += [ "ContentSearchParent.jsm", "ContextMenuChild.jsm", "ContextMenuParent.jsm", + "CryptoSafetyChild.jsm", + "CryptoSafetyParent.jsm", "DecoderDoctorChild.jsm", "DecoderDoctorParent.jsm", "DOMFullscreenChild.jsm", diff --git a/browser/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc index 6adfde017b9e..8f6d28cc81b2 100644 --- a/browser/base/content/popup-notifications.inc +++ b/browser/base/content/popup-notifications.inc @@ -162,3 +162,17 @@ </vbox> </popupnotificationfooter> </popupnotification> + + <popupnotification id="crypto-safety-warning-notification" hidden="true"> + <popupnotificationcontent orient="vertical"> + <description id="crypto-safety-warning-notification-desc"/> + <html:div id="crypto-safety-warning-notification-what-can"> + <html:strong id="crypto-safety-warning-notification-what-can-heading" /> + <html:br/> + <html:span id="crypto-safety-warning-notification-what-can-body" /> + </html:div> + <label id="crypto-safety-warning-notification-learnmore" + class="popup-notification-learnmore-link" + is="text-link"/> + </popupnotificationcontent> + </popupnotification> diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 58db8ff37ce9..9dfad0358ed7 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -432,6 +432,24 @@ let JSWINDOWACTORS = { }, messageManagerGroups: ["browsers"], + + allFrames: true, + }, + + CryptoSafety: { + parent: { + moduleURI: "resource:///actors/CryptoSafetyParent.jsm", + }, + + child: { + moduleURI: "resource:///actors/CryptoSafetyChild.jsm", + group: "browsers", + events: { + copy: { mozSystemGroup: true }, + cut: { mozSystemGroup: true }, + }, + }, + allFrames: true, }, diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm index e8a8d37ae373..1e08b168e4af 100644 --- a/browser/modules/TorStrings.jsm +++ b/browser/modules/TorStrings.jsm @@ -101,6 +101,54 @@ class TorPropertyStringBundle { Security Level Strings */ var TorStrings = { + /* + CryptoSafetyPrompt Strings + */ + cryptoSafetyPrompt: (function() { + let tsb = new TorPropertyStringBundle( + "chrome://torbutton/locale/torbutton.properties", + "cryptoSafetyPrompt." + ); + let getString = function(key, fallback) { + return tsb.getString(key, fallback); + }; + + let retval = { + cryptoWarning: getString( + "cryptoWarning", + "A cryptocurrency address (%S) has been copied from an insecure website. It could have been modified." + ), + whatCanHeading: getString( + "whatCanHeading", + "What can you do about it?" + ), + whatCanBody: getString( + "whatCanBody", + "You can try reconnecting with a new circuit to establish a secure connection, or accept the risk and dismiss this warning." + ), + learnMore: getString("learnMore", "Learn more"), + learnMoreURL: `https://support.torproject.org/${getLocale()}/`, + primaryAction: getString( + "primaryAction", + "Reload Tab with a New Circuit" + ), + primaryActionAccessKey: getString( + "primaryActionAccessKey", + "R" + ), + secondaryAction: getString( + "secondaryAction", + "Dismiss Warning" + ), + secondaryActionAccessKey: getString( + "secondaryActionAccessKey", + "D" + ), + }; + + return retval; + })() /* CryptoSafetyPrompt Strings */, + /* Tor Browser Security Level Strings */ diff --git a/browser/themes/shared/browser.inc.css b/browser/themes/shared/browser.inc.css index 2eeefda472d6..e70aeab1c761 100644 --- a/browser/themes/shared/browser.inc.css +++ b/browser/themes/shared/browser.inc.css @@ -828,3 +828,8 @@ popupnotificationcontent { #tab-notification-deck { display: block; } + +#crypto-safety-warning-notification-what-can { + display: block; + margin: 5px; +} diff --git a/toolkit/content/license.html b/toolkit/content/license.html index d26dc7118d3c..782e874edf2a 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -70,6 +70,7 @@ <li><a href="about:license#arm">ARM License</a></li> <li><a href="about:license#babel">Babel License</a></li> <li><a href="about:license#babylon">Babylon License</a></li> + <li><a href="about:license#bech32">Bech32 License</a></li> <li><a href="about:license#bincode">bincode License</a></li> <li><a href="about:license#bsd2clause">BSD 2-Clause License</a></li> <li><a href="about:license#bsd3clause">BSD 3-Clause License</a></li> @@ -2105,6 +2106,37 @@ furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +</pre> + + + <hr> + + <h1><a id="bech32"></a>Bech32 License</h1> + + <p>This license applies to the file + <code>toolkit/modules/Bech32Decode.jsm</code>. + </p> + +<pre> +Copyright (c) 2017 Pieter Wuille + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/toolkit/modules/Bech32Decode.jsm b/toolkit/modules/Bech32Decode.jsm new file mode 100644 index 000000000000..3a2bc7ae0a10 --- /dev/null +++ b/toolkit/modules/Bech32Decode.jsm @@ -0,0 +1,103 @@ +// Adapted from the reference implementation of Bech32 +// https://github.com/sipa/bech32 + +// Copyright (c) 2017 Pieter Wuille +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +"use strict"; + +/** + * JS module implementation of Bech32 decoding adapted from the reference + * implementation https://github.com/sipa/bech32. + */ + +var EXPORTED_SYMBOLS = ["Bech32Decode"]; + +var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; +var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; + +function polymod(values) { + var chk = 1; + for (var p = 0; p < values.length; ++p) { + var top = chk >> 25; + chk = ((chk & 0x1ffffff) << 5) ^ values[p]; + for (var i = 0; i < 5; ++i) { + if ((top >> i) & 1) { + chk ^= GENERATOR[i]; + } + } + } + return chk; +} + +function hrpExpand(hrp) { + var ret = []; + var p; + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) >> 5); + } + ret.push(0); + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) & 31); + } + return ret; +} + +function verifyChecksum(hrp, data) { + return polymod(hrpExpand(hrp).concat(data)) === 1; +} + +function Bech32Decode(bechString) { + var p; + var has_lower = false; + var has_upper = false; + for (p = 0; p < bechString.length; ++p) { + if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { + return null; + } + if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { + has_lower = true; + } + if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { + has_upper = true; + } + } + if (has_lower && has_upper) { + return null; + } + bechString = bechString.toLowerCase(); + var pos = bechString.lastIndexOf("1"); + if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { + return null; + } + var hrp = bechString.substring(0, pos); + var data = []; + for (p = pos + 1; p < bechString.length; ++p) { + var d = CHARSET.indexOf(bechString.charAt(p)); + if (d === -1) { + return null; + } + data.push(d); + } + if (!verifyChecksum(hrp, data)) { + return null; + } + return { hrp: hrp, data: data.slice(0, data.length - 6) }; +} diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 9d349d9f3394..a3bfdf83ffbd 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -152,6 +152,7 @@ EXTRA_JS_MODULES += [ "ActorManagerParent.jsm", "AppMenuNotifications.jsm", "AsyncPrefs.jsm", + "Bech32Decode.jsm", "BinarySearch.jsm", "BrowserTelemetryUtils.jsm", "BrowserUtils.jsm",
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 19273: Avoid JavaScript patching of the external app helper dialog.
by richard@torproject.org 09 Feb '22

09 Feb '22
commit e973259110333c92842610d643a374aab23a5345 Author: Kathy Brade <brade(a)pearlcrescent.com> Date: Tue Jun 28 15:13:05 2016 -0400 Bug 19273: Avoid JavaScript patching of the external app helper dialog. When handling an external URI or downloading a file, invoke Torbutton's external app blocker component (which will present a download warning dialog unless the user has checked the "Automatically download files from now on" box). For e10s compatibility, avoid using a modal dialog and instead use a callback interface (nsIHelperAppWarningLauncher) to allow Torbutton to indicate the user's desire to cancel or continue each request. Other bugs fixed: Bug 21766: Crash with e10s enabled while trying to download a file Bug 21886: Download is stalled in non-e10s mode Bug 22471: Downloading files via the PDF viewer download button is broken Bug 22472: Fix FTP downloads when external helper app dialog is shown Bug 22610: Avoid crashes when canceling external helper app downloads Bug 22618: Downloading pdf file via file:/// is stalling --- .../exthandler/nsExternalHelperAppService.cpp | 177 ++++++++++++++++++--- uriloader/exthandler/nsExternalHelperAppService.h | 3 + .../exthandler/nsIExternalHelperAppService.idl | 47 ++++++ 3 files changed, 209 insertions(+), 18 deletions(-) diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 0d697b3bec33..a34e7d983cf0 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -133,6 +133,9 @@ static const char NEVER_ASK_FOR_SAVE_TO_DISK_PREF[] = static const char NEVER_ASK_FOR_OPEN_FILE_PREF[] = "browser.helperApps.neverAsk.openFile"; +static const char WARNING_DIALOG_CONTRACT_ID[] = + "@torproject.org/torbutton-extAppBlocker;1"; + // Helper functions for Content-Disposition headers /** @@ -423,6 +426,22 @@ static nsresult GetDownloadDirectory(nsIFile** _directory, return NS_OK; } +static already_AddRefed<nsIInterfaceRequestor> GetDialogParentAux( + BrowsingContext* aBrowsingContext, nsIInterfaceRequestor* aWindowContext) { + nsCOMPtr<nsIInterfaceRequestor> dialogParent = aWindowContext; + + if (!dialogParent && aBrowsingContext) { + dialogParent = do_QueryInterface(aBrowsingContext->GetDOMWindow()); + } + if (!dialogParent && aBrowsingContext && XRE_IsParentProcess()) { + RefPtr<Element> element = aBrowsingContext->Top()->GetEmbedderElement(); + if (element) { + dialogParent = do_QueryInterface(element->OwnerDoc()->GetWindow()); + } + } + return dialogParent.forget(); +} + /** * Structure for storing extension->type mappings. * @see defaultMimeEntries @@ -627,6 +646,96 @@ static const char* descriptionOverwriteExtensions[] = { "avif", "jxl", "pdf", "svg", "webp", "xml", }; +////////////////////////////////////////////////////////////////////////////////////////////////////// +// begin nsExternalLoadURIHandler class definition and implementation +////////////////////////////////////////////////////////////////////////////////////////////////////// +class nsExternalLoadURIHandler final : public nsIHelperAppWarningLauncher { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIHELPERAPPWARNINGLAUNCHER + + nsExternalLoadURIHandler(nsIHandlerInfo* aHandlerInfo, nsIURI* aURI, + nsIPrincipal* aTriggeringPrincipal, + BrowsingContext* aBrowsingContext, + bool aTriggeredExternally); + + protected: + ~nsExternalLoadURIHandler(); + + nsCOMPtr<nsIHandlerInfo> mHandlerInfo; + nsCOMPtr<nsIURI> mURI; + nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; + RefPtr<BrowsingContext> mBrowsingContext; + bool mTriggeredExternally; + nsCOMPtr<nsIHelperAppWarningDialog> mWarningDialog; +}; + +NS_IMPL_ADDREF(nsExternalLoadURIHandler) +NS_IMPL_RELEASE(nsExternalLoadURIHandler) + +NS_INTERFACE_MAP_BEGIN(nsExternalLoadURIHandler) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHelperAppWarningLauncher) + NS_INTERFACE_MAP_ENTRY(nsIHelperAppWarningLauncher) +NS_INTERFACE_MAP_END + +nsExternalLoadURIHandler::nsExternalLoadURIHandler( + nsIHandlerInfo* aHandlerInfo, nsIURI* aURI, + nsIPrincipal* aTriggeringPrincipal, BrowsingContext* aBrowsingContext, + bool aTriggeredExternally) + : mHandlerInfo(aHandlerInfo), + mURI(aURI), + mTriggeringPrincipal(aTriggeringPrincipal), + mBrowsingContext(aBrowsingContext), + mTriggeredExternally(aTriggeredExternally) + +{ + nsresult rv = NS_OK; + mWarningDialog = do_CreateInstance(WARNING_DIALOG_CONTRACT_ID, &rv); + if (NS_SUCCEEDED(rv) && mWarningDialog) { + // This will create a reference cycle (the dialog holds a reference to us + // as nsIHelperAppWarningLauncher), which will be broken in ContinueRequest + // or CancelRequest. + nsCOMPtr<nsIInterfaceRequestor> dialogParent = + GetDialogParentAux(aBrowsingContext, nullptr); + rv = mWarningDialog->MaybeShow(this, dialogParent); + } + + if (NS_FAILED(rv)) { + // If for some reason we could not open the download warning prompt, + // continue with the request. + ContinueRequest(); + } +} + +nsExternalLoadURIHandler::~nsExternalLoadURIHandler() {} + +NS_IMETHODIMP nsExternalLoadURIHandler::ContinueRequest() { + MOZ_ASSERT(mURI); + MOZ_ASSERT(mHandlerInfo); + + // Break our reference cycle with the download warning dialog (set up in + // LoadURI). + mWarningDialog = nullptr; + + nsresult rv = NS_OK; + nsCOMPtr<nsIContentDispatchChooser> chooser = + do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return chooser->HandleURI(mHandlerInfo, mURI, mTriggeringPrincipal, + mBrowsingContext, mTriggeredExternally); +} + +NS_IMETHODIMP nsExternalLoadURIHandler::CancelRequest(nsresult aReason) { + NS_ENSURE_ARG(NS_FAILED(aReason)); + + // Break our reference cycle with the download warning dialog (set up in + // LoadURI). + mWarningDialog = nullptr; + + return NS_OK; +} + static StaticRefPtr<nsExternalHelperAppService> sExtHelperAppSvcSingleton; /** @@ -653,6 +762,9 @@ nsExternalHelperAppService::GetSingleton() { return do_AddRef(sExtHelperAppSvcSingleton); } +////////////////////////////////////////////////////////////////////////////////////////////////////// +// nsExternalHelperAppService definition and implementation +////////////////////////////////////////////////////////////////////////////////////////////////////// NS_IMPL_ISUPPORTS(nsExternalHelperAppService, nsIExternalHelperAppService, nsPIExternalAppLauncher, nsIExternalProtocolService, nsIMIMEService, nsIObserver, nsISupportsWeakReference) @@ -1143,14 +1255,15 @@ nsExternalHelperAppService::LoadURI(nsIURI* aURI, rv = GetProtocolHandlerInfo(scheme, getter_AddRefs(handler)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIContentDispatchChooser> chooser = - do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - return chooser->HandleURI( + RefPtr<nsExternalLoadURIHandler> h = new nsExternalLoadURIHandler( handler, escapedURI, aRedirectPrincipal ? aRedirectPrincipal : aTriggeringPrincipal, aBrowsingContext, aTriggeredExternally); + if (!h) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1295,6 +1408,7 @@ NS_INTERFACE_MAP_BEGIN(nsExternalAppHandler) NS_INTERFACE_MAP_ENTRY(nsIStreamListener) NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) NS_INTERFACE_MAP_ENTRY(nsIHelperAppLauncher) + NS_INTERFACE_MAP_ENTRY(nsIHelperAppWarningLauncher) NS_INTERFACE_MAP_ENTRY(nsICancelable) NS_INTERFACE_MAP_ENTRY(nsIBackgroundFileSaverObserver) NS_INTERFACE_MAP_ENTRY(nsINamed) @@ -1693,18 +1807,7 @@ void nsExternalAppHandler::MaybeApplyDecodingForExtension( already_AddRefed<nsIInterfaceRequestor> nsExternalAppHandler::GetDialogParent() { - nsCOMPtr<nsIInterfaceRequestor> dialogParent = mWindowContext; - - if (!dialogParent && mBrowsingContext) { - dialogParent = do_QueryInterface(mBrowsingContext->GetDOMWindow()); - } - if (!dialogParent && mBrowsingContext && XRE_IsParentProcess()) { - RefPtr<Element> element = mBrowsingContext->Top()->GetEmbedderElement(); - if (element) { - dialogParent = do_QueryInterface(element->OwnerDoc()->GetWindow()); - } - } - return dialogParent.forget(); + return GetDialogParentAux(mBrowsingContext, mWindowContext); } NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { @@ -1832,6 +1935,34 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { loadInfo->SetForceAllowDataURI(true); } + mWarningDialog = do_CreateInstance(WARNING_DIALOG_CONTRACT_ID, &rv); + if (NS_SUCCEEDED(rv) && mWarningDialog) { + // This will create a reference cycle (the dialog holds a reference to us + // as nsIHelperAppWarningLauncher), which will be broken in ContinueRequest + // or CancelRequest. + nsCOMPtr<nsIInterfaceRequestor> dialogParent = GetDialogParent(); + rv = mWarningDialog->MaybeShow(this, dialogParent); + } + + if (NS_FAILED(rv)) { + // If for some reason we could not open the download warning prompt, + // continue with the request. + ContinueRequest(); + } + + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::ContinueRequest() { + nsAutoCString MIMEType; + if (mMimeInfo) { + mMimeInfo->GetMIMEType(MIMEType); + } + + // Break our reference cycle with the download warning dialog (set up in + // OnStartRequest). + mWarningDialog = nullptr; + // now that the temp file is set up, find out if we need to invoke a dialog // asking the user what they want us to do with this content... @@ -1943,6 +2074,8 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { action == nsIMIMEInfo::saveToDisk) { alwaysAsk = true; } + + nsresult rv = NS_OK; if (alwaysAsk) { // Display the dialog mDialog = do_CreateInstance(NS_HELPERAPPLAUNCHERDLG_CONTRACTID, &rv); @@ -2000,6 +2133,14 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { return NS_OK; } +NS_IMETHODIMP nsExternalAppHandler::CancelRequest(nsresult aReason) { + // Break our reference cycle with the download warning dialog (set up in + // OnStartRequest). + mWarningDialog = nullptr; + + return Cancel(aReason); +} + // Convert error info into proper message text and send OnStatusChange // notification to the dialog progress listener or nsITransfer implementation. void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, @@ -2686,7 +2827,7 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { } // Break our reference cycle with the helper app dialog (set up in - // OnStartRequest) + // ContinueRequest) mDialog = nullptr; mRequest = nullptr; diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h index ff933451acbd..39f00efb644b 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -224,6 +224,7 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, */ class nsExternalAppHandler final : public nsIStreamListener, public nsIHelperAppLauncher, + public nsIHelperAppWarningLauncher, public nsIBackgroundFileSaverObserver, public nsINamed { public: @@ -231,6 +232,7 @@ class nsExternalAppHandler final : public nsIStreamListener, NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSIHELPERAPPLAUNCHER + NS_DECL_NSIHELPERAPPWARNINGLAUNCHER NS_DECL_NSICANCELABLE NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER NS_DECL_NSINAMED @@ -502,6 +504,7 @@ class nsExternalAppHandler final : public nsIStreamListener, nsCOMPtr<nsITransfer> mTransfer; nsCOMPtr<nsIHelperAppLauncherDialog> mDialog; + nsCOMPtr<nsIHelperAppWarningDialog> mWarningDialog; /** diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl index 657e15bc0742..ebdb1cdacf78 100644 --- a/uriloader/exthandler/nsIExternalHelperAppService.idl +++ b/uriloader/exthandler/nsIExternalHelperAppService.idl @@ -177,3 +177,50 @@ interface nsIHelperAppLauncher : nsICancelable */ readonly attribute uint64_t browsingContextId; }; + +/** + * nsIHelperAppWarningLauncher is implemented by two classes: + * nsExternalLoadURIHandler + * nsExternalAppHandler + */ +[scriptable, uuid(cffd508b-4aaf-43ad-99c6-671d35cbc558)] +interface nsIHelperAppWarningLauncher : nsISupports +{ + /** + * Callback invoked by the external app warning dialog to continue the + * request. + * NOTE: This will release the reference to the nsIHelperAppWarningDialog. + */ + void continueRequest(); + + /** + * Callback invoked by the external app warning dialog to cancel the request. + * NOTE: This will release the reference to the nsIHelperAppWarningDialog. + * + * @param aReason + * Pass a failure code to indicate the reason why this operation is + * being canceled. It is an error to pass a success code. + */ + void cancelRequest(in nsresult aReason); +}; + +/** + * nsIHelperAppWarningDialog is implemented by Torbutton's external app + * blocker (src/components/external-app-blocker.js). + */ +[scriptable, uuid(f4899a3f-0df3-42cc-9db8-bdf599e5a208)] +interface nsIHelperAppWarningDialog : nsISupports +{ + /** + * Possibly show a launch warning dialog (it will not be shown if the user + * has chosen to not see the warning again). + * + * @param aLauncher + * A nsIHelperAppWarningLauncher to be invoked after the user confirms + * or cancels the download. + * @param aWindowContext + * The window associated with the download. + */ + void maybeShow(in nsIHelperAppWarningLauncher aLauncher, + in nsISupports aWindowContext); +};
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 27476: Implement about:torconnect captive portal within Tor Browser
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 2f2aa50061f698380757df3bd37834c51c3271ea Author: Richard Pospesel <richard(a)torproject.org> Date: Wed Apr 28 23:09:34 2021 -0500 Bug 27476: Implement about:torconnect captive portal within Tor Browser - implements new about:torconnect page as tor-launcher replacement - adds tor connection status to url bar and tweaks UX when not online - adds new torconnect component to browser - tor process management functionality remains implemented in tor-launcher through the TorProtocolService module - adds warning/error box to about:preferences#tor when not connected to tor - explicitly allows about:torconnect URIs to ignore Resist Fingerprinting (RFP) - various tweaks to info-pages.inc.css for about:torconnect (also affects other firefox info pages) --- browser/actors/NetErrorParent.jsm | 8 + browser/base/content/browser-siteIdentity.js | 2 +- browser/base/content/browser.js | 66 +++-- browser/base/content/browser.xhtml | 2 + browser/base/content/certerror/aboutNetError.js | 12 +- browser/base/content/navigator-toolbox.inc.xhtml | 1 + browser/base/content/utilityOverlay.js | 14 + browser/components/BrowserGlue.jsm | 14 + browser/components/about/AboutRedirector.cpp | 4 + browser/components/about/components.conf | 1 + browser/components/moz.build | 1 + browser/components/sessionstore/SessionStore.jsm | 4 + browser/components/torconnect/TorConnectChild.jsm | 9 + browser/components/torconnect/TorConnectParent.jsm | 147 ++++++++++ .../torconnect/content/aboutTorConnect.css | 180 +++++++++++++ .../torconnect/content/aboutTorConnect.js | 298 +++++++++++++++++++++ .../torconnect/content/aboutTorConnect.xhtml | 45 ++++ .../components/torconnect/content/onion-slash.svg | 5 + browser/components/torconnect/content/onion.svg | 4 + .../torconnect/content/torBootstrapUrlbar.js | 93 +++++++ .../torconnect/content/torconnect-urlbar.css | 57 ++++ .../torconnect/content/torconnect-urlbar.inc.xhtml | 10 + browser/components/torconnect/jar.mn | 7 + browser/components/torconnect/moz.build | 6 + browser/components/urlbar/UrlbarInput.jsm | 32 +++ browser/modules/TorProcessService.jsm | 12 + browser/modules/TorStrings.jsm | 80 ++++++ browser/modules/moz.build | 2 + browser/themes/shared/urlbar-searchbar.inc.css | 3 + dom/base/Document.cpp | 51 +++- dom/base/nsGlobalWindowOuter.cpp | 2 + .../processsingleton/MainProcessSingleton.jsm | 5 + toolkit/modules/RemotePageAccessManager.jsm | 16 ++ toolkit/mozapps/update/UpdateService.jsm | 68 ++++- .../lib/environments/browser-window.js | 4 + 35 files changed, 1237 insertions(+), 28 deletions(-) diff --git a/browser/actors/NetErrorParent.jsm b/browser/actors/NetErrorParent.jsm index 3472c68f664a..13afbbbfd4a8 100644 --- a/browser/actors/NetErrorParent.jsm +++ b/browser/actors/NetErrorParent.jsm @@ -21,6 +21,10 @@ const { TelemetryController } = ChromeUtils.import( "resource://gre/modules/TelemetryController.jsm" ); +const { TorConnect } = ChromeUtils.import( + "resource:///modules/TorConnect.jsm" +); + const PREF_SSL_IMPACT_ROOTS = [ "security.tls.version.", "security.ssl3.", @@ -350,6 +354,10 @@ class NetErrorParent extends JSWindowActorParent { break; } } + break; + case "ShouldShowTorConnect": + return TorConnect.shouldShowTorConnect; } + return undefined; } } diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 2846a1cb2fcf..6901ce71814a 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -57,7 +57,7 @@ var gIdentityHandler = { * RegExp used to decide if an about url should be shown as being part of * the browser UI. */ - _secureInternalPages: /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback)(?:[?#]|$)/i, + _secureInternalPages: /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|torconnect)(?:[?#]|$)/i, /** * Whether the established HTTPS connection is considered "broken". diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 566976b6d7aa..ef8a19198767 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -79,6 +79,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { TabModalPrompt: "chrome://global/content/tabprompts.jsm", TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", + TorConnect: "resource:///modules/TorConnect.jsm", Translation: "resource:///modules/translation/TranslationParent.jsm", UITour: "resource:///modules/UITour.jsm", UpdateUtils: "resource://gre/modules/UpdateUtils.jsm", @@ -633,6 +634,7 @@ var gPageIcons = { var gInitialPages = [ "about:tor", + "about:torconnect", "about:blank", "about:newtab", "about:home", @@ -1837,6 +1839,8 @@ var gBrowserInit = { } this._loadHandled = true; + + TorBootstrapUrlbar.init(); }, _cancelDelayedStartup() { @@ -2385,32 +2389,48 @@ var gBrowserInit = { let defaultArgs = BrowserHandler.defaultArgs; - // If the given URI is different from the homepage, we want to load it. - if (uri != defaultArgs) { - AboutNewTab.noteNonDefaultStartup(); + // figure out which URI to actually load (or a Promise to get the uri) + uri = ((uri) => { + // If the given URI is different from the homepage, we want to load it. + if (uri != defaultArgs) { + AboutNewTab.noteNonDefaultStartup(); + + if (uri instanceof Ci.nsIArray) { + // Transform the nsIArray of nsISupportsString's into a JS Array of + // JS strings. + return Array.from( + uri.enumerate(Ci.nsISupportsString), + supportStr => supportStr.data + ); + } else if (uri instanceof Ci.nsISupportsString) { + return uri.data; + } + return uri; + } - if (uri instanceof Ci.nsIArray) { - // Transform the nsIArray of nsISupportsString's into a JS Array of - // JS strings. - return Array.from( - uri.enumerate(Ci.nsISupportsString), - supportStr => supportStr.data - ); - } else if (uri instanceof Ci.nsISupportsString) { - return uri.data; + // The URI appears to be the the homepage. We want to load it only if + // session restore isn't about to override the homepage. + let willOverride = SessionStartup.willOverrideHomepage; + if (typeof willOverride == "boolean") { + return willOverride ? null : uri; } - return uri; - } + return willOverride.then(willOverrideHomepage => + willOverrideHomepage ? null : uri + ); + })(uri); + + // if using TorConnect, convert these uris to redirects + if (TorConnect.shouldShowTorConnect) { + return Promise.resolve(uri).then((uri) => { + if (uri == null) { + uri = []; + } - // The URI appears to be the the homepage. We want to load it only if - // session restore isn't about to override the homepage. - let willOverride = SessionStartup.willOverrideHomepage; - if (typeof willOverride == "boolean") { - return willOverride ? null : uri; + uri = TorConnect.getURIsToLoad(uri); + return uri; + }); } - return willOverride.then(willOverrideHomepage => - willOverrideHomepage ? null : uri - ); + return uri; })()); }, @@ -2473,6 +2493,8 @@ var gBrowserInit = { DownloadsButton.uninit(); + TorBootstrapUrlbar.uninit(); + gAccessibilityServiceIndicator.uninit(); if (gToolbarKeyNavEnabled) { diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 8efb544918b8..f16307365728 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -10,6 +10,7 @@ override rules using selectors with the same specificity. This applies to both "content" and "skin" packages, which bug 1385444 will unify later. --> <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> +<?xml-stylesheet href="chrome://branding/content/tor-styles.css" type="text/css"?> <!-- While these stylesheets are defined in Toolkit, they are only used in the main browser window, so we can load them here. Bug 1474241 is on file to @@ -110,6 +111,7 @@ Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this); Services.scriptloader.loadSubScript("chrome://torbutton/content/tor-circuit-display.js", this); Services.scriptloader.loadSubScript("chrome://torbutton/content/torbutton.js", this); + Services.scriptloader.loadSubScript("chrome://browser/content/torconnect/torBootstrapUrlbar.js", this); window.onload = gBrowserInit.onLoad.bind(gBrowserInit); window.onunload = gBrowserInit.onUnload.bind(gBrowserInit); diff --git a/browser/base/content/certerror/aboutNetError.js b/browser/base/content/certerror/aboutNetError.js index 31c4838a053d..edf97c2a5daf 100644 --- a/browser/base/content/certerror/aboutNetError.js +++ b/browser/base/content/certerror/aboutNetError.js @@ -239,7 +239,7 @@ function setErrorPageStrings(err) { document.l10n.setAttributes(titleElement, title); } -function initPage() { +async function initPage() { // We show an offline support page in case of a system-wide error, // when a user cannot connect to the internet and access the SUMO website. // For example, clock error, which causes certerrors across the web or @@ -258,6 +258,16 @@ function initPage() { } var err = getErrorCode(); + + // proxyConnectFailure because no-tor running daemon would return this error + if ( + (err === "proxyConnectFailure") && + (await RPMSendQuery("ShouldShowTorConnect")) + ) { + // pass orginal destination as redirect param + const encodedRedirect = encodeURIComponent(document.location.href); + document.location.replace(`about:torconnect?redirect=${encodedRedirect}`); + } // List of error pages with an illustration. let illustratedErrors = [ "malformedURI", diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml index 02636a6b46b5..e7f63116ff39 100644 --- a/browser/base/content/navigator-toolbox.inc.xhtml +++ b/browser/base/content/navigator-toolbox.inc.xhtml @@ -330,6 +330,7 @@ data-l10n-id="urlbar-go-button"/> <hbox id="page-action-buttons" context="pageActionContextMenu"> <toolbartabstop/> +#include ../../components/torconnect/content/torconnect-urlbar.inc.xhtml <hbox id="contextual-feature-recommendation" role="button" hidden="true"> <hbox id="cfr-label-container"> <label id="cfr-label"/> diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 3b14beaa5b1e..a95717544b80 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -21,6 +21,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { ExtensionSettingsStore: "resource://gre/modules/ExtensionSettingsStore.jsm", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", ShellService: "resource:///modules/ShellService.jsm", + TorConnect: "resource:///modules/TorConnect.jsm", }); XPCOMUtils.defineLazyGetter(this, "ReferrerInfo", () => @@ -258,6 +259,19 @@ function openUILinkIn( aPostData, aReferrerInfo ) { + // make sure users are not faced with the scary red 'tor isn't working' screen + // if they navigate to about:tor before bootstrapped + // + // fixes tor-browser#40752 + // new tabs also redirect to about:tor if browser.newtabpage.enabled is true + // otherwise they go to about:blank + if (TorConnect.shouldShowTorConnect) { + if (url === "about:tor" || + (url === "about:newtab" && Services.prefs.getBoolPref("browser.newtabpage.enabled", false))) { + url = TorConnect.getRedirectURL(url); + } + } + var params; if (arguments.length == 3 && typeof arguments[2] == "object") { diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 9dfad0358ed7..dc956bc79616 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -703,6 +703,20 @@ let JSWINDOWACTORS = { allFrames: true, }, + TorConnect: { + parent: { + moduleURI: "resource:///modules/TorConnectParent.jsm", + }, + child: { + moduleURI: "resource:///modules/TorConnectChild.jsm", + events: { + DOMWindowCreated: {}, + }, + }, + + matches: ["about:torconnect","about:torconnect?*"], + }, + Translation: { parent: { moduleURI: "resource:///modules/translation/TranslationParent.jsm", diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index 6d283fe67b20..21f673f601d2 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -122,6 +122,10 @@ static const RedirEntry kRedirMap[] = { nsIAboutModule::HIDE_FROM_ABOUTABOUT}, {"restartrequired", "chrome://browser/content/aboutRestartRequired.xhtml", nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, + {"torconnect", "chrome://browser/content/torconnect/aboutTorConnect.xhtml", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | + nsIAboutModule::HIDE_FROM_ABOUTABOUT}, }; static nsAutoCString GetAboutModuleName(nsIURI* aURI) { diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf index 8ce22e9cff51..733abef1a80f 100644 --- a/browser/components/about/components.conf +++ b/browser/components/about/components.conf @@ -26,6 +26,7 @@ pages = [ 'robots', 'sessionrestore', 'tabcrashed', + 'torconnect', 'welcome', 'welcomeback', ] diff --git a/browser/components/moz.build b/browser/components/moz.build index 66de87290bd8..d15ff3051593 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -53,6 +53,7 @@ DIRS += [ "syncedtabs", "uitour", "urlbar", + "torconnect", "torpreferences", "translation", ] diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index 2150c424d8b8..ddeb92378432 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -186,6 +186,10 @@ ChromeUtils.defineModuleGetter( "resource://gre/modules/sessionstore/SessionHistory.jsm" ); +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + XPCOMUtils.defineLazyServiceGetters(this, { gScreenManager: ["@mozilla.org/gfx/screenmanager;1", "nsIScreenManager"], }); diff --git a/browser/components/torconnect/TorConnectChild.jsm b/browser/components/torconnect/TorConnectChild.jsm new file mode 100644 index 000000000000..bd6dd549f156 --- /dev/null +++ b/browser/components/torconnect/TorConnectChild.jsm @@ -0,0 +1,9 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +var EXPORTED_SYMBOLS = ["TorConnectChild"]; + +const { RemotePageChild } = ChromeUtils.import( + "resource://gre/actors/RemotePageChild.jsm" +); + +class TorConnectChild extends RemotePageChild {} diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm new file mode 100644 index 000000000000..2fbc2a5c7c7c --- /dev/null +++ b/browser/components/torconnect/TorConnectParent.jsm @@ -0,0 +1,147 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +var EXPORTED_SYMBOLS = ["TorConnectParent"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); +const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import( + "resource:///modules/TorConnect.jsm" +); +const { TorSettings, TorSettingsTopics, TorSettingsData } = ChromeUtils.import( + "resource:///modules/TorSettings.jsm" +); + +/* +This object is basically a marshalling interface between the TorConnect module +and a particular about:torconnect page +*/ + +class TorConnectParent extends JSWindowActorParent { + constructor(...args) { + super(...args); + + const self = this; + + this.state = { + State: TorConnect.state, + StateChanged: false, + ErrorMessage: TorConnect.errorMessage, + ErrorDetails: TorConnect.errorDetails, + BootstrapProgress: TorConnect.bootstrapProgress, + BootstrapStatus: TorConnect.bootstrapStatus, + ShowCopyLog: TorConnect.logHasWarningOrError, + QuickStartEnabled: TorSettings.quickstart.enabled, + }; + + // JSWindowActiveParent derived objects cannot observe directly, so create a member + // object to do our observing for us + // + // This object converts the various lifecycle events from the TorConnect module, and + // maintains a state object which we pass down to our about:torconnect page, which uses + // the state object to update its UI + this.torConnectObserver = { + observe(aSubject, aTopic, aData) { + let obj = aSubject?.wrappedJSObject; + + // update our state struct based on received torconnect topics and forward on + // to aboutTorConnect.js + self.state.StateChanged = false; + switch(aTopic) { + case TorConnectTopics.StateChange: { + self.state.State = obj.state; + self.state.StateChanged = true; + // clear any previous error information if we are bootstrapping + if (self.state.State === TorConnectState.Bootstrapping) { + self.state.ErrorMessage = null; + self.state.ErrorDetails = null; + } + break; + } + case TorConnectTopics.BootstrapProgress: { + self.state.BootstrapProgress = obj.progress; + self.state.BootstrapStatus = obj.status; + self.state.ShowCopyLog = obj.hasWarnings; + break; + } + case TorConnectTopics.BootstrapComplete: { + // noop + break; + } + case TorConnectTopics.BootstrapError: { + self.state.ErrorMessage = obj.message; + self.state.ErrorDetails = obj.details; + self.state.ShowCopyLog = true; + break; + } + case TorConnectTopics.FatalError: { + // TODO: handle + break; + } + case TorSettingsTopics.SettingChanged:{ + if (aData === TorSettingsData.QuickStartEnabled) { + self.state.QuickStartEnabled = obj.value; + } else { + // this isn't a setting torconnect cares about + return; + } + break; + } + default: { + console.log(`TorConnect: unhandled observe topic '${aTopic}'`); + } + } + + self.sendAsyncMessage("torconnect:state-change", self.state); + }, + }; + + // observe all of the torconnect:.* topics + for (const key in TorConnectTopics) { + const topic = TorConnectTopics[key]; + Services.obs.addObserver(this.torConnectObserver, topic); + } + Services.obs.addObserver(this.torConnectObserver, TorSettingsTopics.SettingChanged); + } + + willDestroy() { + // stop observing all of our torconnect:.* topics + for (const key in TorConnectTopics) { + const topic = TorConnectTopics[key]; + Services.obs.removeObserver(this.torConnectObserver, topic); + } + Services.obs.removeObserver(this.torConnectObserver, TorSettingsTopics.SettingChanged); + } + + receiveMessage(message) { + switch (message.name) { + case "torconnect:set-quickstart": + TorSettings.quickstart.enabled = message.data; + TorSettings.saveToPrefs().applySettings(); + break; + case "torconnect:open-tor-preferences": + TorConnect.openTorPreferences(); + break; + case "torconnect:copy-tor-logs": + return TorConnect.copyTorLogs(); + case "torconnect:cancel-bootstrap": + TorConnect.cancelBootstrap(); + break; + case "torconnect:begin-bootstrap": + TorConnect.beginBootstrap(); + break; + case "torconnect:get-init-args": + // called on AboutTorConnect.init(), pass down all state data it needs to init + + // pretend this is a state transition on init + // so we always get fresh UI + this.state.StateChanged = true; + return { + TorStrings: TorStrings, + TorConnectState: TorConnectState, + Direction: Services.locale.isAppLocaleRTL ? "rtl" : "ltr", + State: this.state, + }; + } + return undefined; + } +} diff --git a/browser/components/torconnect/content/aboutTorConnect.css b/browser/components/torconnect/content/aboutTorConnect.css new file mode 100644 index 000000000000..14a3df2a59be --- /dev/null +++ b/browser/components/torconnect/content/aboutTorConnect.css @@ -0,0 +1,180 @@ + +/* Copyright (c) 2021, The Tor Project, Inc. */ + +@import url("chrome://browser/skin/error-pages.css"); +@import url("chrome://branding/content/tor-styles.css"); + +:root { + --onion-opacity: 1; + --onion-color: var(--card-outline-color); + --onion-radius: 75px; +} + +/* override firefox's default blue focus coloring */ +:focus { + outline: none!important; + box-shadow: 0 0 0 3px var(--purple-30) !important; + border: 1px var(--purple-80) solid !important; +} + +@media (prefers-color-scheme: dark) +{ + :focus { + box-shadow: 0 0 0 3px var(--purple-50)!important; + } +} + +#connectButton { + background-color: var(--purple-60)!important; + color: white; + fill: white; +} + +#connectButton:hover { + background-color: var(--purple-70)!important; + color: white; + fill: white; +} + +#connectButton:active { + background-color: var(--purple-80)!important; + color: white; + fill: white; +} + +/* checkbox css */ +input[type="checkbox"]:not(:disabled) { + background-color: var(--grey-20)!important; +} + +input[type="checkbox"]:not(:disabled):checked { + background-color: var(--purple-60)!important; + color: white; + fill: white; +} + +input[type="checkbox"]:not(:disabled):hover { + /* override firefox's default blue border on hover */ + border-color: var(--purple-70); + background-color: var(--grey-30)!important; +} + +input[type="checkbox"]:not(:disabled):hover:checked { + background-color: var(--purple-70)!important; +} + +input[type="checkbox"]:not(:disabled):active { + background-color: var(--grey-40)!important; +} + +input[type="checkbox"]:not(:disabled):active:checked { + background-color: var(--purple-80)!important; +} + +#progressBackground { + position:fixed; + padding:0; + margin:0; + top:0; + left:0; + width: 0%; + height: 7px; + background-image: linear-gradient(90deg, rgb(20, 218, 221) 0%, rgb(128, 109, 236) 100%); + border-radius: 0; +} + +#connectPageContainer { + margin-top: 10vh; + width: 50%; +} + +#quickstartCheckbox, #quickstartCheckboxLabel { + vertical-align: middle; +} + +#copyLogButton { + position: relative; +} + +/* mirrors p element spacing */ +#copyLogContainer { + margin: 1em 0; + height: 1.2em; + min-height: 1.2em; +} + +#copyLogLink { + position: relative; + display: inline-block; + color: var(--in-content-link-color); +} + +/* hidden apparently only works if no display is set; who knew? */ +#copyLogLink[hidden="true"] { + display: none; +} + +#copyLogLink:hover { + cursor:pointer; +} + +/* This div: + - is centered over its parent + - centers its child + - has z-index above parent + - ignores mouse events from parent +*/ +#copyLogTooltip { + pointer-events: none; + visibility: hidden; + display: flex; + justify-content: center; + white-space: nowrap; + width: 0; + position: absolute; + + z-index: 1; + left: 50%; + bottom: calc(100% + 0.25em); +} + +/* tooltip content (any content could go here) */ +#copyLogTooltipText { + background-color: var(--green-50); + color: var(--green-90); + border-radius: 2px; + padding: 4px; + line-height: 13px; + font: 11px sans-serif; + font-weight: 400; +} + +/* our speech bubble tail */ +#copyLogTooltipText::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -4px; + border-width: 4px; + border-style: solid; + border-color: var(--green-50) transparent transparent transparent; +} + +body { + padding: 0px !important; + justify-content: space-between; + background-color: var(--in-content-page-background); +} + +.title { + background-image: url("chrome://browser/content/torconnect/onion.svg"); + -moz-context-properties: fill, fill-opacity; + fill-opacity: var(--onion-opacity); + fill: var(--onion-color); +} + +.title.error { + background-image: url("chrome://browser/content/torconnect/onion-slash.svg"); +} + diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js new file mode 100644 index 000000000000..26b17afb6938 --- /dev/null +++ b/browser/components/torconnect/content/aboutTorConnect.js @@ -0,0 +1,298 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +/* eslint-env mozilla/frame-script */ + +// populated in AboutTorConnect.init() +let TorStrings = {}; +let TorConnectState = {}; + +class AboutTorConnect { + selectors = Object.freeze({ + textContainer: { + title: "div.title", + titleText: "h1.title-text", + }, + progress: { + description: "p#connectShortDescText", + meter: "div#progressBackground", + }, + copyLog: { + link: "span#copyLogLink", + tooltip: "div#copyLogTooltip", + tooltipText: "span#copyLogTooltipText", + }, + quickstart: { + checkbox: "input#quickstartCheckbox", + label: "label#quickstartCheckboxLabel", + }, + buttons: { + connect: "button#connectButton", + cancel: "button#cancelButton", + advanced: "button#advancedButton", + }, + }) + + elements = Object.freeze({ + title: document.querySelector(this.selectors.textContainer.title), + titleText: document.querySelector(this.selectors.textContainer.titleText), + progressDescription: document.querySelector(this.selectors.progress.description), + progressMeter: document.querySelector(this.selectors.progress.meter), + copyLogLink: document.querySelector(this.selectors.copyLog.link), + copyLogTooltip: document.querySelector(this.selectors.copyLog.tooltip), + copyLogTooltipText: document.querySelector(this.selectors.copyLog.tooltipText), + quickstartCheckbox: document.querySelector(this.selectors.quickstart.checkbox), + quickstartLabel: document.querySelector(this.selectors.quickstart.label), + connectButton: document.querySelector(this.selectors.buttons.connect), + cancelButton: document.querySelector(this.selectors.buttons.cancel), + advancedButton: document.querySelector(this.selectors.buttons.advanced), + }) + + // a redirect url can be passed as a query parameter for the page to + // forward us to once bootstrap completes (otherwise the window will just close) + redirect = null + + beginBootstrap() { + this.hide(this.elements.connectButton); + this.show(this.elements.cancelButton); + this.elements.cancelButton.focus(); + RPMSendAsyncMessage("torconnect:begin-bootstrap"); + } + + cancelBootstrap() { + RPMSendAsyncMessage("torconnect:cancel-bootstrap"); + } + + /* + Element helper methods + */ + + show(element) { + element.removeAttribute("hidden"); + } + + hide(element) { + element.setAttribute("hidden", "true"); + } + + setTitle(title, error) { + this.elements.titleText.textContent = title; + document.title = title; + + if (error) { + this.elements.title.classList.add("error"); + } else { + this.elements.title.classList.remove("error"); + } + } + + setProgress(description, visible, percent) { + this.elements.progressDescription.textContent = description; + if (visible) { + this.show(this.elements.progressMeter); + this.elements.progressMeter.style.width = `${percent}%`; + } else { + this.hide(this.elements.progressMeter); + } + } + + /* + These methods update the UI based on the current TorConnect state + */ + + updateUI(state) { + console.log(state); + + // calls update_$state() + this[`update_${state.State}`](state); + this.elements.quickstartCheckbox.checked = state.QuickStartEnabled; + } + + /* Per-state updates */ + + update_Initial(state) { + const hasError = false; + const showProgressbar = false; + + this.setTitle(TorStrings.torConnect.torConnect, hasError); + this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar); + this.hide(this.elements.copyLogLink); + this.hide(this.elements.connectButton); + this.hide(this.elements.advancedButton); + this.hide(this.elements.cancelButton); + } + + update_Configuring(state) { + const hasError = state.ErrorMessage != null; + const showProgressbar = false; + + if (hasError) { + this.setTitle(state.ErrorMessage, hasError); + this.setProgress(state.ErrorDetails, showProgressbar); + this.show(this.elements.copyLogLink); + this.elements.connectButton.textContent = TorStrings.torConnect.tryAgain; + } else { + this.setTitle(TorStrings.torConnect.torConnect, hasError); + this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar); + this.hide(this.elements.copyLogLink); + this.elements.connectButton.textContent = TorStrings.torConnect.torConnectButton; + } + this.show(this.elements.connectButton); + if (state.StateChanged) { + this.elements.connectButton.focus(); + } + this.show(this.elements.advancedButton); + this.hide(this.elements.cancelButton); + } + + update_AutoBootstrapping(state) { + // TODO: noop until this state is used + } + + update_Bootstrapping(state) { + const hasError = false; + const showProgressbar = true; + + this.setTitle(state.BootstrapStatus ? state.BootstrapStatus : TorStrings.torConnect.torConnecting, hasError); + this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar, state.BootstrapProgress); + if (state.ShowCopyLog) { + this.show(this.elements.copyLogLink); + } else { + this.hide(this.elements.copyLogLink); + } + this.hide(this.elements.connectButton); + this.hide(this.elements.advancedButton); + this.show(this.elements.cancelButton); + if (state.StateChanged) { + this.elements.cancelButton.focus(); + } + } + + update_Error(state) { + const hasError = true; + const showProgressbar = false; + + this.setTitle(state.ErrorMessage, hasError); + this.setProgress(state.ErrorDetails, showProgressbar); + this.show(this.elements.copyLogLink); + this.elements.connectButton.textContent = TorStrings.torConnect.tryAgain; + this.show(this.elements.connectButton); + this.show(this.elements.advancedButton); + this.hide(this.elements.cancelButton); + } + + update_Bootstrapped(state) { + const hasError = false; + const showProgressbar = true; + + this.setTitle(TorStrings.torConnect.torConnected, hasError); + this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar, 100); + this.hide(this.elements.connectButton); + this.hide(this.elements.advancedButton); + this.hide(this.elements.cancelButton); + + // redirects page to the requested redirect url, removes about:torconnect + // from the page stack, so users cannot accidentally go 'back' to the + // now unresponsive page + window.location.replace(this.redirect); + } + + update_Disabled(state) { + // TODO: we should probably have some UX here if a user goes to about:torconnect when + // it isn't in use (eg using tor-launcher or system tor) + } + + async initElements(direction) { + + document.documentElement.setAttribute("dir", direction); + + // sets the text content while keeping the child elements intact + this.elements.copyLogLink.childNodes[0].nodeValue = + TorStrings.torConnect.copyLog; + this.elements.copyLogLink.addEventListener("click", async (event) => { + const copiedMessage = await RPMSendQuery("torconnect:copy-tor-logs"); + this.elements.copyLogTooltipText.textContent = copiedMessage; + this.elements.copyLogTooltipText.style.visibility = "visible"; + + // clear previous timeout if one already exists + if (this.copyLogTimeoutId) { + clearTimeout(this.copyLogTimeoutId); + } + + // hide tooltip after X ms + const TOOLTIP_TIMEOUT = 2000; + this.copyLogTimeoutId = setTimeout(() => { + this.elements.copyLogTooltipText.style.visibility = "hidden"; + this.copyLogTimeoutId = 0; + }, TOOLTIP_TIMEOUT); + }); + + this.elements.quickstartCheckbox.addEventListener("change", () => { + const quickstart = this.elements.quickstartCheckbox.checked; + RPMSendAsyncMessage("torconnect:set-quickstart", quickstart); + }); + this.elements.quickstartLabel.textContent = TorStrings.settings.quickstartCheckbox; + + this.elements.connectButton.textContent = + TorStrings.torConnect.torConnectButton; + this.elements.connectButton.addEventListener("click", () => { + this.beginBootstrap(); + }); + + this.elements.advancedButton.textContent = TorStrings.torConnect.torConfigure; + this.elements.advancedButton.addEventListener("click", () => { + RPMSendAsyncMessage("torconnect:open-tor-preferences"); + }); + + this.elements.cancelButton.textContent = TorStrings.torConnect.cancel; + this.elements.cancelButton.addEventListener("click", () => { + this.cancelBootstrap(); + }); + } + + initObservers() { + // TorConnectParent feeds us state blobs to we use to update our UI + RPMAddMessageListener("torconnect:state-change", ({ data }) => { + this.updateUI(data); + }); + } + + initKeyboardShortcuts() { + document.onkeydown = (evt) => { + // unfortunately it looks like we still haven't standardized keycodes to + // integers, so we must resort to a string compare here :( + // see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code for relevant documentation + if (evt.code === "Escape") { + this.cancelBootstrap(); + } + }; + } + + async init() { + // see if a user has a final destination after bootstrapping + let params = new URLSearchParams(new URL(document.location.href).search); + if (params.has("redirect")) { + const encodedRedirect = params.get("redirect"); + this.redirect = decodeURIComponent(encodedRedirect); + } else { + // if the user gets here manually or via the button in the urlbar + // then we will redirect to about:tor + this.redirect = "about:tor"; + } + + let args = await RPMSendQuery("torconnect:get-init-args"); + + // various constants + TorStrings = Object.freeze(args.TorStrings); + TorConnectState = Object.freeze(args.TorConnectState); + + this.initElements(args.Direction); + this.initObservers(); + this.initKeyboardShortcuts(); + + // populate UI based on current state + this.updateUI(args.State); + } +} + +const aboutTorConnect = new AboutTorConnect(); +aboutTorConnect.init(); diff --git a/browser/components/torconnect/content/aboutTorConnect.xhtml b/browser/components/torconnect/content/aboutTorConnect.xhtml new file mode 100644 index 000000000000..595bbdf9a70a --- /dev/null +++ b/browser/components/torconnect/content/aboutTorConnect.xhtml @@ -0,0 +1,45 @@ +<!-- Copyright (c) 2021, The Tor Project, Inc. --> +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'" /> + <link rel="stylesheet" href="chrome://browser/skin/onionPattern.css" type="text/css" media="all" /> + <link rel="stylesheet" href="chrome://browser/content/torconnect/aboutTorConnect.css" type="text/css" media="all" /> + </head> + <body> + <div id="progressBackground"></div> + <div id="connectPageContainer" class="container"> + <div id="text-container"> + <div class="title"> + <h1 class="title-text"/> + </div> + <div id="connectLongContent"> + <div id="connectShortDesc"> + <p id="connectShortDescText" /> + </div> + </div> + + <div id="copyLogContainer"> + <span id="copyLogLink" hidden="true"> + <div id="copyLogTooltip"> + <span id="copyLogTooltipText"/> + </div> + </span> + </div> + + <div id="quickstartContainer"> + <input id="quickstartCheckbox" type="checkbox" /> + <label id="quickstartCheckboxLabel" for="quickstartCheckbox"/> + </div> + + <div id="connectButtonContainer" class="button-container"> + <button id="advancedButton" hidden="true"></button> + <button id="cancelButton" hidden="true"></button> + <button id="connectButton" class="primary try-again" hidden="true"></button> + </div> + </div> + </div> +#include ../../../themes/shared/onionPattern.inc.xhtml + </body> + <script src="chrome://browser/content/torconnect/aboutTorConnect.js"/> +</html> diff --git a/browser/components/torconnect/content/onion-slash.svg b/browser/components/torconnect/content/onion-slash.svg new file mode 100644 index 000000000000..93eb24b03905 --- /dev/null +++ b/browser/components/torconnect/content/onion-slash.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg viewBox="0 0 16 16" width="16" height="16" xmlns="http://www.w3.org/2000/svg"> + <path d="m14.1161 15.6245c-.0821.0001-.1634-.016-.2393-.0474-.0758-.0314-.1447-.0775-.2027-.1356l-12.749984-12.749c-.109266-.11882-.168406-.27526-.165071-.43666.003335-.16139.068886-.31525.182967-.42946.114078-.11421.267868-.17994.429258-.18345.16139-.00352.3179.05544.43685.16457l12.74998 12.75c.1168.1176.1824.2767.1824.4425s-.0656.3249-.1824.4425c-.058.058-.1269.1039-.2028.1352-.0759.0312-.1571.0471-.2392.0468z" fill-opacity="context-fill-opacity" fill="#ff0039" /> + <path d="m 8,0.5000002 c -1.61963,0 -3.1197431,0.5137987 -4.3457031,1.3867188 l 0.84375,0.8417968 0.7792969,0.78125 0.8613281,0.8613282 0.8164062,0.8164062 0.9863281,0.984375 h 0.058594 c 1.00965,0 1.828125,0.818485 1.828125,1.828125 0,0.01968 6.2e-4,0.039074 0,0.058594 L 10.8125,9.0449221 C 10.9334,8.7195921 11,8.3674002 11,8.0000002 c 0,-1.65685 -1.34314,-3 -3,-3 v -1.078125 c 2.25231,0 4.078125,1.825845 4.078125,4.078125 0,0.67051 -0.162519,1.3033281 -0.449219,1.8613281 l 0.861328,0.8613277 C 12.972434,9.9290067 13.25,8.9965102 13.25,8.0000002 c 0,-2.89949 -2.35049,-5.25 -5.25,-5.25 v -1.078125 c 3.4949,0 6.328125,2.833195 6.328125,6.328125 0,1.29533 -0.388841,2.4990528 -1.056641,3.5019528 l 0.841797,0.84375 C 14.986181,11.119703 15.5,9.6196302 15.5,8.0000002 c 0,-4.14214 -3.3579,-7.5 -7.5,-7.5 z m -6.1113281,3.15625 C 1.0154872,4.8821451 0.5,6.3803304 0.5,8.0000002 0.5,12.1421 3.85786,15.5 8,15.5 c 1.6198027,0 3.117896,-0.515441 4.34375,-1.388672 L 11.501953,13.269531 C 10.498 787,13.937828 9.295838,14.328125 8,14.328125 V 13.25 c 0.9967306,0 1.9287093,-0.277621 2.722656,-0.759766 L 9.859375,11.626953 C 9.3016226,11.913918 8.6705338,12.078125 8,12.078125 V 11 C 8.3664751,11 8.716425,10.93088 9.0410156,10.810547 6.6639891,8.4300416 4.2743195,6.0418993 1.8886719,3.6562502 Z" fill-opacity="context-fill-opacity" fill="context-fill"/> +</svg> diff --git a/browser/components/torconnect/content/onion.svg b/browser/components/torconnect/content/onion.svg new file mode 100644 index 000000000000..7655a800d9ee --- /dev/null +++ b/browser/components/torconnect/content/onion.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg viewBox="0 0 16 16" width="16" height="16" xmlns="http://www.w3.org/2000/svg"> + <path d="M 8 0.5 C 3.85786 0.5 0.5 3.85786 0.5 8 C 0.5 12.1421 3.85786 15.5 8 15.5 C 12.1421 15.5 15.5 12.1421 15.5 8 C 15.5 3.85786 12.1421 0.5 8 0.5 z M 8 1.671875 C 11.4949 1.671875 14.328125 4.50507 14.328125 8 C 14.328125 11.4949 11.4949 14.328125 8 14.328125 L 8 13.25 C 10.89951 13.25 13.25 10.89951 13.25 8 C 13.25 5.10051 10.89951 2.75 8 2.75 L 8 1.671875 z M 8 3.921875 C 10.25231 3.921875 12.078125 5.74772 12.078125 8 C 12.078125 10.25231 10.25231 12.078125 8 12.078125 L 8 11 C 9.65686 11 11 9.65686 11 8 C 11 6.34315 9.65686 5 8 5 L 8 3.921875 z M 8 6.171875 C 9.00965 6.171875 9.828125 6.99036 9.828125 8 C 9.828125 9.00965 9.00965 9.828125 8 9.828125 L 8 6.171875 z " clip-rule="evenodd" fill-rule="evenodd" fill="context-fill" fill-opacity="context-fill-opacity"/> +</svg> diff --git a/browser/components/torconnect/content/torBootstrapUrlbar.js b/browser/components/torconnect/content/torBootstrapUrlbar.js new file mode 100644 index 000000000000..e6a88490f33d --- /dev/null +++ b/browser/components/torconnect/content/torBootstrapUrlbar.js @@ -0,0 +1,93 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +"use strict"; + +const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import( + "resource:///modules/TorConnect.jsm" +); +const { TorStrings } = ChromeUtils.import( + "resource:///modules/TorStrings.jsm" +); + +var TorBootstrapUrlbar = { + selectors: Object.freeze({ + torConnect: { + box: "hbox#torconnect-box", + label: "label#torconnect-label", + }, + }), + + elements: null, + + updateTorConnectBox: function(state) { + switch(state) + { + case TorConnectState.Initial: + case TorConnectState.Configuring: + case TorConnectState.AutoConfiguring: + case TorConnectState.Error: + case TorConnectState.FatalError: { + this.elements.torConnectBox.removeAttribute("hidden"); + this.elements.torConnectLabel.textContent = + TorStrings.torConnect.torNotConnectedConcise; + this.elements.inputContainer.setAttribute("torconnect", "offline"); + break; + } + case TorConnectState.Bootstrapping: { + this.elements.torConnectBox.removeAttribute("hidden"); + this.elements.torConnectLabel.textContent = + TorStrings.torConnect.torConnectingConcise; + this.elements.inputContainer.setAttribute("torconnect", "connecting"); + break; + } + case TorConnectState.Bootstrapped: { + this.elements.torConnectBox.removeAttribute("hidden"); + this.elements.torConnectLabel.textContent = + TorStrings.torConnect.torConnectedConcise; + this.elements.inputContainer.setAttribute("torconnect", "connected"); + // hide torconnect box after 5 seconds + setTimeout(() => { + this.elements.torConnectBox.setAttribute("hidden", "true"); + }, 5000); + break; + } + case TorConnectState.Disabled: { + this.elements.torConnectBox.setAttribute("hidden", "true"); + break; + } + default: + break; + } + }, + + observe: function(aSubject, aTopic, aData) { + if (aTopic === TorConnectTopics.StateChange) { + const obj = aSubject?.wrappedJSObject; + this.updateTorConnectBox(obj?.state); + } + }, + + init: function() { + if (TorConnect.shouldShowTorConnect) { + // browser isn't populated until init + this.elements = Object.freeze({ + torConnectBox: browser.ownerGlobal.document.querySelector(this.selectors.torConnect.box), + torConnectLabel: browser.ownerGlobal.document.querySelector(this.selectors.torConnect.label), + inputContainer: gURLBar._inputContainer, + }) + this.elements.torConnectBox.addEventListener("click", () => { + TorConnect.openTorConnect(); + }); + Services.obs.addObserver(this, TorConnectTopics.StateChange); + this.observing = true; + this.updateTorConnectBox(TorConnect.state); + } + }, + + uninit: function() { + if (this.observing) { + Services.obs.removeObserver(this, TorConnectTopics.StateChange); + } + }, +}; + diff --git a/browser/components/torconnect/content/torconnect-urlbar.css b/browser/components/torconnect/content/torconnect-urlbar.css new file mode 100644 index 000000000000..5aabcffedbd0 --- /dev/null +++ b/browser/components/torconnect/content/torconnect-urlbar.css @@ -0,0 +1,57 @@ +/* + ensure our torconnect button is always visible (same rule as for the bookmark button) +*/ +hbox.urlbar-page-action#torconnect-box { + display: -moz-inline-box!important; + height: 28px; +} + +label#torconnect-label { + line-height: 28px; + margin: 0; + opacity: 0.6; + padding: 0 0.5em; +} + +/* set appropriate sizes for the non-standard ui densities */ +:root[uidensity=compact] hbox.urlbar-page-action#torconnect-box { + height: 24px; +} +:root[uidensity=compact] label#torconnect-label { + line-height: 24px; +} + + +:root[uidensity=touch] hbox.urlbar-page-action#torconnect-box { + height: 30px; +} +:root[uidensity=touch] label#torconnect-label { + line-height: 30px; +} + + +/* hide when hidden attribute is set */ +hbox.urlbar-page-action#torconnect-box[hidden="true"], +/* hide when user is typing in URL bar */ +#urlbar[usertyping] > #urlbar-input-container > #page-action-buttons > #torconnect-box { + display: none!important; +} + +/* hide urlbar's placeholder text when not connectd to tor */ +hbox#urlbar-input-container[torconnect="offline"] input#urlbar-input::placeholder, +hbox#urlbar-input-container[torconnect="connecting"] input#urlbar-input::placeholder { + opacity: 0; +} + +/* hide search suggestions when not connected to tor */ +hbox#urlbar-input-container[torconnect="offline"] + vbox.urlbarView, +hbox#urlbar-input-container[torconnect="connecting"] + vbox.urlbarView { + display: none!important; +} + +/* hide search icon when we are not connected to tor */ +hbox#urlbar-input-container[torconnect="offline"] > #identity-box[pageproxystate="invalid"] > #identity-icon, +hbox#urlbar-input-container[torconnect="connecting"] > #identity-box[pageproxystate="invalid"] > #identity-icon +{ + display: none!important; +} diff --git a/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml new file mode 100644 index 000000000000..60e985a72691 --- /dev/null +++ b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml @@ -0,0 +1,10 @@ +# Copyright (c) 2021, The Tor Project, Inc. + +<hbox id="torconnect-box" + class="urlbar-icon-wrapper urlbar-page-action" + role="status" + hidden="true"> + <hbox id="torconnect-container"> + <label id="torconnect-label"/> + </hbox> +</hbox> \ No newline at end of file diff --git a/browser/components/torconnect/jar.mn b/browser/components/torconnect/jar.mn new file mode 100644 index 000000000000..ed8a4de299b2 --- /dev/null +++ b/browser/components/torconnect/jar.mn @@ -0,0 +1,7 @@ +browser.jar: + content/browser/torconnect/torBootstrapUrlbar.js (content/torBootstrapUrlbar.js) + content/browser/torconnect/aboutTorConnect.css (content/aboutTorConnect.css) +* content/browser/torconnect/aboutTorConnect.xhtml (content/aboutTorConnect.xhtml) + content/browser/torconnect/aboutTorConnect.js (content/aboutTorConnect.js) + content/browser/torconnect/onion.svg (content/onion.svg) + content/browser/torconnect/onion-slash.svg (content/onion-slash.svg) diff --git a/browser/components/torconnect/moz.build b/browser/components/torconnect/moz.build new file mode 100644 index 000000000000..eb29c31a4243 --- /dev/null +++ b/browser/components/torconnect/moz.build @@ -0,0 +1,6 @@ +JAR_MANIFESTS += ['jar.mn'] + +EXTRA_JS_MODULES += [ + 'TorConnectChild.jsm', + 'TorConnectParent.jsm', +] diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm index 4e1ccac6bd17..c62edbe9a907 100644 --- a/browser/components/urlbar/UrlbarInput.jsm +++ b/browser/components/urlbar/UrlbarInput.jsm @@ -10,6 +10,34 @@ const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); +const { TorConnect } = ChromeUtils.import( + "resource:///modules/TorConnect.jsm" +); + +// in certain scenarios we want user input uris to open in a new tab if they do so from the +// about:torconnect tab +function maybeUpdateOpenLocationForTorConnect(openUILinkWhere, currentURI, destinationURI) { + try { + // only open in new tab if: + if (// user is navigating away from about:torconnect + currentURI === "about:torconnect" && + // we are trying to open in same tab + openUILinkWhere === "current" && + // only if user still has not bootstrapped + TorConnect.shouldShowTorConnect && + // and user is not just navigating to about:torconnect + destinationURI !== "about:torconnect") { + return "tab"; + } + } catch (e) { + // swallow exception and fall through returning original so we don't accidentally break + // anything if an exception is thrown + console.log(e?.message ? e.message : e); + } + + return openUILinkWhere; +}; + XPCOMUtils.defineLazyModuleGetters(this, { AppConstants: "resource://gre/modules/AppConstants.jsm", BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm", @@ -2407,6 +2435,10 @@ class UrlbarInput { this.selectionStart = this.selectionEnd = 0; } + openUILinkWhere = maybeUpdateOpenLocationForTorConnect( + openUILinkWhere, + this.window.gBrowser.currentURI.asciiSpec, + url); if (openUILinkWhere != "current") { this.handleRevert(); } diff --git a/browser/modules/TorProcessService.jsm b/browser/modules/TorProcessService.jsm new file mode 100644 index 000000000000..201e331b2806 --- /dev/null +++ b/browser/modules/TorProcessService.jsm @@ -0,0 +1,12 @@ +"use strict"; + +var EXPORTED_SYMBOLS = ["TorProcessService"]; + +var TorProcessService = { + get isBootstrapDone() { + const svc = Cc["@torproject.org/torlauncher-process-service;1"].getService( + Ci.nsISupports + ).wrappedJSObject; + return svc.mIsBootstrapDone; + }, +}; diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm index 1e08b168e4af..96d3de8186e2 100644 --- a/browser/modules/TorStrings.jsm +++ b/browser/modules/TorStrings.jsm @@ -257,6 +257,9 @@ var TorStrings = { "Tor Browser routes your traffic over the Tor Network, run by thousands of volunteers around the world." ), learnMore: getString("torPreferences.learnMore", "Learn More"), + quickstartHeading: getString("torPreferences.quickstart", "Quickstart"), + quickstartDescription: getString("torPreferences.quickstartDescription", "Quickstart allows Tor Browser to connect automatically."), + quickstartCheckbox : getString("torPreferences.quickstartCheckbox", "Always connect automatically"), bridgesHeading: getString("torPreferences.bridges", "Bridges"), bridgesDescription: getString( "torPreferences.bridgesDescription", @@ -364,6 +367,83 @@ var TorStrings = { return retval; })() /* Tor Network Settings Strings */, + torConnect: (() => { + const tsbNetwork = new TorDTDStringBundle( + ["chrome://torlauncher/locale/network-settings.dtd"], + "" + ); + const tsbLauncher = new TorPropertyStringBundle( + "chrome://torlauncher/locale/torlauncher.properties", + "torlauncher." + ); + const tsbCommon = new TorPropertyStringBundle( + "chrome://global/locale/commonDialogs.properties", + "" + ); + + const getStringNet = tsbNetwork.getString.bind(tsbNetwork); + const getStringLauncher = tsbLauncher.getString.bind(tsbLauncher); + const getStringCommon = tsbCommon.getString.bind(tsbCommon); + + return { + torConnect: getStringNet( + "torsettings.wizard.title.default", + "Connect to Tor" + ), + + torConnecting: getStringNet( + "torsettings.wizard.title.connecting", + "Establishing a Connection" + ), + + torNotConnectedConcise: getStringNet( + "torConnect.notConnectedConcise", + "Not Connected" + ), + + torConnectingConcise: getStringNet( + "torConnect.connectingConcise", + "Connecting…" + ), + + torBootstrapFailed: getStringLauncher( + "tor_bootstrap_failed", + "Tor failed to establish a Tor network connection." + ), + + torConfigure: getStringNet( + "torsettings.wizard.title.configure", + "Tor Network Settings" + ), + + copyLog: getStringNet( + "torConnect.copyLog", + "Copy Tor Logs" + ), + + torConnectButton: getStringNet("torSettings.connect", "Connect"), + + cancel: getStringCommon("Cancel", "Cancel"), + + torConnected: getStringLauncher( + "torlauncher.bootstrapStatus.done", + "Connected to the Tor network" + ), + + torConnectedConcise: getStringLauncher( + "torConnect.connectedConcise", + "Connected" + ), + + tryAgain: getStringNet("torConnect.tryAgain", "Try connecting again"), + offline: getStringNet("torConnect.offline", "Offline"), + + // tor connect strings for message box in about:preferences#tor + connectMessage: getStringNet("torConnect.connectMessage", "Changes to Tor Settings will not take effect until you connect"), + tryAgainMessage: getStringNet("torConnect.tryAgainMessage", "Tor Browser has failed to establish a connection to the Tor Network"), + }; + })(), + /* Tor Onion Services Strings, e.g., for the authentication prompt. */ diff --git a/browser/modules/moz.build b/browser/modules/moz.build index bc543283d887..a06914ccf8d9 100644 --- a/browser/modules/moz.build +++ b/browser/modules/moz.build @@ -154,6 +154,8 @@ EXTRA_JS_MODULES += [ "TabsList.jsm", "TabUnloader.jsm", "ThemeVariableMap.jsm", + 'TorConnect.jsm', + 'TorProcessService.jsm', "TorProtocolService.jsm", "TorSettings.jsm", "TorStrings.jsm", diff --git a/browser/themes/shared/urlbar-searchbar.inc.css b/browser/themes/shared/urlbar-searchbar.inc.css index 82675dae2041..f91278ce5ed3 100644 --- a/browser/themes/shared/urlbar-searchbar.inc.css +++ b/browser/themes/shared/urlbar-searchbar.inc.css @@ -745,3 +745,6 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after { .searchbar-textbox::placeholder { opacity: 0.69; } + +%include ../../components/torconnect/content/torconnect-urlbar.css + diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 0ef4b3236477..1e75ed7fe032 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -17099,9 +17099,56 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) { StylePrefersColorScheme Document::PrefersColorScheme( IgnoreRFP aIgnoreRFP) const { + + // tor-browser#27476 + // should this document ignore resist finger-printing settings with regards to + // setting the color scheme + // currently only enabled for about:torconnect but we could expand to other non- + // SystemPrincipal pages if we wish + const auto documentUsesPreferredColorScheme = [](auto const* constDocument) -> bool { + if (auto* document = const_cast<Document*>(constDocument); document != nullptr) { + auto uri = document->GetDocBaseURI(); + + // try and extract out our prepath and filepath portions of the uri to C-strings + nsAutoCString prePathStr, filePathStr; + if(NS_FAILED(uri->GetPrePath(prePathStr)) || + NS_FAILED(uri->GetFilePath(filePathStr))) { + return false; + } + + // stick them in string view for easy comparisons + std::string_view prePath(prePathStr.get(), prePathStr.Length()), + filePath(filePathStr.get(), filePathStr.Length()); + + // these about URIs will have the user's preferred color scheme exposed to them + // we can place other URIs here in the future if we wish + // see nsIURI.idl for URI part definitions + constexpr struct { + std::string_view prePath; + std::string_view filePath; + } allowedURIs[] = { + { "about:", "torconnect" }, + }; + + // check each uri in the allow list against this document's uri + // verify the prepath and the file path match + for(auto const& uri : allowedURIs) { + if (prePath == uri.prePath && + filePath == uri.filePath) { + // positive match means we can apply dark-mode to the page + return true; + } + } + } + + // do not allow if no match or other error + return false; + }; + if (aIgnoreRFP == IgnoreRFP::No && - nsContentUtils::ShouldResistFingerprinting(this)) { - return StylePrefersColorScheme::Light; + nsContentUtils::ShouldResistFingerprinting(this) && + !documentUsesPreferredColorScheme(this)) { + return StylePrefersColorScheme::Light; } if (auto* bc = GetBrowsingContext()) { diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 41c93c51cf3b..aab4a37e78a8 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -6212,6 +6212,8 @@ void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) { NS_ENSURE_SUCCESS_VOID(rv); if (!StringBeginsWith(url, u"about:neterror"_ns) && + // we want about:torconnect pages to be able to close themselves after bootstrap + !StringBeginsWith(url, u"about:torconnect"_ns) && !mBrowsingContext->HadOriginalOpener() && !aTrustedCaller && !IsOnlyTopLevelDocumentInSHistory()) { bool allowClose = diff --git a/toolkit/components/processsingleton/MainProcessSingleton.jsm b/toolkit/components/processsingleton/MainProcessSingleton.jsm index 7bde782e54ce..ba8cd0f3f97d 100644 --- a/toolkit/components/processsingleton/MainProcessSingleton.jsm +++ b/toolkit/components/processsingleton/MainProcessSingleton.jsm @@ -29,6 +29,11 @@ MainProcessSingleton.prototype = { null ); + ChromeUtils.import( + "resource:///modules/TorConnect.jsm", + null + ); + Services.ppmm.loadProcessScript( "chrome://global/content/process-content.js", true diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm index 50fb4ea8d417..486409ab5c8b 100644 --- a/toolkit/modules/RemotePageAccessManager.jsm +++ b/toolkit/modules/RemotePageAccessManager.jsm @@ -102,6 +102,7 @@ let RemotePageAccessManager = { RPMAddToHistogram: ["*"], RPMGetInnerMostURI: ["*"], RPMGetHttpResponseHeader: ["*"], + RPMSendQuery: ["ShouldShowTorConnect"], }, "about:plugins": { RPMSendQuery: ["RequestPlugins"], @@ -213,6 +214,21 @@ let RemotePageAccessManager = { RPMAddMessageListener: ["*"], RPMRemoveMessageListener: ["*"], }, + "about:torconnect": { + RPMAddMessageListener: [ + "torconnect:state-change", + ], + RPMSendAsyncMessage: [ + "torconnect:open-tor-preferences", + "torconnect:begin-bootstrap", + "torconnect:cancel-bootstrap", + "torconnect:set-quickstart", + ], + RPMSendQuery: [ + "torconnect:get-init-args", + "torconnect:copy-tor-logs", + ], + }, }, /** diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm index 4d1b1c59eff5..cd87b21b0ff9 100644 --- a/toolkit/mozapps/update/UpdateService.jsm +++ b/toolkit/mozapps/update/UpdateService.jsm @@ -12,6 +12,17 @@ const { AppConstants } = ChromeUtils.import( const { AUSTLMY } = ChromeUtils.import( "resource://gre/modules/UpdateTelemetry.jsm" ); + +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + +function _shouldRegisterBootstrapObserver(errorCode) { + return errorCode == PROXY_SERVER_CONNECTION_REFUSED && + !TorProtocolService.isBootstrapDone() && + TorProtocolService.ownsTorDaemon; +}; + const { Bits, BitsRequest, @@ -228,6 +239,7 @@ const SERVICE_ERRORS = [ // Custom update error codes const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110; const NETWORK_ERROR_OFFLINE = 111; +const PROXY_SERVER_CONNECTION_REFUSED = 2152398920; // Error codes should be < 1000. Errors above 1000 represent http status codes const HTTP_ERROR_OFFSET = 1000; @@ -2613,6 +2625,9 @@ UpdateService.prototype = { case "network:offline-status-changed": this._offlineStatusChanged(data); break; + case "torconnect:bootstrap-complete": + this._bootstrapComplete(); + break; case "nsPref:changed": if (data == PREF_APP_UPDATE_LOG || data == PREF_APP_UPDATE_LOG_FILE) { gLogEnabled; // Assigning this before it is lazy-loaded is an error. @@ -3063,6 +3078,35 @@ UpdateService.prototype = { this._attemptResume(); }, + _registerBootstrapObserver: function AUS__registerBootstrapObserver() { + if (this._registeredBootstrapObserver) { + LOG( + "UpdateService:_registerBootstrapObserver - observer already registered" + ); + return; + } + + LOG( + "UpdateService:_registerBootstrapObserver - waiting for tor bootstrap to " + + "be complete, then forcing another check" + ); + + Services.obs.addObserver(this, "torconnect:bootstrap-complete"); + this._registeredBootstrapObserver = true; + }, + + _bootstrapComplete: function AUS__bootstrapComplete() { + Services.obs.removeObserver(this, "torconnect:bootstrap-complete"); + this._registeredBootstrapObserver = false; + + LOG( + "UpdateService:_bootstrapComplete - bootstrapping complete, forcing " + + "another background check" + ); + + this._attemptResume(); + }, + onCheckComplete: function AUS_onCheckComplete(request, updates) { this._selectAndInstallUpdate(updates); }, @@ -3082,6 +3126,11 @@ UpdateService.prototype = { AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_OFFLINE); } return; + } else if (_shouldRegisterBootstrapObserver(update.errorCode)) { + // Register boostrap observer to try again, but only when we own the + // tor process. + this._registerBootstrapObserver(); + return; } // Send the error code to telemetry @@ -5843,6 +5892,7 @@ Downloader.prototype = { var state = this._patch.state; var shouldShowPrompt = false; var shouldRegisterOnlineObserver = false; + var shouldRegisterBootstrapObserver = false; var shouldRetrySoon = false; var deleteActiveUpdate = false; let migratedToReadyUpdate = false; @@ -5961,7 +6011,18 @@ Downloader.prototype = { ); shouldRegisterOnlineObserver = true; deleteActiveUpdate = false; - + } else if(_shouldRegisterBootstrapObserver(status)) { + // Register a bootstrap observer to try again. + // The bootstrap observer will continue the incremental download by + // calling downloadUpdate on the active update which continues + // downloading the file from where it was. + LOG("Downloader:onStopRequest - not bootstrapped, register bootstrap observer: true"); + AUSTLMY.pingDownloadCode( + this.isCompleteUpdate, + AUSTLMY.DWNLD_RETRY_OFFLINE + ); + shouldRegisterBootstrapObserver = true; + deleteActiveUpdate = false; // Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED, // NS_ERROR_NET_RESET and NS_ERROR_DOCUMENT_NOT_CACHED can be returned // when disconnecting the internet while a download of a MAR is in @@ -6083,7 +6144,7 @@ Downloader.prototype = { // Only notify listeners about the stopped state if we // aren't handling an internal retry. - if (!shouldRetrySoon && !shouldRegisterOnlineObserver) { + if (!shouldRetrySoon && !shouldRegisterOnlineObserver && !shouldRegisterBootstrapObserver) { this.updateService.forEachDownloadListener(listener => { listener.onStopRequest(request, status); }); @@ -6269,6 +6330,9 @@ Downloader.prototype = { if (shouldRegisterOnlineObserver) { LOG("Downloader:onStopRequest - Registering online observer"); this.updateService._registerOnlineObserver(); + } else if (shouldRegisterBootstrapObserver) { + LOG("Downloader:onStopRequest - Registering bootstrap observer"); + this.updateService._registerBootstrapObserver(); } else if (shouldRetrySoon) { LOG("Downloader:onStopRequest - Retrying soon"); this.updateService._consecutiveSocketErrors++; diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js index 2ff107b553b2..f8fa83574df7 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js @@ -70,6 +70,10 @@ function getGlobalScriptIncludes(scriptPath) { let match = line.match(globalScriptsRegExp); if (match) { let sourceFile = match[1] + .replace( + "chrome://browser/content/torconnect/", + "browser/components/torconnect/content/" + ) .replace( "chrome://browser/content/search/", "browser/components/search/content/"
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 40253: Explicitly allow NoScript in Private Browsing mode.
by richard@torproject.org 09 Feb '22

09 Feb '22
commit c288247de8d0b6660767696391e743bdaef1a0d8 Author: Matthew Finkel <sysrqb(a)torproject.org> Date: Fri Sep 3 14:58:28 2021 +0000 Bug 40253: Explicitly allow NoScript in Private Browsing mode. --- toolkit/components/extensions/Extension.jsm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm index 783ec7c3391d..1d72f88b276d 100644 --- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -2644,6 +2644,15 @@ class Extension extends ExtensionData { this.permissions.add(PRIVATE_ALLOWED_PERMISSION); } + // Bug 40253: Explicitly allow NoScript in Private Browsing mode. + if (this.id === "{73a6fe31-595d-460b-a920-fcc0f8843232}") { + ExtensionPermissions.add(this.id, { + permissions: [PRIVATE_ALLOWED_PERMISSION], + origins: [], + }); + this.permissions.add(PRIVATE_ALLOWED_PERMISSION); + } + // We only want to update the SVG_CONTEXT_PROPERTIES_PERMISSION during install and // upgrade/downgrade startups. if (INSTALL_AND_UPDATE_STARTUP_REASONS.has(this.startupReason)) {
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 12620: TorBrowser regression tests
by richard@torproject.org 09 Feb '22

09 Feb '22
commit ff1d9e7b2e22ae7dc7e4a998db655de2b05aa567 Author: Arthur Edelstein <arthuredelstein(a)gmail.com> Date: Wed Aug 27 16:25:00 2014 -0700 Bug 12620: TorBrowser regression tests Regression tests for Bug #2950: Make Permissions Manager memory-only Regression tests for TB4: Tor Browser's Firefox preference overrides. Note: many more functional tests could be made here Regression tests for #2874: Block Components.interfaces from content Bug 18923: Add a script to run all Tor Browser specific tests Regression tests for Bug #16441: Suppress "Reset Tor Browser" prompt. --- run-tbb-tests | 66 +++++++++++++++++++++++++++++++++++ tbb-tests-ignore.txt | 13 +++++++ tbb-tests/browser.ini | 5 +++ tbb-tests/browser_tor_TB4.js | 35 +++++++++++++++++++ tbb-tests/browser_tor_bug2950.js | 74 ++++++++++++++++++++++++++++++++++++++++ tbb-tests/mochitest.ini | 3 ++ tbb-tests/moz.build | 9 +++++ tbb-tests/test_tor_bug2874.html | 25 ++++++++++++++ toolkit/toolkit.mozbuild | 3 +- 9 files changed, 232 insertions(+), 1 deletion(-) diff --git a/run-tbb-tests b/run-tbb-tests new file mode 100755 index 000000000000..bc09839f9f05 --- /dev/null +++ b/run-tbb-tests @@ -0,0 +1,66 @@ +#!/bin/bash + +# This script runs all the Mochitest tests that have been added or +# modified since the last ffxbld commit. +# +# It does not currently run XPCShell tests. We should change this if we +# start using this type or other types of tests. +# +# The logs of the tests are stored in the tbb-tests.log file. +# Ignored tests are listed in the tbb-tests-ignore.txt file. +# +# https://trac.torproject.org/projects/tor/ticket/18923 + +IFS=$'\n' + +if [ -n "$USE_TESTS_LIST" ] && [ -f tbb-tests-list.txt ] +then + echo "Using tests list from file tbb-tests-list.txt" + tests=($(cat tbb-tests-list.txt)) +else + ffxbld_commit=$(git log -500 --format='oneline' | grep "TB3: Tor Browser's official .mozconfigs." \ + | head -1 | cut -d ' ' -f 1) + + tests=($(git diff --name-status "$ffxbld_commit" HEAD | \ + grep -e '^[AM].*/test_[^/]\+\.\(html\|xul\)$' \ + -e '^[AM].*/browser_[^/]\+\.js$' \ + | sed 's/^[AM]\s\+//')) +fi + +echo 'The following tests will be run:' +for i in "${!tests[@]}" +do + if [ -z "$USE_TESTS_LIST" ] \ + && grep -q "^${tests[$i]}$" tbb-tests-ignore.txt + then + unset "tests[$i]" + continue + fi + echo "- ${tests[$i]}" +done + +if [ -n "$WRITE_TESTS_LIST" ] +then + rm -f tbb-tests-list.txt + for i in "${!tests[@]}" + do + echo "${tests[$i]}" >> tbb-tests-list.txt + done + exit 0 +fi + +rm -f tbb-tests.log +echo $'\n''Starting tests' +# We need `security.nocertdb = false` because of #18087. That pref is +# forced to have the same value as `browser.privatebrowsing.autostart` in +# torbutton, so we just set `browser.privatebrowsing.autostart=false` here. +./mach mochitest --log-tbpl tbb-tests.log \ + --setpref network.file.path_blacklist='' \ + --setpref extensions.torbutton.use_nontor_proxy=true \ + --setpref browser.privatebrowsing.autostart=false \ + "${tests[@]}" + +echo "*************************" +echo "*************************" +echo "Summary of failed tests:" +grep --color=never TEST-UNEXPECTED-FAIL tbb-tests.log diff --git a/tbb-tests-ignore.txt b/tbb-tests-ignore.txt new file mode 100644 index 000000000000..ee3927a9e7c4 --- /dev/null +++ b/tbb-tests-ignore.txt @@ -0,0 +1,13 @@ +browser/extensions/onboarding/test/browser/browser_onboarding_accessibility.js +browser/extensions/onboarding/test/browser/browser_onboarding_keyboard.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_5.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_click_auto_complete_tour.js +browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js +browser/extensions/onboarding/test/browser/browser_onboarding_skip_tour.js +browser/extensions/onboarding/test/browser/browser_onboarding_tours.js +browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js +browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js diff --git a/tbb-tests/browser.ini b/tbb-tests/browser.ini new file mode 100644 index 000000000000..f481660f1417 --- /dev/null +++ b/tbb-tests/browser.ini @@ -0,0 +1,5 @@ +[DEFAULT] + +[browser_tor_bug2950.js] +[browser_tor_omnibox.js] +[browser_tor_TB4.js] diff --git a/tbb-tests/browser_tor_TB4.js b/tbb-tests/browser_tor_TB4.js new file mode 100644 index 000000000000..8bb12f360e5e --- /dev/null +++ b/tbb-tests/browser_tor_TB4.js @@ -0,0 +1,35 @@ +// # Test for TB4: Tor Browser's Firefox preference overrides +// This is a minimal test to check whether the 000-tor-browser.js +// pref overrides are being used at all or not. More comprehensive +// pref tests are maintained in the tor-browser-bundle-testsuite project. + +function test() { + +let expectedPrefs = [ + // Homepage + ["browser.startup.homepage", "about:tor"], + + // Disable the "Refresh" prompt that is displayed for stale profiles. + ["browser.disableResetPrompt", true], + + // Version placeholder + ["torbrowser.version", "dev-build"], + ]; + +let getPref = function (prefName) { + let type = Services.prefs.getPrefType(prefName); + if (type === Services.prefs.PREF_INT) return Services.prefs.getIntPref(prefName); + if (type === Services.prefs.PREF_BOOL) return Services.prefs.getBoolPref(prefName); + if (type === Services.prefs.PREF_STRING) return Services.prefs.getCharPref(prefName); + // Something went wrong. + throw new Error("Can't access pref " + prefName); +}; + +let testPref = function([key, expectedValue]) { + let foundValue = getPref(key); + is(foundValue, expectedValue, "Pref '" + key + "' should be '" + expectedValue +"'."); +}; + +expectedPrefs.map(testPref); + +} // end function test() diff --git a/tbb-tests/browser_tor_bug2950.js b/tbb-tests/browser_tor_bug2950.js new file mode 100644 index 000000000000..16e41344a3c4 --- /dev/null +++ b/tbb-tests/browser_tor_bug2950.js @@ -0,0 +1,74 @@ +// # Regression tests for tor Bug #2950, Make Permissions Manager memory-only +// Ensures that permissions.sqlite file in profile directory is not written to, +// even when we write a value to Firefox's permissions database. + +// The requisite test() function. +function test() { + +// Needed because of asynchronous part later in the test. +waitForExplicitFinish(); + +// Shortcut +let Ci = Components.interfaces; + +// ## utility functions + +// __principal(spec)__. +// Creates a principal instance from a spec +// (string address such as "https://www.torproject.org"). +let principal = spec => Services.scriptSecurityManager.createContentPrincipalFromOrigin(spec); + +// __setPermission(spec, key, value)__. +// Sets the site permission of type key to value, for the site located at address spec. +let setPermission = (spec, key, value) => SitePermissions.setForPrincipal(principal(spec), key, value); + +// __getPermission(spec, key)__. +// Reads the site permission value for permission type key, for the site +// located at address spec. +let getPermission = (spec, key) => SitePermissions.getForPrincipal(principal(spec), key); + +// __profileDirPath__. +// The Firefox Profile directory. Expected location of various persistent files. +let profileDirPath = Services.dirsvc.get("ProfD", Components.interfaces.nsIFile).path; + +// __fileInProfile(fileName)__. +// Returns an nsIFile instance corresponding to a file in the Profile directory. +let fileInProfile = fileName => FileUtils.File(profileDirPath + "/" + fileName); + +// ## Now let's run the test. + +let SITE = "https://www.torproject.org", + KEY = "popup"; + +let permissionsFile = fileInProfile("permissions.sqlite"), + lastModifiedTime = null, + newModifiedTime = null; +if (permissionsFile.exists()) { + lastModifiedTime = permissionsFile.lastModifiedTime; +} +// Read the original value of the permission. +let originalValue = getPermission(SITE, KEY); + +// We need to delay by at least 1000 ms, because that's the granularity +// of file time stamps, it seems. +window.setTimeout( + function () { + // Set the permission to a new value. + setPermission(SITE, KEY, SitePermissions.BLOCK); + // Now read back the permission value again. + let newReadValue = getPermission(SITE, KEY); + // Compare to confirm that the permission + // value was successfully changed. + Assert.notDeepEqual(originalValue, newReadValue, "Set a value in permissions db (perhaps in memory)."); + // If file existed or now exists, get the current time stamp. + if (permissionsFile.exists()) { + newModifiedTime = permissionsFile.lastModifiedTime; + } + // If file was created or modified since we began this test, + // then permissions db is not memory only. Complain! + is(lastModifiedTime, newModifiedTime, "Don't write to permissions.sqlite file on disk."); + // We are done with the test. + finish(); + }, 1100); + +} // test() diff --git a/tbb-tests/mochitest.ini b/tbb-tests/mochitest.ini new file mode 100644 index 000000000000..cc5172733bbe --- /dev/null +++ b/tbb-tests/mochitest.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[test_tor_bug2874.html] diff --git a/tbb-tests/moz.build b/tbb-tests/moz.build new file mode 100644 index 000000000000..01db60b9c28a --- /dev/null +++ b/tbb-tests/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOCHITEST_MANIFESTS += ["mochitest.ini"] + +BROWSER_CHROME_MANIFESTS += ["browser.ini"] diff --git a/tbb-tests/test_tor_bug2874.html b/tbb-tests/test_tor_bug2874.html new file mode 100644 index 000000000000..c0a956e9f687 --- /dev/null +++ b/tbb-tests/test_tor_bug2874.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<!-- +Tor bug +https://trac.torproject.org/projects/tor/ticket/2874 +--> +<head> + <meta charset="utf-8"> + <title>Test for Tor Bug 2874</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + is(typeof Components, 'undefined', "The global window object should not expose a Components property to untrusted content."); + </script> +</head> +<body> +<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/2874">Tor Bug 2874</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index 5576f6acc427..a2c3ddf2dc38 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -99,7 +99,8 @@ if CONFIG['MOZ_WEBRTC'] and CONFIG['COMPILE_ENVIRONMENT']: ] if CONFIG['ENABLE_TESTS']: - DIRS += ['/testing/specialpowers'] + DIRS += ['/testing/specialpowers', + '/tbb-tests'] DIRS += [ '/testing/gtest',
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 40091: Load HTTPS Everywhere as a builtin addon in desktop
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 76917352d6c9f865638a541bcd458f00d15691e5 Author: Alex Catarineu <acat(a)torproject.org> Date: Fri Sep 4 12:34:35 2020 +0200 Bug 40091: Load HTTPS Everywhere as a builtin addon in desktop This loads HTTPS Everywhere as a builtin addon from a hardcoded resource:// URI in desktop. It also ensures that the non-builtin HTTPS Everywhere addon is always uninstalled on browser startup. The reason of making this desktop-only is that there are some issues when installing a builtin extension from geckoview side, making the extension not available on first startup. So, at least for now we handle the Fenix case separately. See #40118 for a followup for investigating these. --- browser/components/BrowserGlue.jsm | 37 ++++++++++++++++++++++ toolkit/components/extensions/Extension.jsm | 10 ++++-- .../mozapps/extensions/internal/XPIProvider.jsm | 13 ++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index dc956bc79616..7c81eaaccf77 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -45,6 +45,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { DownloadsViewableInternally: "resource:///modules/DownloadsViewableInternally.jsm", E10SUtils: "resource://gre/modules/E10SUtils.jsm", + ExtensionData: "resource://gre/modules/Extension.jsm", ExtensionsUI: "resource:///modules/ExtensionsUI.jsm", FeatureGate: "resource://featuregates/FeatureGate.jsm", FxAccounts: "resource://gre/modules/FxAccounts.jsm", @@ -119,6 +120,13 @@ XPCOMUtils.defineLazyServiceGetters(this, { PushService: ["@mozilla.org/push/Service;1", "nsIPushService"], }); +XPCOMUtils.defineLazyServiceGetters(this, { + resProto: [ + "@mozilla.org/network/protocol;1?name=resource", + "nsISubstitutingProtocolHandler", + ], +}); + const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; /** @@ -1399,6 +1407,35 @@ BrowserGlue.prototype = { "resource://builtin-themes/alpenglow/" ); + // Install https-everywhere builtin addon if needed. + (async () => { + const HTTPS_EVERYWHERE_ID = "https-everywhere-eff(a)eff.org"; + const HTTPS_EVERYWHERE_BUILTIN_URL = + "resource://torbutton/content/extensions/https-everywhere/"; + // This does something similar as GeckoViewWebExtension.jsm: it tries + // to load the manifest to retrieve the version of the builtin and + // compares it to the currently installed one to see whether we need + // to install or not. Here we delegate that to + // AddonManager.maybeInstallBuiltinAddon. + try { + const resolvedURI = Services.io.newURI( + resProto.resolveURI(Services.io.newURI(HTTPS_EVERYWHERE_BUILTIN_URL)) + ); + const extensionData = new ExtensionData(resolvedURI); + const manifest = await extensionData.loadManifest(); + + await AddonManager.maybeInstallBuiltinAddon( + HTTPS_EVERYWHERE_ID, + manifest.version, + HTTPS_EVERYWHERE_BUILTIN_URL + ); + } catch (e) { + const log = Log.repository.getLogger("HttpsEverywhereBuiltinLoader"); + log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); + log.error("Could not install https-everywhere extension", e); + } + })(); + if (AppConstants.MOZ_NORMANDY) { Normandy.init(); } diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm index 08c5cf8a9190..783ec7c3391d 100644 --- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -267,6 +267,7 @@ const LOGGER_ID_BASE = "addons.webextension."; const UUID_MAP_PREF = "extensions.webextensions.uuids"; const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall"; const LEAVE_UUID_PREF = "extensions.webextensions.keepUuidOnUninstall"; +const PERSISTENT_EXTENSIONS = new Set(["https-everywhere-eff(a)eff.org"]); const COMMENT_REGEXP = new RegExp( String.raw` @@ -413,7 +414,8 @@ var ExtensionAddonObserver = { ); } - if (!Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false)) { + if (!Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false) && + !PERSISTENT_EXTENSIONS.has(addon.id)) { // Clear browser.storage.local backends. AsyncShutdown.profileChangeTeardown.addBlocker( `Clear Extension Storage ${addon.id} (File Backend)`, @@ -461,7 +463,8 @@ var ExtensionAddonObserver = { ExtensionPermissions.removeAll(addon.id); - if (!Services.prefs.getBoolPref(LEAVE_UUID_PREF, false)) { + if (!Services.prefs.getBoolPref(LEAVE_UUID_PREF, false) && + !PERSISTENT_EXTENSIONS.has(addon.id)) { // Clear the entry in the UUID map UUIDMap.remove(addon.id); } @@ -2696,7 +2699,8 @@ class Extension extends ExtensionData { ); } else if ( this.startupReason === "ADDON_INSTALL" && - !Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false) + !Services.prefs.getBoolPref(LEAVE_STORAGE_PREF, false) && + !PERSISTENT_EXTENSIONS.has(this.id) ) { // If the extension has been just installed, set it as migrated, // because there will not be any data to migrate. diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 04d57a42348e..fd1e3f75935d 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -1495,6 +1495,19 @@ var XPIStates = { continue; } + // Uninstall HTTPS Everywhere if it is installed in the user profile. + if ( + id === "https-everywhere-eff(a)eff.org" && + loc.name === KEY_APP_PROFILE + ) { + logger.debug( + "Uninstalling the HTTPS Everywhere extension from user profile." + ); + loc.installer.uninstallAddon(id); + changed = true; + continue; + } + let xpiState = loc.get(id); if (!xpiState) { // If the location is not supported for sideloading, skip new
1 0
0 0
[tor-browser/tor-browser-91.6.0esr-11.5-1] Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#tor
by richard@torproject.org 09 Feb '22

09 Feb '22
commit 333c9f4e8cc032051ff4eef599ee6571fef00d53 Author: Richard Pospesel <richard(a)torproject.org> Date: Mon Sep 16 15:25:39 2019 -0700 Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#tor This patch adds a new about:preferences#tor page which allows modifying bridge, proxy, and firewall settings from within Tor Browser. All of the functionality present in tor-launcher's Network Configuration panel is present: - Setting built-in bridges - Requesting bridges from BridgeDB via moat - Using user-provided bridges - Configuring SOCKS4, SOCKS5, and HTTP/HTTPS proxies - Setting firewall ports - Viewing and Copying Tor's logs - The Networking Settings in General preferences has been removed --- browser/components/moz.build | 1 + browser/components/preferences/main.inc.xhtml | 54 -- browser/components/preferences/main.js | 14 - browser/components/preferences/preferences.js | 9 + browser/components/preferences/preferences.xhtml | 5 + .../torpreferences/content/requestBridgeDialog.jsm | 209 +++++ .../content/requestBridgeDialog.xhtml | 35 + .../torpreferences/content/torCategory.inc.xhtml | 9 + .../torpreferences/content/torLogDialog.jsm | 66 ++ .../torpreferences/content/torLogDialog.xhtml | 23 + .../components/torpreferences/content/torPane.js | 940 +++++++++++++++++++++ .../torpreferences/content/torPane.xhtml | 157 ++++ .../torpreferences/content/torPreferences.css | 189 +++++ .../torpreferences/content/torPreferencesIcon.svg | 8 + browser/components/torpreferences/jar.mn | 10 + browser/components/torpreferences/moz.build | 1 + 16 files changed, 1662 insertions(+), 68 deletions(-) diff --git a/browser/components/moz.build b/browser/components/moz.build index 1bc09f4093fb..66de87290bd8 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -53,6 +53,7 @@ DIRS += [ "syncedtabs", "uitour", "urlbar", + "torpreferences", "translation", ] diff --git a/browser/components/preferences/main.inc.xhtml b/browser/components/preferences/main.inc.xhtml index a89b89f723a8..594711e61474 100644 --- a/browser/components/preferences/main.inc.xhtml +++ b/browser/components/preferences/main.inc.xhtml @@ -671,58 +671,4 @@ <label id="cfrFeaturesLearnMore" class="learnMore" data-l10n-id="browsing-cfr-recommendations-learn-more" is="text-link"/> </hbox> </groupbox> - -<hbox id="networkProxyCategory" - class="subcategory" - hidden="true" - data-category="paneGeneral"> - <html:h1 data-l10n-id="network-settings-title"/> -</hbox> - -<!-- Network Settings--> -<groupbox id="connectionGroup" data-category="paneGeneral" hidden="true"> - <label class="search-header" hidden="true"><html:h2 data-l10n-id="network-settings-title"/></label> - - <hbox align="center"> - <hbox align="center" flex="1"> - <description id="connectionSettingsDescription" control="connectionSettings"/> - <spacer width="5"/> - <label id="connectionSettingsLearnMore" class="learnMore" is="text-link" - data-l10n-id="network-proxy-connection-learn-more"> - </label> - <separator orient="vertical"/> - </hbox> - - <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. --> - <hbox> - <button id="connectionSettings" - is="highlightable-button" - class="accessory-button" - data-l10n-id="network-proxy-connection-settings" - searchkeywords="doh trr" - search-l10n-ids=" - connection-window.title, - connection-proxy-option-no.label, - connection-proxy-option-auto.label, - connection-proxy-option-system.label, - connection-proxy-option-manual.label, - connection-proxy-http, - connection-proxy-https, - connection-proxy-http-port, - connection-proxy-socks, - connection-proxy-socks4, - connection-proxy-socks5, - connection-proxy-noproxy, - connection-proxy-noproxy-desc, - connection-proxy-https-sharing.label, - connection-proxy-autotype.label, - connection-proxy-reload.label, - connection-proxy-autologin.label, - connection-proxy-socks-remote-dns.label, - connection-dns-over-https.label, - connection-dns-over-https-url-custom.label, - " /> - </hbox> - </hbox> -</groupbox> </html:template> diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js index 2a6ba4a3d8e4..501ba9144a31 100644 --- a/browser/components/preferences/main.js +++ b/browser/components/preferences/main.js @@ -368,15 +368,6 @@ var gMainPane = { }); this.updatePerformanceSettingsBox({ duringChangeEvent: false }); this.displayUseSystemLocale(); - let connectionSettingsLink = document.getElementById( - "connectionSettingsLearnMore" - ); - let connectionSettingsUrl = - Services.urlFormatter.formatURLPref("app.support.baseURL") + - "prefs-connection-settings"; - connectionSettingsLink.setAttribute("href", connectionSettingsUrl); - this.updateProxySettingsUI(); - initializeProxyUI(gMainPane); if (Services.prefs.getBoolPref("intl.multilingual.enabled")) { gMainPane.initBrowserLocale(); @@ -510,11 +501,6 @@ var gMainPane = { "change", gMainPane.updateHardwareAcceleration.bind(gMainPane) ); - setEventListener( - "connectionSettings", - "command", - gMainPane.showConnections - ); setEventListener( "browserContainersCheckbox", "command", diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js index a3656f827ffc..ce338584142e 100644 --- a/browser/components/preferences/preferences.js +++ b/browser/components/preferences/preferences.js @@ -13,6 +13,7 @@ /* import-globals-from findInPage.js */ /* import-globals-from ../../base/content/utilityOverlay.js */ /* import-globals-from ../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from ../torpreferences/content/torPane.js */ "use strict"; @@ -136,6 +137,14 @@ function init_all() { register_module("paneSync", gSyncPane); } register_module("paneSearchResults", gSearchResultsPane); + if (gTorPane.enabled) { + document.getElementById("category-tor").hidden = false; + register_module("paneTor", gTorPane); + } else { + // Remove the pane from the DOM so it doesn't get incorrectly included in search results. + document.getElementById("template-paneTor").remove(); + } + gSearchResultsPane.init(); gMainPane.preInit(); diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml index 32184867ac17..0923005c8b90 100644 --- a/browser/components/preferences/preferences.xhtml +++ b/browser/components/preferences/preferences.xhtml @@ -12,6 +12,7 @@ <?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?> <?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?> +<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?> <!DOCTYPE html [ <!ENTITY % aboutTorDTD SYSTEM "chrome://torbutton/locale/aboutTor.dtd"> @@ -154,6 +155,9 @@ <image class="category-icon"/> <label class="category-name" flex="1" data-l10n-id="pane-experimental-title"></label> </richlistitem> + +#include ../torpreferences/content/torCategory.inc.xhtml + </richlistbox> <spacer flex="1"/> @@ -207,6 +211,7 @@ #include containers.inc.xhtml #include sync.inc.xhtml #include experimental.inc.xhtml +#include ../torpreferences/content/torPane.xhtml </vbox> </vbox> </vbox> diff --git a/browser/components/torpreferences/content/requestBridgeDialog.jsm b/browser/components/torpreferences/content/requestBridgeDialog.jsm new file mode 100644 index 000000000000..44ae11762def --- /dev/null +++ b/browser/components/torpreferences/content/requestBridgeDialog.jsm @@ -0,0 +1,209 @@ +"use strict"; + +var EXPORTED_SYMBOLS = ["RequestBridgeDialog"]; + +const { BridgeDB } = ChromeUtils.import("resource:///modules/BridgeDB.jsm"); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); + +class RequestBridgeDialog { + constructor() { + this._dialog = null; + this._submitButton = null; + this._dialogDescription = null; + this._captchaImage = null; + this._captchaEntryTextbox = null; + this._captchaRefreshButton = null; + this._incorrectCaptchaHbox = null; + this._incorrectCaptchaLabel = null; + this._bridges = []; + } + + static get selectors() { + return { + submitButton: + "accept" /* not really a selector but a key for dialog's getButton */, + dialogDescription: "description#torPreferences-requestBridge-description", + captchaImage: "image#torPreferences-requestBridge-captchaImage", + captchaEntryTextbox: "input#torPreferences-requestBridge-captchaTextbox", + refreshCaptchaButton: + "button#torPreferences-requestBridge-refreshCaptchaButton", + incorrectCaptchaHbox: + "hbox#torPreferences-requestBridge-incorrectCaptchaHbox", + incorrectCaptchaLabel: + "label#torPreferences-requestBridge-incorrectCaptchaError", + }; + } + + _populateXUL(dialog) { + const selectors = RequestBridgeDialog.selectors; + + this._dialog = dialog; + const dialogWin = dialog.parentElement; + dialogWin.setAttribute( + "title", + TorStrings.settings.requestBridgeDialogTitle + ); + // user may have opened a Request Bridge dialog in another tab, so update the + // CAPTCHA image or close out the dialog if we have a bridge list + this._dialog.addEventListener("focusin", () => { + const uri = BridgeDB.currentCaptchaImage; + const bridges = BridgeDB.currentBridges; + + // new captcha image + if (uri) { + this._setcaptchaImage(uri); + } else if (bridges) { + this._bridges = bridges; + this._submitButton.disabled = false; + this._dialog.cancelDialog(); + } + }); + + this._submitButton = this._dialog.getButton(selectors.submitButton); + this._submitButton.setAttribute("label", TorStrings.settings.submitCaptcha); + this._submitButton.disabled = true; + this._dialog.addEventListener("dialogaccept", e => { + e.preventDefault(); + this.onSubmitCaptcha(); + }); + + this._dialogDescription = this._dialog.querySelector( + selectors.dialogDescription + ); + this._dialogDescription.textContent = + TorStrings.settings.contactingBridgeDB; + + this._captchaImage = this._dialog.querySelector(selectors.captchaImage); + + // request captcha from bridge db + BridgeDB.requestNewCaptchaImage().then(uri => { + this._setcaptchaImage(uri); + }); + + this._captchaEntryTextbox = this._dialog.querySelector( + selectors.captchaEntryTextbox + ); + this._captchaEntryTextbox.setAttribute( + "placeholder", + TorStrings.settings.captchaTextboxPlaceholder + ); + this._captchaEntryTextbox.disabled = true; + // disable submit if entry textbox is empty + this._captchaEntryTextbox.oninput = () => { + this._submitButton.disabled = this._captchaEntryTextbox.value == ""; + }; + + this._captchaRefreshButton = this._dialog.querySelector( + selectors.refreshCaptchaButton + ); + this._captchaRefreshButton.disabled = true; + + this._incorrectCaptchaHbox = this._dialog.querySelector( + selectors.incorrectCaptchaHbox + ); + this._incorrectCaptchaLabel = this._dialog.querySelector( + selectors.incorrectCaptchaLabel + ); + this._incorrectCaptchaLabel.setAttribute( + "value", + TorStrings.settings.incorrectCaptcha + ); + + return true; + } + + _setcaptchaImage(uri) { + if (uri != this._captchaImage.src) { + this._captchaImage.src = uri; + this._dialogDescription.textContent = TorStrings.settings.solveTheCaptcha; + this._setUIDisabled(false); + this._captchaEntryTextbox.focus(); + this._captchaEntryTextbox.select(); + } + } + + _setUIDisabled(disabled) { + this._submitButton.disabled = this._captchaGuessIsEmpty() || disabled; + this._captchaEntryTextbox.disabled = disabled; + this._captchaRefreshButton.disabled = disabled; + } + + _captchaGuessIsEmpty() { + return this._captchaEntryTextbox.value == ""; + } + + init(window, dialog) { + // defer to later until firefox has populated the dialog with all our elements + window.setTimeout(() => { + this._populateXUL(dialog); + }, 0); + } + + close() { + BridgeDB.close(); + } + + /* + Event Handlers + */ + onSubmitCaptcha() { + let captchaText = this._captchaEntryTextbox.value.trim(); + // noop if the field is empty + if (captchaText == "") { + return; + } + + // freeze ui while we make request + this._setUIDisabled(true); + this._incorrectCaptchaHbox.style.visibility = "hidden"; + + BridgeDB.submitCaptchaGuess(captchaText) + .then(aBridges => { + if (aBridges) { + this._bridges = aBridges; + this._submitButton.disabled = false; + // This was successful, but use cancelDialog() to close, since + // we intercept the `dialogaccept` event. + this._dialog.cancelDialog(); + } else { + this._bridges = []; + this._setUIDisabled(false); + this._incorrectCaptchaHbox.style.visibility = "visible"; + } + }) + .catch(aError => { + // TODO: handle other errors properly here when we do the bridge settings re-design + this._bridges = []; + this._setUIDisabled(false); + this._incorrectCaptchaHbox.style.visibility = "visible"; + console.log(eError); + }); + } + + onRefreshCaptcha() { + this._setUIDisabled(true); + this._captchaImage.src = ""; + this._dialogDescription.textContent = + TorStrings.settings.contactingBridgeDB; + this._captchaEntryTextbox.value = ""; + this._incorrectCaptchaHbox.style.visibility = "hidden"; + + BridgeDB.requestNewCaptchaImage().then(uri => { + this._setcaptchaImage(uri); + }); + } + + openDialog(gSubDialog, aCloseCallback) { + gSubDialog.open( + "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml", + { + features: "resizable=yes", + closingCallback: () => { + this.close(); + aCloseCallback(this._bridges); + } + }, + this, + ); + } +} diff --git a/browser/components/torpreferences/content/requestBridgeDialog.xhtml b/browser/components/torpreferences/content/requestBridgeDialog.xhtml new file mode 100644 index 000000000000..64c4507807fb --- /dev/null +++ b/browser/components/torpreferences/content/requestBridgeDialog.xhtml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?> +<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?> + +<window type="child" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml"> +<dialog id="torPreferences-requestBridge-dialog" + buttons="accept,cancel"> + <!-- ok, so &#8203; is a zero-width space. We need to have *something* in the innerText so that XUL knows how tall the + description node is so that it can determine how large to make the dialog element's inner draw area. If we have + nothing in the innerText, then it collapse to 0 height, and the contents of the dialog ends up partially hidden >:( --> + <description id="torPreferences-requestBridge-description">&#8203;</description> + <!-- init to transparent 400x125 png --> + <image id="torPreferences-requestBridge-captchaImage" flex="1"/> + <hbox id="torPreferences-requestBridge-inputHbox"> + <html:input id="torPreferences-requestBridge-captchaTextbox" type="text" style="-moz-box-flex: 1;"/> + <button id="torPreferences-requestBridge-refreshCaptchaButton" + image="chrome://browser/skin/reload.svg" + oncommand="requestBridgeDialog.onRefreshCaptcha();"/> + </hbox> + <hbox id="torPreferences-requestBridge-incorrectCaptchaHbox" align="center"> + <image id="torPreferences-requestBridge-errorIcon" /> + <label id="torPreferences-requestBridge-incorrectCaptchaError" flex="1"/> + </hbox> + <script type="application/javascript"><![CDATA[ + "use strict"; + + let requestBridgeDialog = window.arguments[0]; + let dialog = document.getElementById("torPreferences-requestBridge-dialog"); + requestBridgeDialog.init(window, dialog); + ]]></script> +</dialog> +</window> \ No newline at end of file diff --git a/browser/components/torpreferences/content/torCategory.inc.xhtml b/browser/components/torpreferences/content/torCategory.inc.xhtml new file mode 100644 index 000000000000..abe56200f571 --- /dev/null +++ b/browser/components/torpreferences/content/torCategory.inc.xhtml @@ -0,0 +1,9 @@ +<richlistitem id="category-tor" + class="category" + value="paneTor" + helpTopic="prefs-tor" + align="center" + hidden="true"> + <image class="category-icon"/> + <label id="torPreferences-labelCategory" class="category-name" flex="1" value="Tor"/> +</richlistitem> diff --git a/browser/components/torpreferences/content/torLogDialog.jsm b/browser/components/torpreferences/content/torLogDialog.jsm new file mode 100644 index 000000000000..ecc684d878c2 --- /dev/null +++ b/browser/components/torpreferences/content/torLogDialog.jsm @@ -0,0 +1,66 @@ +"use strict"; + +var EXPORTED_SYMBOLS = ["TorLogDialog"]; + +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); + +class TorLogDialog { + constructor() { + this._dialog = null; + this._logTextarea = null; + this._copyLogButton = null; + } + + static get selectors() { + return { + copyLogButton: "extra1", + logTextarea: "textarea#torPreferences-torDialog-textarea", + }; + } + + _populateXUL(aDialog) { + this._dialog = aDialog; + const dialogWin = this._dialog.parentElement; + dialogWin.setAttribute("title", TorStrings.settings.torLogDialogTitle); + + this._logTextarea = this._dialog.querySelector( + TorLogDialog.selectors.logTextarea + ); + + this._copyLogButton = this._dialog.getButton( + TorLogDialog.selectors.copyLogButton + ); + this._copyLogButton.setAttribute("label", TorStrings.settings.copyLog); + this._copyLogButton.addEventListener("command", () => { + this.copyTorLog(); + }); + + this._logTextarea.value = TorProtocolService.getLog(); + } + + init(window, aDialog) { + // defer to later until firefox has populated the dialog with all our elements + window.setTimeout(() => { + this._populateXUL(aDialog); + }, 0); + } + + copyTorLog() { + // Copy tor log messages to the system clipboard. + let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( + Ci.nsIClipboardHelper + ); + clipboard.copyString(this._logTextarea.value); + } + + openDialog(gSubDialog) { + gSubDialog.open( + "chrome://browser/content/torpreferences/torLogDialog.xhtml", + { features: "resizable=yes" }, + this + ); + } +} diff --git a/browser/components/torpreferences/content/torLogDialog.xhtml b/browser/components/torpreferences/content/torLogDialog.xhtml new file mode 100644 index 000000000000..9c17f8132978 --- /dev/null +++ b/browser/components/torpreferences/content/torLogDialog.xhtml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?> +<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?> + +<window type="child" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml"> +<dialog id="torPreferences-torLog-dialog" + buttons="accept,extra1"> + <html:textarea + id="torPreferences-torDialog-textarea" + multiline="true" + readonly="true"/> + <script type="application/javascript"><![CDATA[ + "use strict"; + + let torLogDialog = window.arguments[0]; + let dialog = document.getElementById("torPreferences-torLog-dialog"); + torLogDialog.init(window, dialog); + ]]></script> +</dialog> +</window> \ No newline at end of file diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js new file mode 100644 index 000000000000..58eec7ff74aa --- /dev/null +++ b/browser/components/torpreferences/content/torPane.js @@ -0,0 +1,940 @@ +"use strict"; + +/* global Services */ + +const { TorSettings, TorSettingsTopics, TorSettingsData, TorBridgeSource, TorBuiltinBridgeTypes, TorProxyType } = ChromeUtils.import( + "resource:///modules/TorSettings.jsm" +); + +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + +const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import( + "resource:///modules/TorConnect.jsm" +); + +const { TorLogDialog } = ChromeUtils.import( + "chrome://browser/content/torpreferences/torLogDialog.jsm" +); + +const { RequestBridgeDialog } = ChromeUtils.import( + "chrome://browser/content/torpreferences/requestBridgeDialog.jsm" +); + +ChromeUtils.defineModuleGetter( + this, + "TorStrings", + "resource:///modules/TorStrings.jsm" +); + +/* + Tor Pane + + Code for populating the XUL in about:preferences#tor, handling input events, interfacing with tor-launcher +*/ +const gTorPane = (function() { + /* CSS selectors for all of the Tor Network DOM elements we need to access */ + const selectors = { + category: { + title: "label#torPreferences-labelCategory", + }, + messageBox: { + box: "div#torPreferences-connectMessageBox", + message: "td#torPreferences-connectMessageBox-message", + button: "button#torPreferences-connectMessageBox-button", + }, + torPreferences: { + header: "h1#torPreferences-header", + description: "span#torPreferences-description", + learnMore: "label#torPreferences-learnMore", + }, + quickstart: { + header: "h2#torPreferences-quickstart-header", + description: "span#torPreferences-quickstart-description", + enableQuickstartCheckbox: "checkbox#torPreferences-quickstart-toggle", + }, + bridges: { + header: "h2#torPreferences-bridges-header", + description: "span#torPreferences-bridges-description", + learnMore: "label#torPreferences-bridges-learnMore", + useBridgeCheckbox: "checkbox#torPreferences-bridges-toggle", + bridgeSelectionRadiogroup: + "radiogroup#torPreferences-bridges-bridgeSelection", + builtinBridgeOption: "radio#torPreferences-bridges-radioBuiltin", + builtinBridgeList: "menulist#torPreferences-bridges-builtinList", + requestBridgeOption: "radio#torPreferences-bridges-radioRequestBridge", + requestBridgeButton: "button#torPreferences-bridges-buttonRequestBridge", + requestBridgeTextarea: + "textarea#torPreferences-bridges-textareaRequestBridge", + provideBridgeOption: "radio#torPreferences-bridges-radioProvideBridge", + provideBridgeDescription: + "description#torPreferences-bridges-descriptionProvideBridge", + provideBridgeTextarea: + "textarea#torPreferences-bridges-textareaProvideBridge", + }, + advanced: { + header: "h2#torPreferences-advanced-header", + description: "span#torPreferences-advanced-description", + learnMore: "label#torPreferences-advanced-learnMore", + useProxyCheckbox: "checkbox#torPreferences-advanced-toggleProxy", + proxyTypeLabel: "label#torPreferences-localProxy-type", + proxyTypeList: "menulist#torPreferences-localProxy-builtinList", + proxyAddressLabel: "label#torPreferences-localProxy-address", + proxyAddressTextbox: "input#torPreferences-localProxy-textboxAddress", + proxyPortLabel: "label#torPreferences-localProxy-port", + proxyPortTextbox: "input#torPreferences-localProxy-textboxPort", + proxyUsernameLabel: "label#torPreferences-localProxy-username", + proxyUsernameTextbox: "input#torPreferences-localProxy-textboxUsername", + proxyPasswordLabel: "label#torPreferences-localProxy-password", + proxyPasswordTextbox: "input#torPreferences-localProxy-textboxPassword", + useFirewallCheckbox: "checkbox#torPreferences-advanced-toggleFirewall", + firewallAllowedPortsLabel: "label#torPreferences-advanced-allowedPorts", + firewallAllowedPortsTextbox: + "input#torPreferences-advanced-textboxAllowedPorts", + torLogsLabel: "label#torPreferences-torLogs", + torLogsButton: "button#torPreferences-buttonTorLogs", + }, + }; /* selectors */ + + let retval = { + // cached frequently accessed DOM elements + _messageBox: null, + _messageBoxMessage: null, + _messageBoxButton: null, + _enableQuickstartCheckbox: null, + _useBridgeCheckbox: null, + _bridgeSelectionRadiogroup: null, + _builtinBridgeOption: null, + _builtinBridgeMenulist: null, + _requestBridgeOption: null, + _requestBridgeButton: null, + _requestBridgeTextarea: null, + _provideBridgeOption: null, + _provideBridgeTextarea: null, + _useProxyCheckbox: null, + _proxyTypeLabel: null, + _proxyTypeMenulist: null, + _proxyAddressLabel: null, + _proxyAddressTextbox: null, + _proxyPortLabel: null, + _proxyPortTextbox: null, + _proxyUsernameLabel: null, + _proxyUsernameTextbox: null, + _proxyPasswordLabel: null, + _proxyPasswordTextbox: null, + _useFirewallCheckbox: null, + _allowedPortsLabel: null, + _allowedPortsTextbox: null, + + // tor network settings + _bridgeSettings: null, + _proxySettings: null, + _firewallSettings: null, + + // disables the provided list of elements + _setElementsDisabled(elements, disabled) { + for (let currentElement of elements) { + currentElement.disabled = disabled; + } + }, + + // populate xul with strings and cache the relevant elements + _populateXUL() { + // saves tor settings to disk when navigate away from about:preferences + window.addEventListener("blur", val => { + TorProtocolService.flushSettings(); + }); + + document + .querySelector(selectors.category.title) + .setAttribute("value", TorStrings.settings.categoryTitle); + + let prefpane = document.getElementById("mainPrefPane"); + + // 'Connect to Tor' Message Bar + + this._messageBox = prefpane.querySelector(selectors.messageBox.box); + this._messageBoxMessage = prefpane.querySelector(selectors.messageBox.message); + this._messageBoxButton = prefpane.querySelector(selectors.messageBox.button); + // wire up connect button + this._messageBoxButton.addEventListener("click", () => { + TorConnect.beginBootstrap(); + TorConnect.openTorConnect(); + }); + + this._populateMessagebox = () => { + if (TorConnect.shouldShowTorConnect && + TorConnect.state === TorConnectState.Configuring) { + // set messagebox style and text + if (TorProtocolService.torBootstrapErrorOccurred()) { + this._messageBox.parentNode.style.display = null; + this._messageBox.className = "error"; + this._messageBoxMessage.innerText = TorStrings.torConnect.tryAgainMessage; + this._messageBoxButton.innerText = TorStrings.torConnect.tryAgain; + } else { + this._messageBox.parentNode.style.display = null; + this._messageBox.className = "warning"; + this._messageBoxMessage.innerText = TorStrings.torConnect.connectMessage; + this._messageBoxButton.innerText = TorStrings.torConnect.torConnectButton; + } + } else { + // we need to explicitly hide the groupbox, as switching between + // the tor pane and other panes will 'unhide' (via the 'hidden' + // attribute) the groupbox, offsetting all of the content down + // by the groupbox's margin (even if content is 0 height) + this._messageBox.parentNode.style.display = "none"; + this._messageBox.className = "hidden"; + this._messageBoxMessage.innerText = ""; + this._messageBoxButton.innerText = ""; + } + } + this._populateMessagebox(); + Services.obs.addObserver(this, TorConnectTopics.StateChange); + + // update the messagebox whenever we come back to the page + window.addEventListener("focus", val => { + this._populateMessagebox(); + }); + + // Heading + prefpane.querySelector(selectors.torPreferences.header).innerText = + TorStrings.settings.torPreferencesHeading; + prefpane.querySelector(selectors.torPreferences.description).textContent = + TorStrings.settings.torPreferencesDescription; + { + let learnMore = prefpane.querySelector( + selectors.torPreferences.learnMore + ); + learnMore.setAttribute("value", TorStrings.settings.learnMore); + learnMore.setAttribute( + "href", + TorStrings.settings.learnMoreTorBrowserURL + ); + } + + // Quickstart + prefpane.querySelector(selectors.quickstart.header).innerText = + TorStrings.settings.quickstartHeading; + prefpane.querySelector(selectors.quickstart.description).textContent = + TorStrings.settings.quickstartDescription; + + this._enableQuickstartCheckbox = prefpane.querySelector( + selectors.quickstart.enableQuickstartCheckbox + ); + this._enableQuickstartCheckbox.setAttribute( + "label", + TorStrings.settings.quickstartCheckbox + ); + this._enableQuickstartCheckbox.addEventListener("command", e => { + const checked = this._enableQuickstartCheckbox.checked; + TorSettings.quickstart.enabled = checked; + TorSettings.saveToPrefs().applySettings(); + }); + this._enableQuickstartCheckbox.checked = TorSettings.quickstart.enabled; + Services.obs.addObserver(this, TorSettingsTopics.SettingChanged); + + // Bridge setup + prefpane.querySelector(selectors.bridges.header).innerText = + TorStrings.settings.bridgesHeading; + prefpane.querySelector(selectors.bridges.description).textContent = + TorStrings.settings.bridgesDescription; + { + let learnMore = prefpane.querySelector(selectors.bridges.learnMore); + learnMore.setAttribute("value", TorStrings.settings.learnMore); + learnMore.setAttribute("href", TorStrings.settings.learnMoreBridgesURL); + } + + this._useBridgeCheckbox = prefpane.querySelector( + selectors.bridges.useBridgeCheckbox + ); + this._useBridgeCheckbox.setAttribute( + "label", + TorStrings.settings.useBridge + ); + this._useBridgeCheckbox.addEventListener("command", e => { + const checked = this._useBridgeCheckbox.checked; + gTorPane.onToggleBridge(checked).onUpdateBridgeSettings(); + }); + this._bridgeSelectionRadiogroup = prefpane.querySelector( + selectors.bridges.bridgeSelectionRadiogroup + ); + this._bridgeSelectionRadiogroup.value = TorBridgeSource.BuiltIn; + this._bridgeSelectionRadiogroup.addEventListener("command", e => { + const value = this._bridgeSelectionRadiogroup.value; + gTorPane.onSelectBridgeOption(value).onUpdateBridgeSettings(); + }); + + // Builtin bridges + this._builtinBridgeOption = prefpane.querySelector( + selectors.bridges.builtinBridgeOption + ); + this._builtinBridgeOption.setAttribute( + "label", + TorStrings.settings.selectBridge + ); + this._builtinBridgeOption.setAttribute("value", TorBridgeSource.BuiltIn); + this._builtinBridgeMenulist = prefpane.querySelector( + selectors.bridges.builtinBridgeList + ); + this._builtinBridgeMenulist.addEventListener("command", e => { + gTorPane.onUpdateBridgeSettings(); + }); + + // Request bridge + this._requestBridgeOption = prefpane.querySelector( + selectors.bridges.requestBridgeOption + ); + this._requestBridgeOption.setAttribute( + "label", + TorStrings.settings.requestBridgeFromTorProject + ); + this._requestBridgeOption.setAttribute("value", TorBridgeSource.BridgeDB); + this._requestBridgeButton = prefpane.querySelector( + selectors.bridges.requestBridgeButton + ); + this._requestBridgeButton.setAttribute( + "label", + TorStrings.settings.requestNewBridge + ); + this._requestBridgeButton.addEventListener("command", () => + gTorPane.onRequestBridge() + ); + this._requestBridgeTextarea = prefpane.querySelector( + selectors.bridges.requestBridgeTextarea + ); + + // Provide a bridge + this._provideBridgeOption = prefpane.querySelector( + selectors.bridges.provideBridgeOption + ); + this._provideBridgeOption.setAttribute( + "label", + TorStrings.settings.provideBridge + ); + this._provideBridgeOption.setAttribute( + "value", + TorBridgeSource.UserProvided + ); + prefpane.querySelector( + selectors.bridges.provideBridgeDescription + ).textContent = TorStrings.settings.provideBridgeDirections; + this._provideBridgeTextarea = prefpane.querySelector( + selectors.bridges.provideBridgeTextarea + ); + this._provideBridgeTextarea.setAttribute( + "placeholder", + TorStrings.settings.provideBridgePlaceholder + ); + this._provideBridgeTextarea.addEventListener("blur", () => { + gTorPane.onUpdateBridgeSettings(); + }); + + // Advanced setup + prefpane.querySelector(selectors.advanced.header).innerText = + TorStrings.settings.advancedHeading; + prefpane.querySelector(selectors.advanced.description).textContent = + TorStrings.settings.advancedDescription; + { + let learnMore = prefpane.querySelector(selectors.advanced.learnMore); + learnMore.setAttribute("value", TorStrings.settings.learnMore); + learnMore.setAttribute( + "href", + TorStrings.settings.learnMoreNetworkSettingsURL + ); + } + + // Local Proxy + this._useProxyCheckbox = prefpane.querySelector( + selectors.advanced.useProxyCheckbox + ); + this._useProxyCheckbox.setAttribute( + "label", + TorStrings.settings.useLocalProxy + ); + this._useProxyCheckbox.addEventListener("command", e => { + const checked = this._useProxyCheckbox.checked; + gTorPane.onToggleProxy(checked).onUpdateProxySettings(); + }); + this._proxyTypeLabel = prefpane.querySelector( + selectors.advanced.proxyTypeLabel + ); + this._proxyTypeLabel.setAttribute("value", TorStrings.settings.proxyType); + + let mockProxies = [ + { + value: TorProxyType.Socks4, + label: TorStrings.settings.proxyTypeSOCKS4, + }, + { + value: TorProxyType.Socks5, + label: TorStrings.settings.proxyTypeSOCKS5, + }, + { value: TorProxyType.HTTPS, label: TorStrings.settings.proxyTypeHTTP }, + ]; + this._proxyTypeMenulist = prefpane.querySelector( + selectors.advanced.proxyTypeList + ); + this._proxyTypeMenulist.addEventListener("command", e => { + const value = this._proxyTypeMenulist.value; + gTorPane.onSelectProxyType(value).onUpdateProxySettings(); + }); + for (let currentProxy of mockProxies) { + let menuEntry = document.createXULElement("menuitem"); + menuEntry.setAttribute("value", currentProxy.value); + menuEntry.setAttribute("label", currentProxy.label); + this._proxyTypeMenulist + .querySelector("menupopup") + .appendChild(menuEntry); + } + + this._proxyAddressLabel = prefpane.querySelector( + selectors.advanced.proxyAddressLabel + ); + this._proxyAddressLabel.setAttribute( + "value", + TorStrings.settings.proxyAddress + ); + this._proxyAddressTextbox = prefpane.querySelector( + selectors.advanced.proxyAddressTextbox + ); + this._proxyAddressTextbox.setAttribute( + "placeholder", + TorStrings.settings.proxyAddressPlaceholder + ); + this._proxyAddressTextbox.addEventListener("blur", () => { + gTorPane.onUpdateProxySettings(); + }); + this._proxyPortLabel = prefpane.querySelector( + selectors.advanced.proxyPortLabel + ); + this._proxyPortLabel.setAttribute("value", TorStrings.settings.proxyPort); + this._proxyPortTextbox = prefpane.querySelector( + selectors.advanced.proxyPortTextbox + ); + this._proxyPortTextbox.addEventListener("blur", () => { + gTorPane.onUpdateProxySettings(); + }); + this._proxyUsernameLabel = prefpane.querySelector( + selectors.advanced.proxyUsernameLabel + ); + this._proxyUsernameLabel.setAttribute( + "value", + TorStrings.settings.proxyUsername + ); + this._proxyUsernameTextbox = prefpane.querySelector( + selectors.advanced.proxyUsernameTextbox + ); + this._proxyUsernameTextbox.setAttribute( + "placeholder", + TorStrings.settings.proxyUsernamePasswordPlaceholder + ); + this._proxyUsernameTextbox.addEventListener("blur", () => { + gTorPane.onUpdateProxySettings(); + }); + this._proxyPasswordLabel = prefpane.querySelector( + selectors.advanced.proxyPasswordLabel + ); + this._proxyPasswordLabel.setAttribute( + "value", + TorStrings.settings.proxyPassword + ); + this._proxyPasswordTextbox = prefpane.querySelector( + selectors.advanced.proxyPasswordTextbox + ); + this._proxyPasswordTextbox.setAttribute( + "placeholder", + TorStrings.settings.proxyUsernamePasswordPlaceholder + ); + this._proxyPasswordTextbox.addEventListener("blur", () => { + gTorPane.onUpdateProxySettings(); + }); + + // Local firewall + this._useFirewallCheckbox = prefpane.querySelector( + selectors.advanced.useFirewallCheckbox + ); + this._useFirewallCheckbox.setAttribute( + "label", + TorStrings.settings.useFirewall + ); + this._useFirewallCheckbox.addEventListener("command", e => { + const checked = this._useFirewallCheckbox.checked; + gTorPane.onToggleFirewall(checked).onUpdateFirewallSettings(); + }); + this._allowedPortsLabel = prefpane.querySelector( + selectors.advanced.firewallAllowedPortsLabel + ); + this._allowedPortsLabel.setAttribute( + "value", + TorStrings.settings.allowedPorts + ); + this._allowedPortsTextbox = prefpane.querySelector( + selectors.advanced.firewallAllowedPortsTextbox + ); + this._allowedPortsTextbox.setAttribute( + "placeholder", + TorStrings.settings.allowedPortsPlaceholder + ); + this._allowedPortsTextbox.addEventListener("blur", () => { + gTorPane.onUpdateFirewallSettings(); + }); + + // Tor logs + prefpane + .querySelector(selectors.advanced.torLogsLabel) + .setAttribute("value", TorStrings.settings.showTorDaemonLogs); + let torLogsButton = prefpane.querySelector( + selectors.advanced.torLogsButton + ); + torLogsButton.setAttribute("label", TorStrings.settings.showLogs); + torLogsButton.addEventListener("command", () => { + gTorPane.onViewTorLogs(); + }); + + // Disable all relevant elements by default + this._setElementsDisabled( + [ + this._builtinBridgeOption, + this._builtinBridgeMenulist, + this._requestBridgeOption, + this._requestBridgeButton, + this._requestBridgeTextarea, + this._provideBridgeOption, + this._provideBridgeTextarea, + this._proxyTypeLabel, + this._proxyTypeMenulist, + this._proxyAddressLabel, + this._proxyAddressTextbox, + this._proxyPortLabel, + this._proxyPortTextbox, + this._proxyUsernameLabel, + this._proxyUsernameTextbox, + this._proxyPasswordLabel, + this._proxyPasswordTextbox, + this._allowedPortsLabel, + this._allowedPortsTextbox, + ], + true + ); + + // init bridge UI + for (let currentBridge of TorBuiltinBridgeTypes) { + let menuEntry = document.createXULElement("menuitem"); + menuEntry.setAttribute("value", currentBridge); + menuEntry.setAttribute("label", currentBridge); + this._builtinBridgeMenulist + .querySelector("menupopup") + .appendChild(menuEntry); + } + + if (TorSettings.bridges.enabled) { + this.onSelectBridgeOption(TorSettings.bridges.source); + this.onToggleBridge( + TorSettings.bridges.source != TorBridgeSource.Invalid + ); + switch (TorSettings.bridges.source) { + case TorBridgeSource.Invalid: + break; + case TorBridgeSource.BuiltIn: + this._builtinBridgeMenulist.value = TorSettings.bridges.builtin_type; + break; + case TorBridgeSource.BridgeDB: + this._requestBridgeTextarea.value = TorSettings.bridges.bridge_strings.join("\n"); + break; + case TorBridgeSource.UserProvided: + this._provideBridgeTextarea.value = TorSettings.bridges.bridge_strings.join("\n"); + break; + } + } + + // init proxy UI + if (TorSettings.proxy.enabled) { + this.onToggleProxy(true); + this.onSelectProxyType(TorSettings.proxy.type); + this._proxyAddressTextbox.value = TorSettings.proxy.address; + this._proxyPortTextbox.value = TorSettings.proxy.port; + this._proxyUsernameTextbox.value = TorSettings.proxy.username; + this._proxyPasswordTextbox.value = TorSettings.proxy.password; + } + + // init firewall + if (TorSettings.firewall.enabled) { + this.onToggleFirewall(true); + this._allowedPortsTextbox.value = TorSettings.firewall.allowed_ports.join(", "); + } + }, + + init() { + this._populateXUL(); + + let onUnload = () => { + window.removeEventListener("unload", onUnload); + gTorPane.uninit(); + }; + window.addEventListener("unload", onUnload); + }, + + uninit() { + // unregister our observer topics + Services.obs.removeObserver(this, TorSettingsTopics.SettingChanged); + Services.obs.removeObserver(this, TorConnectTopics.StateChange); + }, + + // whether the page should be present in about:preferences + get enabled() { + return TorProtocolService.ownsTorDaemon; + }, + + // + // Callbacks + // + + observe(subject, topic, data) { + switch (topic) { + // triggered when a TorSettings param has changed + case TorSettingsTopics.SettingChanged: { + let obj = subject?.wrappedJSObject; + switch(data) { + case TorSettingsData.QuickStartEnabled: { + this._enableQuickstartCheckbox.checked = obj.value; + break; + } + } + break; + } + // triggered when tor connect state changes and we may + // need to update the messagebox + case TorConnectTopics.StateChange: { + this._populateMessagebox(); + break; + } + } + }, + + // callback when using bridges toggled + onToggleBridge(enabled) { + this._useBridgeCheckbox.checked = enabled; + let disabled = !enabled; + + // first disable all the bridge related elements + this._setElementsDisabled( + [ + this._builtinBridgeOption, + this._builtinBridgeMenulist, + this._requestBridgeOption, + this._requestBridgeButton, + this._requestBridgeTextarea, + this._provideBridgeOption, + this._provideBridgeTextarea, + ], + disabled + ); + + // and selectively re-enable based on the radiogroup's current value + if (enabled) { + this.onSelectBridgeOption(this._bridgeSelectionRadiogroup.value); + } else { + this.onSelectBridgeOption(TorBridgeSource.Invalid); + } + return this; + }, + + // callback when a bridge option is selected + onSelectBridgeOption(source) { + if (typeof source === "string") { + source = parseInt(source); + } + + // disable all of the bridge elements under radio buttons + this._setElementsDisabled( + [ + this._builtinBridgeMenulist, + this._requestBridgeButton, + this._requestBridgeTextarea, + this._provideBridgeTextarea, + ], + true + ); + + if (source != TorBridgeSource.Invalid) { + this._bridgeSelectionRadiogroup.value = source; + } + + switch (source) { + case TorBridgeSource.BuiltIn: { + this._setElementsDisabled([this._builtinBridgeMenulist], false); + break; + } + case TorBridgeSource.BridgeDB: { + this._setElementsDisabled( + [this._requestBridgeButton, this._requestBridgeTextarea], + false + ); + break; + } + case TorBridgeSource.UserProvided: { + this._setElementsDisabled([this._provideBridgeTextarea], false); + break; + } + } + return this; + }, + + // called when the request bridge button is activated + onRequestBridge() { + let requestBridgeDialog = new RequestBridgeDialog(); + requestBridgeDialog.openDialog( + gSubDialog, + aBridges => { + if (aBridges.length > 0) { + let bridgeStrings = aBridges.join("\n"); + TorSettings.bridges.enabled = true; + TorSettings.bridges.source = TorBridgeSource.BridgeDB; + TorSettings.bridges.bridge_strings = bridgeStrings; + TorSettings.saveToPrefs(); + TorSettings.applySettings().then((result) => { + this._requestBridgeTextarea.value = bridgeStrings; + }); + } + } + ); + return this; + }, + + // pushes bridge settings from UI to tor + onUpdateBridgeSettings() { + let source = this._useBridgeCheckbox.checked + ? parseInt(this._bridgeSelectionRadiogroup.value) + : TorBridgeSource.Invalid; + + switch (source) { + case TorBridgeSource.Invalid: { + TorSettings.bridges.enabled = false; + } + break; + case TorBridgeSource.BuiltIn: { + // if there is a built-in bridge already selected, use that + let bridgeType = this._builtinBridgeMenulist.value; + console.log(`bridge type: ${bridgeType}`); + if (bridgeType) { + TorSettings.bridges.enabled = true; + TorSettings.bridges.source = TorBridgeSource.BuiltIn; + TorSettings.bridges.builtin_type = bridgeType; + } else { + TorSettings.bridges.enabled = false; + } + break; + } + case TorBridgeSource.BridgeDB: { + // if there are bridgedb bridges saved in the text area, use them + let bridgeStrings = this._requestBridgeTextarea.value; + if (bridgeStrings) { + TorSettings.bridges.enabled = true; + TorSettings.bridges.source = TorBridgeSource.BridgeDB; + TorSettings.bridges.bridge_strings = bridgeStrings; + } else { + TorSettings.bridges.enabled = false; + } + break; + } + case TorBridgeSource.UserProvided: { + // if bridges already exist in the text area, use them + let bridgeStrings = this._provideBridgeTextarea.value; + if (bridgeStrings) { + TorSettings.bridges.enabled = true; + TorSettings.bridges.source = TorBridgeSource.UserProvided; + TorSettings.bridges.bridge_strings = bridgeStrings; + } else { + TorSettings.bridges.enabled = false; + } + break; + } + } + TorSettings.saveToPrefs(); + TorSettings.applySettings(); + + return this; + }, + + // callback when proxy is toggled + onToggleProxy(enabled) { + this._useProxyCheckbox.checked = enabled; + let disabled = !enabled; + + this._setElementsDisabled( + [ + this._proxyTypeLabel, + this._proxyTypeMenulist, + this._proxyAddressLabel, + this._proxyAddressTextbox, + this._proxyPortLabel, + this._proxyPortTextbox, + this._proxyUsernameLabel, + this._proxyUsernameTextbox, + this._proxyPasswordLabel, + this._proxyPasswordTextbox, + ], + disabled + ); + this.onSelectProxyType(this._proxyTypeMenulist.value); + return this; + }, + + // callback when proxy type is changed + onSelectProxyType(value) { + if (typeof value === "string") { + value = parseInt(value); + } + + this._proxyTypeMenulist.value = value; + switch (value) { + case TorProxyType.Invalid: { + this._setElementsDisabled( + [ + this._proxyAddressLabel, + this._proxyAddressTextbox, + this._proxyPortLabel, + this._proxyPortTextbox, + this._proxyUsernameLabel, + this._proxyUsernameTextbox, + this._proxyPasswordLabel, + this._proxyPasswordTextbox, + ], + true + ); // DISABLE + + this._proxyAddressTextbox.value = ""; + this._proxyPortTextbox.value = ""; + this._proxyUsernameTextbox.value = ""; + this._proxyPasswordTextbox.value = ""; + break; + } + case TorProxyType.Socks4: { + this._setElementsDisabled( + [ + this._proxyAddressLabel, + this._proxyAddressTextbox, + this._proxyPortLabel, + this._proxyPortTextbox, + ], + false + ); // ENABLE + this._setElementsDisabled( + [ + this._proxyUsernameLabel, + this._proxyUsernameTextbox, + this._proxyPasswordLabel, + this._proxyPasswordTextbox, + ], + true + ); // DISABLE + + this._proxyUsernameTextbox.value = ""; + this._proxyPasswordTextbox.value = ""; + break; + } + case TorProxyType.Socks5: + case TorProxyType.HTTPS: { + this._setElementsDisabled( + [ + this._proxyAddressLabel, + this._proxyAddressTextbox, + this._proxyPortLabel, + this._proxyPortTextbox, + this._proxyUsernameLabel, + this._proxyUsernameTextbox, + this._proxyPasswordLabel, + this._proxyPasswordTextbox, + ], + false + ); // ENABLE + break; + } + } + return this; + }, + + // pushes proxy settings from UI to tor + onUpdateProxySettings() { + const type = this._useProxyCheckbox.checked + ? parseInt(this._proxyTypeMenulist.value) + : TorProxyType.Invalid; + const address = this._proxyAddressTextbox.value; + const port = this._proxyPortTextbox.value; + const username = this._proxyUsernameTextbox.value; + const password = this._proxyPasswordTextbox.value; + + switch (type) { + case TorProxyType.Invalid: + TorSettings.proxy.enabled = false; + break; + case TorProxyType.Socks4: + TorSettings.proxy.enabled = true; + TorSettings.proxy.type = type; + TorSettings.proxy.address = address; + TorSettings.proxy.port = port; + + break; + case TorProxyType.Socks5: + TorSettings.proxy.enabled = true; + TorSettings.proxy.type = type; + TorSettings.proxy.address = address; + TorSettings.proxy.port = port; + TorSettings.proxy.username = username; + TorSettings.proxy.password = password; + break; + case TorProxyType.HTTPS: + TorSettings.proxy.enabled = true; + TorSettings.proxy.type = type; + TorSettings.proxy.address = address; + TorSettings.proxy.port = port; + TorSettings.proxy.username = username; + TorSettings.proxy.password = password; + break; + } + TorSettings.saveToPrefs(); + TorSettings.applySettings(); + + return this; + }, + + // callback when firewall proxy is toggled + onToggleFirewall(enabled) { + this._useFirewallCheckbox.checked = enabled; + let disabled = !enabled; + + this._setElementsDisabled( + [this._allowedPortsLabel, this._allowedPortsTextbox], + disabled + ); + + return this; + }, + + // pushes firewall settings from UI to tor + onUpdateFirewallSettings() { + + let portListString = this._useFirewallCheckbox.checked + ? this._allowedPortsTextbox.value + : ""; + + if (portListString) { + TorSettings.firewall.enabled = true; + TorSettings.firewall.allowed_ports = portListString; + } else { + TorSettings.firewall.enabled = false; + } + TorSettings.saveToPrefs(); + TorSettings.applySettings(); + + return this; + }, + + onViewTorLogs() { + let torLogDialog = new TorLogDialog(); + torLogDialog.openDialog(gSubDialog); + }, + }; + return retval; +})(); /* gTorPane */ diff --git a/browser/components/torpreferences/content/torPane.xhtml b/browser/components/torpreferences/content/torPane.xhtml new file mode 100644 index 000000000000..7c8071f2cf10 --- /dev/null +++ b/browser/components/torpreferences/content/torPane.xhtml @@ -0,0 +1,157 @@ +<!-- Tor panel --> + +<script type="application/javascript" + src="chrome://browser/content/torpreferences/torPane.js"/> +<html:template id="template-paneTor"> + +<!-- Tor Connect Message Box --> +<groupbox data-category="paneTor" hidden="true"> + <html:div id="torPreferences-connectMessageBox" + class="subcategory" + data-category="paneTor" + hidden="true"> + <html:table > + <html:tr> + <html:td> + <html:div id="torPreferences-connectMessageBox-icon"/> + </html:td> + <html:td id="torPreferences-connectMessageBox-message"> + </html:td> + <html:td> + <html:button id="torPreferences-connectMessageBox-button"> + </html:button> + </html:td> + </html:tr> + </html:table> + </html:div> +</groupbox> + +<hbox id="torPreferencesCategory" + class="subcategory" + data-category="paneTor" + hidden="true"> + <html:h1 id="torPreferences-header"/> +</hbox> + +<groupbox data-category="paneTor" + hidden="true"> + <description flex="1"> + <html:span id="torPreferences-description" class="tail-with-learn-more"/> + <label id="torPreferences-learnMore" class="learnMore text-link" is="text-link"/> + </description> +</groupbox> + +<!-- Quickstart --> +<groupbox id="torPreferences-quickstart-group" + data-category="paneTor" + hidden="true"> + <html:h2 id="torPreferences-quickstart-header"/> + <description flex="1"> + <html:span id="torPreferences-quickstart-description"/> + </description> + <checkbox id="torPreferences-quickstart-toggle"/> +</groupbox> + +<!-- Bridges --> +<groupbox id="torPreferences-bridges-group" + data-category="paneTor" + hidden="true"> + <html:h2 id="torPreferences-bridges-header"/> + <description flex="1"> + <html:span id="torPreferences-bridges-description" class="tail-with-learn-more"/> + <label id="torPreferences-bridges-learnMore" class="learnMore text-link" is="text-link"/> + </description> + <checkbox id="torPreferences-bridges-toggle"/> + <radiogroup id="torPreferences-bridges-bridgeSelection"> + <hbox class="indent"> + <radio id="torPreferences-bridges-radioBuiltin"/> + <spacer flex="1"/> + <menulist id="torPreferences-bridges-builtinList" class="torMarginFix"> + <menupopup/> + </menulist> + </hbox> + <vbox class="indent"> + <hbox> + <radio id="torPreferences-bridges-radioRequestBridge"/> + <space flex="1"/> + <button id="torPreferences-bridges-buttonRequestBridge" class="torMarginFix"/> + </hbox> + <html:textarea + id="torPreferences-bridges-textareaRequestBridge" + class="indent torMarginFix" + multiline="true" + rows="3" + readonly="true"/> + </vbox> + <hbox class="indent" flex="1"> + <vbox flex="1"> + <radio id="torPreferences-bridges-radioProvideBridge"/> + <description id="torPreferences-bridges-descriptionProvideBridge" class="indent"/> + <html:textarea + id="torPreferences-bridges-textareaProvideBridge" + class="indent torMarginFix" + multiline="true" + rows="3"/> + </vbox> + </hbox> + </radiogroup> +</groupbox> + +<!-- Advanced --> +<groupbox id="torPreferences-advanced-group" + data-category="paneTor" + hidden="true"> + <html:h2 id="torPreferences-advanced-header"/> + <description flex="1"> + <html:span id="torPreferences-advanced-description" class="tail-with-learn-more"/> + <label id="torPreferences-advanced-learnMore" class="learnMore text-link" is="text-link" style="display:none"/> + </description> + <box id="torPreferences-advanced-grid"> + <!-- Local Proxy --> + <hbox class="torPreferences-advanced-checkbox-container"> + <checkbox id="torPreferences-advanced-toggleProxy"/> + </hbox> + <hbox class="indent" align="center"> + <label id="torPreferences-localProxy-type"/> + </hbox> + <hbox align="center"> + <spacer flex="1"/> + <menulist id="torPreferences-localProxy-builtinList" class="torMarginFix"> + <menupopup/> + </menulist> + </hbox> + <hbox class="indent" align="center"> + <label id="torPreferences-localProxy-address"/> + </hbox> + <hbox align="center"> + <html:input id="torPreferences-localProxy-textboxAddress" type="text" class="torMarginFix"/> + <label id="torPreferences-localProxy-port"/> + <!-- proxy-port-input class style pulled from preferences.css and used in the vanilla proxy setup menu --> + <html:input id="torPreferences-localProxy-textboxPort" class="proxy-port-input torMarginFix" hidespinbuttons="true" type="number" min="0" max="65535" maxlength="5"/> + </hbox> + <hbox class="indent" align="center"> + <label id="torPreferences-localProxy-username"/> + </hbox> + <hbox align="center"> + <html:input id="torPreferences-localProxy-textboxUsername" type="text" class="torMarginFix"/> + <label id="torPreferences-localProxy-password"/> + <html:input id="torPreferences-localProxy-textboxPassword" class="torMarginFix" type="password"/> + </hbox> + <!-- Firewall --> + <hbox class="torPreferences-advanced-checkbox-container"> + <checkbox id="torPreferences-advanced-toggleFirewall"/> + </hbox> + <hbox class="indent" align="center"> + <label id="torPreferences-advanced-allowedPorts"/> + </hbox> + <hbox align="center"> + <html:input id="torPreferences-advanced-textboxAllowedPorts" type="text" class="torMarginFix" value="80,443"/> + </hbox> + </box> + <hbox id="torPreferences-torDaemon-hbox" align="center"> + <label id="torPreferences-torLogs"/> + <spacer flex="1"/> + <button id="torPreferences-buttonTorLogs" class="torMarginFix"/> + </hbox> +</groupbox> +</html:template> \ No newline at end of file diff --git a/browser/components/torpreferences/content/torPreferences.css b/browser/components/torpreferences/content/torPreferences.css new file mode 100644 index 000000000000..b6eb0a740e5e --- /dev/null +++ b/browser/components/torpreferences/content/torPreferences.css @@ -0,0 +1,189 @@ +@import url("chrome://branding/content/tor-styles.css"); + +#category-tor > .category-icon { + list-style-image: url("chrome://browser/content/torpreferences/torPreferencesIcon.svg"); +} + +/* Connect Message Box */ + +#torPreferences-connectMessageBox { + display: block; + position: relative; + + width: auto; + min-height: 32px; + border-radius: 4px; + padding: 8px; +} + +#torPreferences-connectMessageBox.hidden { + display: none; +} + +#torPreferences-connectMessageBox.error { + background-color: var(--red-60); + color: white; +} + +#torPreferences-connectMessageBox.warning { + background-color: var(--purple-50); + color: white; +} + +#torPreferences-connectMessageBox table { + border-collapse: collapse; +} + +#torPreferences-connectMessageBox td { + vertical-align: middle; +} + +#torPreferences-connectMessageBox td:first-child { + width: 16px; +} + +#torPreferences-connectMessageBox-icon { + width: 16px; + height: 16px; + + mask-repeat: no-repeat !important; + mask-size: 16px !important; +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-icon +{ + mask: url("chrome://browser/skin/onion-slash.svg"); + background-color: white; +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-icon +{ + mask: url("chrome://browser/skin/onion.svg"); + background-color: white; +} + +#torPreferences-connectMessageBox-message { + line-height: 16px; + font-size: 1.11em; + padding-left: 8px!important; +} + +#torPreferences-connectMessageBox-button { + display: block; + width: auto; + + border-radius: 4px; + border: 0; + + padding-inline: 18px; + padding-block: 8px; + margin-block: 0px; + margin-inline-start: 8px; + margin-inline-end: 0px; + + font-size: 1.0em; + font-weight: 600; + white-space: nowrap; + + color: white; +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button { + background-color: var(--red-70); +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button:hover { + background-color: var(--red-80); +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button:active { + background-color: var(--red-90); +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button { + background-color: var(--purple-70); +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:hover { + background-color: var(--purple-80); +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:active { + background-color: var(--purple-90); +} + +/* Advanced Settings */ + +#torPreferences-advanced-grid { + display: grid; + grid-template-columns: auto 1fr; +} + +.torPreferences-advanced-checkbox-container { + grid-column: 1 / 3; +} + +#torPreferences-localProxy-textboxAddress, +#torPreferences-localProxy-textboxUsername, +#torPreferences-localProxy-textboxPassword, +#torPreferences-advanced-textboxAllowedPorts { + -moz-box-flex: 1; +} + +hbox#torPreferences-torDaemon-hbox { + margin-top: 20px; +} + +description#torPreferences-requestBridge-description { + /*margin-bottom: 1em;*/ + min-height: 2em; +} + +image#torPreferences-requestBridge-captchaImage { + margin: 1em; + min-height: 125px; +} + +button#torPreferences-requestBridge-refreshCaptchaButton { + min-width: initial; +} + +dialog#torPreferences-requestBridge-dialog > hbox { + margin-bottom: 1em; +} + +/* + Various elements that really should be lining up don't because they have inconsistent margins +*/ +.torMarginFix { + margin-left : 4px; + margin-right : 4px; +} + +/* + This hbox is hidden by css here by default so that the + xul dialog allocates enough screen space for the error message + element, otherwise it gets cut off since dialog's overflow is hidden +*/ +hbox#torPreferences-requestBridge-incorrectCaptchaHbox { + visibility: hidden; +} + +image#torPreferences-requestBridge-errorIcon { + list-style-image: url("chrome://browser/skin/warning.svg"); +} + +groupbox#torPreferences-bridges-group textarea { + white-space: pre; + overflow: auto; +} + +textarea#torPreferences-torDialog-textarea { + -moz-box-flex: 1; + font-family: monospace; + font-size: 0.8em; + white-space: pre; + overflow: auto; + /* 10 lines */ + min-height: 20em; +} \ No newline at end of file diff --git a/browser/components/torpreferences/content/torPreferencesIcon.svg b/browser/components/torpreferences/content/torPreferencesIcon.svg new file mode 100644 index 000000000000..382a061774aa --- /dev/null +++ b/browser/components/torpreferences/content/torPreferencesIcon.svg @@ -0,0 +1,8 @@ +<svg fill="context-fill" fill-opacity="context-fill-opacity" viewBox="0 0 16 16" width="16" height="16" xmlns="http://www.w3.org/2000/svg"> + <g clip-rule="evenodd" fill-rule="evenodd"> + <path d="m11 8c0 1.65686-1.34314 3-3 3-1.65685 0-3-1.34314-3-3 0-1.65685 1.34315-3 3-3 1.65686 0 3 1.34315 3 3zm-1.17187 0c0 1.00965-.81848 1.82813-1.82813 1.82813-1.00964 0-1.82812-.81848-1.82812-1.82813 0-1.00964.81848-1.82812 1.82812-1.82812 1.00965 0 1.82813.81848 1.82813 1.82812z"/> + <path d="m7.99999 13.25c2.89951 0 5.25001-2.3505 5.25001-5.25001 0-2.89949-2.3505-5.25-5.25001-5.25-2.89949 0-5.25 2.35051-5.25 5.25 0 2.89951 2.35051 5.25001 5.25 5.25001zm0-1.1719c2.25231 0 4.07811-1.8258 4.07811-4.07811 0-2.25228-1.8258-4.07812-4.07811-4.07812-2.25228 0-4.07812 1.82584-4.07812 4.07812 0 2.25231 1.82584 4.07811 4.07812 4.07811z"/> + <path d="m8 15.5c4.1421 0 7.5-3.3579 7.5-7.5 0-4.14214-3.3579-7.5-7.5-7.5-4.14214 0-7.5 3.35786-7.5 7.5 0 4.1421 3.35786 7.5 7.5 7.5zm0-1.1719c3.4949 0 6.3281-2.8332 6.3281-6.3281 0-3.49493-2.8332-6.32812-6.3281-6.32812-3.49493 0-6.32812 2.83319-6.32812 6.32812 0 3.4949 2.83319 6.3281 6.32812 6.3281z"/> + </g> + <path d="m.5 8c0 4.1421 3.35786 7.5 7.5 7.5v-15c-4.14214 0-7.5 3.35786-7.5 7.5z"/> +</svg> \ No newline at end of file diff --git a/browser/components/torpreferences/jar.mn b/browser/components/torpreferences/jar.mn new file mode 100644 index 000000000000..552c92b2feff --- /dev/null +++ b/browser/components/torpreferences/jar.mn @@ -0,0 +1,10 @@ +browser.jar: + content/browser/torpreferences/requestBridgeDialog.xhtml (content/requestBridgeDialog.xhtml) + content/browser/torpreferences/requestBridgeDialog.jsm (content/requestBridgeDialog.jsm) + content/browser/torpreferences/torCategory.inc.xhtml (content/torCategory.inc.xhtml) + content/browser/torpreferences/torLogDialog.jsm (content/torLogDialog.jsm) + content/browser/torpreferences/torLogDialog.xhtml (content/torLogDialog.xhtml) + content/browser/torpreferences/torPane.js (content/torPane.js) + content/browser/torpreferences/torPane.xhtml (content/torPane.xhtml) + content/browser/torpreferences/torPreferences.css (content/torPreferences.css) + content/browser/torpreferences/torPreferencesIcon.svg (content/torPreferencesIcon.svg) diff --git a/browser/components/torpreferences/moz.build b/browser/components/torpreferences/moz.build new file mode 100644 index 000000000000..2661ad7cb9f3 --- /dev/null +++ b/browser/components/torpreferences/moz.build @@ -0,0 +1 @@ +JAR_MANIFESTS += ["jar.mn"]
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • ...
  • 782
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.