tbb-commits
Threads by month
- ----- 2025 -----
- 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
July 2021
- 4 participants
- 523 discussions

[tor-browser/tor-browser-91.0b5-11.0-1] Bug 21724: Make Firefox and Tor Browser distinct macOS apps
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit db961a36965e3bc6eb607c3efadaf593f5ab30a9
Author: teor <teor2345(a)gmail.com>
Date: Mon Mar 13 23:06:23 2017 +1100
Bug 21724: Make Firefox and Tor Browser distinct macOS apps
When macOS opens a document or selects a default browser, it sometimes
uses the CFBundleSignature. Changing from the Firefox MOZB signature to
a different signature TORB allows macOS to distinguish between Firefox
and Tor Browser.
---
browser/app/Makefile.in | 2 +…
[View More]-
browser/app/macbuild/Contents/Info.plist.in | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in
index 54d6b43fe126..8dd3a9a65661 100644
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -102,5 +102,5 @@ ifdef MOZ_UPDATER
mv -f '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' '$(dist_dest)/Contents/Library/LaunchServices'
ln -s ../../../../Library/LaunchServices/org.mozilla.updater '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater'
endif
- printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo'
+ printf APPLTORB > '$(dist_dest)/Contents/PkgInfo'
endif
diff --git a/browser/app/macbuild/Contents/Info.plist.in b/browser/app/macbuild/Contents/Info.plist.in
index 9ceaf88f15c1..d8858e9f01bf 100644
--- a/browser/app/macbuild/Contents/Info.plist.in
+++ b/browser/app/macbuild/Contents/Info.plist.in
@@ -179,7 +179,7 @@
<key>CFBundleShortVersionString</key>
<string>@APP_VERSION@</string>
<key>CFBundleSignature</key>
- <string>MOZB</string>
+ <string>TORB</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
[View Less]
1
0

[tor-browser/tor-browser-91.0b5-11.0-1] Bug 19121: reinstate the update.xml hash check
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 800023adf89d03cd517da9c43fbeefa14f815dc6
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Mon Apr 23 15:22:57 2018 -0400
Bug 19121: reinstate the update.xml hash check
Revert most changes from Mozilla Bug 1373267 "Remove hashFunction and
hashValue attributes from nsIUpdatePatch and code related to these
attributes." Changes to the tests were not reverted; the tests have
been changed significantly and we do not run automated updater tests
for Tor …
[View More]Browser at this time.
Also partial revert of commit f1241db6986e4b54473a1ed870f7584c75d51122.
Revert the nsUpdateService.js changes from Mozilla Bug 862173 "don't
verify mar file hash when using mar signing to verify the mar file
(lessens main thread I/O)."
Changes to the tests were not reverted; the tests have been changed
significantly and we do not run automated updater tests for
Tor Browser at this time.
We kept the addition to the AppConstants API in case other JS code
references it in the future.
---
toolkit/modules/AppConstants.jsm | 7 ++++
toolkit/mozapps/update/UpdateService.jsm | 63 ++++++++++++++++++++++++++++-
toolkit/mozapps/update/UpdateTelemetry.jsm | 1 +
toolkit/mozapps/update/nsIUpdateService.idl | 11 +++++
4 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm
index 6adc706952e3..63c7ef6f3402 100644
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -205,6 +205,13 @@ this.AppConstants = Object.freeze({
false,
#endif
+ MOZ_VERIFY_MAR_SIGNATURE:
+#ifdef MOZ_VERIFY_MAR_SIGNATURE
+ true,
+#else
+ false,
+#endif
+
MOZ_MAINTENANCE_SERVICE:
#ifdef MOZ_MAINTENANCE_SERVICE
true,
diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm
index 4d1b1c59eff5..10581c785074 100644
--- a/toolkit/mozapps/update/UpdateService.jsm
+++ b/toolkit/mozapps/update/UpdateService.jsm
@@ -969,6 +969,20 @@ function LOG(string) {
}
}
+/**
+ * Convert a string containing binary values to hex.
+ */
+function binaryToHex(input) {
+ var result = "";
+ for (var i = 0; i < input.length; ++i) {
+ var hex = input.charCodeAt(i).toString(16);
+ if (hex.length == 1)
+ hex = "0" + hex;
+ result += hex;
+ }
+ return result;
+}
+
/**
* Gets the specified directory at the specified hierarchy under the
* update root directory and creates it if it doesn't exist.
@@ -1988,6 +2002,8 @@ function UpdatePatch(patch) {
}
break;
case "finalURL":
+ case "hashFunction":
+ case "hashValue":
case "state":
case "type":
case "URL":
@@ -2007,6 +2023,8 @@ UpdatePatch.prototype = {
// over writing nsIUpdatePatch attributes.
_attrNames: [
"errorCode",
+ "hashFunction",
+ "hashValue",
"finalURL",
"selected",
"size",
@@ -2020,6 +2038,8 @@ UpdatePatch.prototype = {
*/
serialize: function UpdatePatch_serialize(updates) {
var patch = updates.createElementNS(URI_UPDATE_NS, "patch");
+ patch.setAttribute("hashFunction", this.hashFunction);
+ patch.setAttribute("hashValue", this.hashValue);
patch.setAttribute("size", this.size);
patch.setAttribute("type", this.type);
patch.setAttribute("URL", this.URL);
@@ -5122,7 +5142,42 @@ Downloader.prototype = {
}
LOG("Downloader:_verifyDownload downloaded size == expected size.");
- return true;
+ let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
+ createInstance(Ci.nsIFileInputStream);
+ fileStream.init(destination, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
+
+ let digest;
+ try {
+ let hash = Cc["@mozilla.org/security/hash;1"].
+ createInstance(Ci.nsICryptoHash);
+ var hashFunction = Ci.nsICryptoHash[this._patch.hashFunction.toUpperCase()];
+ if (hashFunction == undefined) {
+ throw Cr.NS_ERROR_UNEXPECTED;
+ }
+ hash.init(hashFunction);
+ hash.updateFromStream(fileStream, -1);
+ // NOTE: For now, we assume that the format of _patch.hashValue is hex
+ // encoded binary (such as what is typically output by programs like
+ // sha1sum). In the future, this may change to base64 depending on how
+ // we choose to compute these hashes.
+ digest = binaryToHex(hash.finish(false));
+ } catch (e) {
+ LOG("Downloader:_verifyDownload - failed to compute hash of the " +
+ "downloaded update archive");
+ digest = "";
+ }
+
+ fileStream.close();
+
+ if (digest == this._patch.hashValue.toLowerCase()) {
+ LOG("Downloader:_verifyDownload hashes match.");
+ return true;
+ }
+
+ LOG("Downloader:_verifyDownload hashes do not match. ");
+ AUSTLMY.pingDownloadCode(this.isCompleteUpdate,
+ AUSTLMY.DWNLD_ERR_VERIFY_NO_HASH_MATCH);
+ return false;
},
/**
@@ -5719,6 +5774,9 @@ Downloader.prototype = {
" is higher than patch size: " +
this._patch.size
);
+ // It's important that we use a different code than
+ // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference
+ // between a hash error and a wrong download error.
AUSTLMY.pingDownloadCode(
this.isCompleteUpdate,
AUSTLMY.DWNLD_ERR_PATCH_SIZE_LARGER
@@ -5737,6 +5795,9 @@ Downloader.prototype = {
" is not equal to expected patch size: " +
this._patch.size
);
+ // It's important that we use a different code than
+ // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference
+ // between a hash error and a wrong download error.
AUSTLMY.pingDownloadCode(
this.isCompleteUpdate,
AUSTLMY.DWNLD_ERR_PATCH_SIZE_NOT_EQUAL
diff --git a/toolkit/mozapps/update/UpdateTelemetry.jsm b/toolkit/mozapps/update/UpdateTelemetry.jsm
index dae76e09acd0..df5b8917970e 100644
--- a/toolkit/mozapps/update/UpdateTelemetry.jsm
+++ b/toolkit/mozapps/update/UpdateTelemetry.jsm
@@ -192,6 +192,7 @@ var AUSTLMY = {
DWNLD_ERR_VERIFY_NO_REQUEST: 13,
DWNLD_ERR_VERIFY_PATCH_SIZE_NOT_EQUAL: 14,
DWNLD_ERR_WRITE_FAILURE: 15,
+ DWNLD_ERR_VERIFY_NO_HASH_MATCH: 16,
// Temporary failure code to see if there are failures without an update phase
DWNLD_UNKNOWN_PHASE_ERR_WRITE_FAILURE: 40,
diff --git a/toolkit/mozapps/update/nsIUpdateService.idl b/toolkit/mozapps/update/nsIUpdateService.idl
index 78929e1cef44..5db1db71fc81 100644
--- a/toolkit/mozapps/update/nsIUpdateService.idl
+++ b/toolkit/mozapps/update/nsIUpdateService.idl
@@ -39,6 +39,17 @@ interface nsIUpdatePatch : nsISupports
*/
attribute AString finalURL;
+ /**
+ * The hash function to use when determining this file's integrity
+ */
+ attribute AString hashFunction;
+
+ /**
+ * The value of the hash function named above that should be computed if
+ * this file is not corrupt.
+ */
+ attribute AString hashValue;
+
/**
* The size of this file, in bytes.
*/
[View Less]
1
0

[tor-browser/tor-browser-91.0b5-11.0-1] Bug 13379: Sign our MAR files.
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 61df8fedbedc1185b2c2f49954fba1706783bdb8
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Wed Dec 17 16:37:11 2014 -0500
Bug 13379: Sign our MAR files.
Configure with --enable-verify-mar (when updating, require a valid
signature on the MAR file before it is applied).
Use the Tor Browser version instead of the Firefox version inside the
MAR file info block (necessary to prevent downgrade attacks).
Use NSS on all platforms for checking MAR …
[View More]signatures (instead of using
OS-native APIs, which Mozilla does on Mac OS and Windows). So that the
NSS and NSPR libraries the updater depends on can be found at runtime,
we add the firefox directory to the shared library search path on macOS.
On Linux, rpath is used by Mozilla to solve that problem, but that
approach won't work on macOS because the updater executable is copied
during the update process to a location that is under TorBrowser-Data,
and the location of TorBrowser-Data varies.
Also includes the fix for bug 18900.
---
.mozconfig | 1 +
.mozconfig-asan | 1 +
.mozconfig-mac | 1 +
.mozconfig-mingw | 1 +
modules/libmar/tool/mar.c | 6 +--
modules/libmar/tool/moz.build | 12 ++++--
modules/libmar/verify/moz.build | 14 +++---
.../mozapps/update/updater/updater-common.build | 26 +++++++++--
toolkit/mozapps/update/updater/updater.cpp | 25 +++++++----
toolkit/xre/moz.build | 3 ++
toolkit/xre/nsUpdateDriver.cpp | 50 ++++++++++++++++++++++
11 files changed, 115 insertions(+), 25 deletions(-)
diff --git a/.mozconfig b/.mozconfig
index 18cd1f9b6487..c50c57d410de 100755
--- a/.mozconfig
+++ b/.mozconfig
@@ -37,3 +37,4 @@ 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
+ac_add_options --enable-verify-mar
diff --git a/.mozconfig-asan b/.mozconfig-asan
index bad7ea022c9f..e42ff6c86bc5 100644
--- a/.mozconfig-asan
+++ b/.mozconfig-asan
@@ -29,6 +29,7 @@ ac_add_options --enable-official-branding
ac_add_options --enable-default-toolkit=cairo-gtk3
ac_add_options --enable-tor-browser-update
+ac_add_options --enable-verify-mar
ac_add_options --disable-strip
ac_add_options --disable-install-strip
diff --git a/.mozconfig-mac b/.mozconfig-mac
index 26e2b6b92fdb..5b4624ef1f67 100644
--- a/.mozconfig-mac
+++ b/.mozconfig-mac
@@ -43,6 +43,7 @@ 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 --enable-verify-mar
ac_add_options --disable-crashreporter
ac_add_options --disable-webrtc
diff --git a/.mozconfig-mingw b/.mozconfig-mingw
index 3ec6ff18a3e9..ce6ace1dad67 100644
--- a/.mozconfig-mingw
+++ b/.mozconfig-mingw
@@ -15,6 +15,7 @@ ac_add_options --enable-strip
ac_add_options --enable-official-branding
ac_add_options --enable-tor-browser-update
+ac_add_options --enable-verify-mar
ac_add_options --disable-bits-download
# Let's make sure no preference is enabling either Adobe's or Google's CDM.
diff --git a/modules/libmar/tool/mar.c b/modules/libmar/tool/mar.c
index 0bf2cb4bd1d4..ea2b79924914 100644
--- a/modules/libmar/tool/mar.c
+++ b/modules/libmar/tool/mar.c
@@ -65,7 +65,7 @@ static void print_usage() {
"signed_input_archive.mar base_64_encoded_signature_file "
"changed_signed_output.mar\n");
printf("(i) is the index of the certificate to extract\n");
-# if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(MAR_NSS))
+# if (defined(XP_MACOSX) || defined(XP_WIN)) && !defined(MAR_NSS)
printf("Verify a MAR file:\n");
printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
printf(
@@ -149,7 +149,7 @@ int main(int argc, char** argv) {
memset((void*)certBuffers, 0, sizeof(certBuffers));
#endif
#if !defined(NO_SIGN_VERIFY) && \
- ((!defined(MAR_NSS) && defined(XP_WIN)) || defined(XP_MACOSX))
+ (!defined(MAR_NSS) && (defined(XP_WIN) || defined(XP_MACOSX)))
memset(DERFilePaths, 0, sizeof(DERFilePaths));
memset(fileSizes, 0, sizeof(fileSizes));
#endif
@@ -181,7 +181,7 @@ int main(int argc, char** argv) {
argc -= 2;
}
#if !defined(NO_SIGN_VERIFY)
-# if (!defined(MAR_NSS) && defined(XP_WIN)) || defined(XP_MACOSX)
+# if (!defined(MAR_NSS) && (defined(XP_WIN) || defined(XP_MACOSX)))
/* -D DERFilePath, also matches -D[index] DERFilePath
We allow an index for verifying to be symmetric
with the import and export command line arguments. */
diff --git a/modules/libmar/tool/moz.build b/modules/libmar/tool/moz.build
index a6d26c66a668..d6fa1677ddf1 100644
--- a/modules/libmar/tool/moz.build
+++ b/modules/libmar/tool/moz.build
@@ -43,15 +43,21 @@ if CONFIG["MOZ_BUILD_APP"] != "tools/update-packaging":
"verifymar",
]
+ if CONFIG["TOR_BROWSER_UPDATE"]:
+ DEFINES["MAR_NSS"] = True
+
if CONFIG["OS_ARCH"] == "WINNT":
USE_STATIC_LIBS = True
OS_LIBS += [
"ws2_32",
- "crypt32",
- "advapi32",
]
- elif CONFIG["OS_ARCH"] == "Darwin":
+ if not CONFIG["TOR_BROWSER_UPDATE"]:
+ OS_LIBS += [
+ "crypt32",
+ "advapi32",
+ ]
+ elif CONFIG["OS_ARCH"] == "Darwin" and not CONFIG["TOR_BROWSER_UPDATE"]:
OS_LIBS += [
"-framework Security",
]
diff --git a/modules/libmar/verify/moz.build b/modules/libmar/verify/moz.build
index b07475655f0d..03718eee50b4 100644
--- a/modules/libmar/verify/moz.build
+++ b/modules/libmar/verify/moz.build
@@ -16,15 +16,12 @@ FORCE_STATIC_LIB = True
if CONFIG["OS_ARCH"] == "WINNT":
USE_STATIC_LIBS = True
elif CONFIG["OS_ARCH"] == "Darwin":
- UNIFIED_SOURCES += [
- "MacVerifyCrypto.cpp",
- ]
- OS_LIBS += [
- "-framework Security",
+ USE_LIBS += [
+ "nspr",
+ "nss",
+ "signmar",
]
else:
- DEFINES["MAR_NSS"] = True
- LOCAL_INCLUDES += ["../sign"]
USE_LIBS += [
"nspr",
"nss",
@@ -38,6 +35,9 @@ else:
"-Wl,-rpath=\\$$ORIGIN",
]
+DEFINES["MAR_NSS"] = True
+LOCAL_INCLUDES += ["../sign"]
+
LOCAL_INCLUDES += [
"../src",
]
diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build
index 13926ea82046..c9ef02bbe291 100644
--- a/toolkit/mozapps/update/updater/updater-common.build
+++ b/toolkit/mozapps/update/updater/updater-common.build
@@ -4,6 +4,12 @@
# 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/.
+DEFINES["MAR_NSS"] = True
+
+link_with_nss = DEFINES["MAR_NSS"] or (
+ CONFIG["OS_ARCH"] == "Linux" and CONFIG["MOZ_VERIFY_MAR_SIGNATURE"]
+)
+
srcs = [
"archivereader.cpp",
"updater.cpp",
@@ -36,10 +42,14 @@ if CONFIG["OS_ARCH"] == "WINNT":
"ws2_32",
"shell32",
"shlwapi",
- "crypt32",
- "advapi32",
]
+ if not link_with_nss:
+ OS_LIBS += [
+ "crypt32",
+ "advapi32",
+ ]
+
USE_LIBS += [
"bspatch",
"mar",
@@ -47,6 +57,13 @@ USE_LIBS += [
"xz-embedded",
]
+if link_with_nss:
+ USE_LIBS += [
+ "nspr",
+ "nss",
+ "signmar",
+ ]
+
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
have_progressui = 1
srcs += [
@@ -61,9 +78,12 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
]
OS_LIBS += [
"-framework Cocoa",
- "-framework Security",
"-framework SystemConfiguration",
]
+ if not link_with_nss:
+ OS_LIBS += [
+ "-framework Security",
+ ]
UNIFIED_SOURCES += [
"/toolkit/xre/updaterfileutils_osx.mm",
]
diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp
index d22233066157..ddbcdf5cc22a 100644
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -110,9 +110,11 @@ struct UpdateServerThreadArgs {
# define stat64 stat
#endif
-#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX)
-# include "nss.h"
-# include "prerror.h"
+#if defined(MOZ_VERIFY_MAR_SIGNATURE)
+# if defined(MAR_NSS) || (!defined(XP_WIN) && !defined(XP_MACOSX))
+# include "nss.h"
+# include "prerror.h"
+# endif
#endif
#include "crctable.h"
@@ -2732,8 +2734,13 @@ static void UpdateThreadFunc(void* param) {
if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
rv = UPDATE_SETTINGS_FILE_CHANNEL;
} else {
+# ifdef TOR_BROWSER_UPDATE
+ const char* appVersion = TOR_BROWSER_VERSION_QUOTED;
+# else
+ const char* appVersion = MOZ_APP_VERSION;
+# endif
rv = gArchiveReader.VerifyProductInformation(
- MARStrings.MARChannelID.get(), MOZ_APP_VERSION);
+ MARStrings.MARChannelID.get(), appVersion);
}
}
}
@@ -2963,11 +2970,10 @@ int NS_main(int argc, NS_tchar** argv) {
}
#endif
-#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX)
- // On Windows and Mac we rely on native APIs to do verifications so we don't
- // need to initialize NSS at all there.
- // Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS
- // databases.
+#if defined(MOZ_VERIFY_MAR_SIGNATURE)
+# if defined(MAR_NSS) || (!defined(XP_WIN) && !defined(XP_MACOSX))
+ // If using NSS for signature verification, initialize NSS but minimize
+ // the portion we depend on by avoiding all of the NSS databases.
if (NSS_NoDB_Init(nullptr) != SECSuccess) {
PRErrorCode error = PR_GetError();
fprintf(stderr, "Could not initialize NSS: %s (%d)", PR_ErrorToName(error),
@@ -2975,6 +2981,7 @@ int NS_main(int argc, NS_tchar** argv) {
_exit(1);
}
#endif
+#endif
#ifdef XP_MACOSX
if (!isElevated) {
diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build
index 90d06481ee9e..53883cbf196f 100644
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -233,6 +233,9 @@ for var in ("APP_VERSION", "APP_ID"):
if CONFIG["MOZ_BUILD_APP"] == "browser":
DEFINES["MOZ_BUILD_APP_IS_BROWSER"] = True
+if CONFIG["TOR_BROWSER_UPDATE"]:
+ DEFINES["MAR_NSS"] = True
+
LOCAL_INCLUDES += [
"../../other-licenses/nsis/Contrib/CityHash/cityhash",
"../components/find",
diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp
index f83f28288786..4d2ca85928a9 100644
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -366,6 +366,42 @@ static nsresult GetUpdateDirFromAppDir(nsIFile* aAppDir, nsIFile** aResult) {
# endif
#endif
+#if defined(TOR_BROWSER_UPDATE) && defined(MOZ_VERIFY_MAR_SIGNATURE) && \
+ defined(MAR_NSS) && defined(XP_MACOSX)
+/**
+ * Ideally we would save and restore the original library path value after
+ * the updater finishes its work (and before firefox is re-launched).
+ * Doing so would avoid potential problems like the following bug:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1434033
+ */
+/**
+ * Appends the specified path to the library path.
+ * This is used so that the updater can find libnss3.dylib and other
+ * shared libs.
+ *
+ * @param pathToAppend A new library path to prepend to the dynamic linker's
+ * search path.
+ */
+# include "prprf.h"
+# define PATH_SEPARATOR ":"
+# define LD_LIBRARY_PATH_ENVVAR_NAME "DYLD_LIBRARY_PATH"
+static void AppendToLibPath(const char* pathToAppend) {
+ char* pathValue = getenv(LD_LIBRARY_PATH_ENVVAR_NAME);
+ if (nullptr == pathValue || '\0' == *pathValue) {
+ // Leak the string because that is required by PR_SetEnv.
+ char* s =
+ Smprintf("%s=%s", LD_LIBRARY_PATH_ENVVAR_NAME, pathToAppend).release();
+ PR_SetEnv(s);
+ } else {
+ // Leak the string because that is required by PR_SetEnv.
+ char* s = Smprintf("%s=%s" PATH_SEPARATOR "%s", LD_LIBRARY_PATH_ENVVAR_NAME,
+ pathToAppend, pathValue)
+ .release();
+ PR_SetEnv(s);
+ }
+}
+#endif
+
/**
* Applies, switches, or stages an update.
*
@@ -612,6 +648,20 @@ static void ApplyUpdate(nsIFile* greDir, nsIFile* updateDir, nsIFile* appDir,
PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
}
+#if defined(TOR_BROWSER_UPDATE) && defined(MOZ_VERIFY_MAR_SIGNATURE) && \
+ defined(MAR_NSS) && defined(XP_MACOSX)
+ // On macOS, append the app directory to the shared library search path
+ // so the system can locate the shared libraries that are needed by the
+ // updater, e.g., libnss3.dylib).
+ nsAutoCString appPath;
+ nsresult rv2 = appDir->GetNativePath(appPath);
+ if (NS_SUCCEEDED(rv2)) {
+ AppendToLibPath(appPath.get());
+ } else {
+ LOG(("ApplyUpdate -- appDir->GetNativePath() failed (0x%x)\n", rv2));
+ }
+#endif
+
LOG(("spawning updater process [%s]\n", updaterPath.get()));
#ifdef DEBUG
dump_argv("ApplyUpdate updater", argv, argc);
[View Less]
1
0

[tor-browser/tor-browser-91.0b5-11.0-1] Bug 11641: change TBB directory structure to be more like Firefox's
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit cfe438c79099ec10293d13a8feb7c74ed0d41329
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Tue Apr 29 13:08:24 2014 -0400
Bug 11641: change TBB directory structure 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 ++++++++++++++++---…
[View More]--
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 046a02180d3d..4abf4eb91940 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
@@ -4100,16 +4102,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");
[View Less]
1
0

[tor-browser/tor-browser-91.0b5-11.0-1] Bug 16940: After update, load local change notes.
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 6e3cd918896110e6dac7608f895ad9c181bee5de
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Wed Nov 25 11:36:20 2015 -0500
Bug 16940: After update, load local change notes.
Add an about:tbupdate page that displays the first section from
TorBrowser/Docs/ChangeLog.txt and includes a link to the remote
post-update page (typically our blog entry for the release).
Always load about:tbupdate in a content process, but implement the
code that reads …
[View More]the file system (changelog) in the chrome process
for compatibility with future sandboxing efforts.
Also fix bug 29440. Now about:tbupdate is styled as a fairly simple
changelog page that is designed to be displayed via a link that is on
about:tor.
---
browser/actors/AboutTBUpdateChild.jsm | 12 +++
browser/actors/AboutTBUpdateParent.jsm | 120 +++++++++++++++++++++
browser/actors/moz.build | 6 ++
.../base/content/abouttbupdate/aboutTBUpdate.css | 74 +++++++++++++
.../base/content/abouttbupdate/aboutTBUpdate.js | 27 +++++
.../base/content/abouttbupdate/aboutTBUpdate.xhtml | 39 +++++++
browser/base/content/browser-siteIdentity.js | 2 +-
browser/base/content/browser.js | 4 +
browser/base/jar.mn | 5 +
browser/components/BrowserContentHandler.jsm | 55 +++++++---
browser/components/BrowserGlue.jsm | 15 +++
browser/components/about/AboutRedirector.cpp | 6 ++
browser/components/about/components.conf | 3 +
browser/components/moz.build | 5 +-
.../locales/en-US/chrome/browser/aboutTBUpdate.dtd | 8 ++
browser/locales/jar.mn | 3 +
toolkit/modules/RemotePageAccessManager.jsm | 5 +
17 files changed, 373 insertions(+), 16 deletions(-)
diff --git a/browser/actors/AboutTBUpdateChild.jsm b/browser/actors/AboutTBUpdateChild.jsm
new file mode 100644
index 000000000000..4670da19b3db
--- /dev/null
+++ b/browser/actors/AboutTBUpdateChild.jsm
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+// See LICENSE for licensing information.
+//
+// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
+
+var EXPORTED_SYMBOLS = ["AboutTBUpdateChild"];
+
+const { RemotePageChild } = ChromeUtils.import(
+ "resource://gre/actors/RemotePageChild.jsm"
+);
+
+class AboutTBUpdateChild extends RemotePageChild {}
diff --git a/browser/actors/AboutTBUpdateParent.jsm b/browser/actors/AboutTBUpdateParent.jsm
new file mode 100644
index 000000000000..56a10394565a
--- /dev/null
+++ b/browser/actors/AboutTBUpdateParent.jsm
@@ -0,0 +1,120 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+// See LICENSE for licensing information.
+//
+// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["AboutTBUpdateParent"];
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+const { AppConstants } = ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+
+const kRequestUpdateMessageName = "FetchUpdateData";
+
+/**
+ * This code provides services to the about:tbupdate page. Whenever
+ * about:tbupdate needs to do something chrome-privileged, it sends a
+ * message that's handled here. It is modeled after Mozilla's about:home
+ * implementation.
+ */
+class AboutTBUpdateParent extends JSWindowActorParent {
+ receiveMessage(aMessage) {
+ if (aMessage.name == kRequestUpdateMessageName) {
+ return this.releaseNoteInfo;
+ }
+ return undefined;
+ }
+
+ get moreInfoURL() {
+ try {
+ return Services.prefs.getCharPref("torbrowser.post_update.url");
+ } catch (e) {}
+
+ // Use the default URL as a fallback.
+ return Services.urlFormatter.formatURLPref("startup.homepage_override_url");
+ }
+
+ // Read the text from the beginning of the changelog file that is located
+ // at TorBrowser/Docs/ChangeLog.txt and return an object that contains
+ // the following properties:
+ // version e.g., Tor Browser 8.5
+ // releaseDate e.g., March 31 2019
+ // releaseNotes details of changes (lines 2 - end of ChangeLog.txt)
+ // We attempt to parse the first line of ChangeLog.txt to extract the
+ // version and releaseDate. If parsing fails, we return the entire first
+ // line in version and omit releaseDate.
+ //
+ // On Mac OS, when building with --enable-tor-browser-data-outside-app-dir
+ // to support Gatekeeper signing, the ChangeLog.txt file is located in
+ // TorBrowser.app/Contents/Resources/TorBrowser/Docs/.
+ get releaseNoteInfo() {
+ let info = { moreInfoURL: this.moreInfoURL };
+
+ try {
+ let f;
+ if (AppConstants.TOR_BROWSER_DATA_OUTSIDE_APP_DIR) {
+ // "XREExeF".parent is the directory that contains firefox, i.e.,
+ // Browser/ or, on Mac OS, TorBrowser.app/Contents/MacOS/.
+ f = Services.dirsvc.get("XREExeF", Ci.nsIFile).parent;
+ if (AppConstants.platform === "macosx") {
+ f = f.parent;
+ f.append("Resources");
+ }
+ f.append("TorBrowser");
+ } else {
+ // "DefProfRt" is .../TorBrowser/Data/Browser
+ f = Services.dirsvc.get("DefProfRt", Ci.nsIFile);
+ f = f.parent.parent; // Remove "Data/Browser"
+ }
+
+ f.append("Docs");
+ f.append("ChangeLog.txt");
+
+ let fs = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
+ Ci.nsIFileInputStream
+ );
+ fs.init(f, -1, 0, 0);
+ let s = NetUtil.readInputStreamToString(fs, fs.available());
+ fs.close();
+
+ // Truncate at the first empty line.
+ s = s.replace(/[\r\n][\r\n][\s\S]*$/m, "");
+
+ // Split into first line (version plus releaseDate) and
+ // remainder (releaseNotes).
+ // This first match() uses multiline mode with two capture groups:
+ // first line: (.*$)
+ // remaining lines: ([\s\S]+)
+ // [\s\S] matches all characters including end of line. This trick
+ // is needed because when using JavaScript regex in multiline mode,
+ // . does not match an end of line character.
+ let matchArray = s.match(/(.*$)\s*([\s\S]+)/m);
+ if (matchArray && matchArray.length == 3) {
+ info.releaseNotes = matchArray[2];
+ let line1 = matchArray[1];
+ // Extract the version and releaseDate. The first line looks like:
+ // Tor Browser 8.5 -- May 1 2019
+ // The regex uses two capture groups:
+ // text that does not include a hyphen: (^[^-]*)
+ // remaining text: (.*$)
+ // In between we match optional whitespace, one or more hyphens, and
+ // optional whitespace by using: \s*-+\s*
+ matchArray = line1.match(/(^[^-]*)\s*-+\s*(.*$)/);
+ if (matchArray && matchArray.length == 3) {
+ info.version = matchArray[1];
+ info.releaseDate = matchArray[2];
+ } else {
+ info.version = line1; // Match failed: return entire line in version.
+ }
+ } else {
+ info.releaseNotes = s; // Only one line: use as releaseNotes.
+ }
+ } catch (e) {}
+
+ return info;
+ }
+}
diff --git a/browser/actors/moz.build b/browser/actors/moz.build
index 28c981625a7f..3eac455c5356 100644
--- a/browser/actors/moz.build
+++ b/browser/actors/moz.build
@@ -87,3 +87,9 @@ FINAL_TARGET_FILES.actors += [
"WebRTCChild.jsm",
"WebRTCParent.jsm",
]
+
+if CONFIG["TOR_BROWSER_UPDATE"]:
+ FINAL_TARGET_FILES.actors += [
+ "AboutTBUpdateChild.jsm",
+ "AboutTBUpdateParent.jsm",
+ ]
diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.css b/browser/base/content/abouttbupdate/aboutTBUpdate.css
new file mode 100644
index 000000000000..7c1a34b77f17
--- /dev/null
+++ b/browser/base/content/abouttbupdate/aboutTBUpdate.css
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019, The Tor Project, Inc.
+ * See LICENSE for licensing information.
+ *
+ * vim: set sw=2 sts=2 ts=8 et syntax=css:
+ */
+
+:root {
+ --abouttor-text-color: white;
+ --abouttor-bg-toron-color: #420C5D;
+}
+
+body {
+ font-family: Helvetica, Arial, sans-serif;
+ color: var(--abouttor-text-color);
+ background-color: var(--abouttor-bg-toron-color);
+ background-attachment: fixed;
+ background-size: 100% 100%;
+}
+
+a {
+ color: var(--abouttor-text-color);
+}
+
+.two-column-grid {
+ display: inline-grid;
+ grid-template-columns: auto auto;
+ grid-column-gap: 50px;
+ margin: 10px 0px 0px 50px;
+}
+
+.two-column-grid div {
+ margin-top: 40px;
+ align-self: baseline; /* Align baseline of text across the row. */
+}
+
+.label-column {
+ font-size: 14px;
+ font-weight: 400;
+}
+
+/*
+ * Use a reduced top margin to bring the row that contains the
+ * "visit our website" link closer to the row that precedes it. This
+ * looks better because the "visit our website" row does not have a
+ * label in the left column.
+ */
+div.more-info-row {
+ margin-top: 5px;
+ font-size: 14px;
+}
+
+#version-content {
+ font-size: 50px;
+ font-weight: 300;
+}
+
+body:not([havereleasedate]) .release-date-cell {
+ display: none;
+}
+
+#releasedate-content {
+ font-size: 17px;
+}
+
+#releasenotes-label {
+ align-self: start; /* Anchor "Release Notes" label at the top. */
+}
+
+#releasenotes-content {
+ font-family: monospace;
+ font-size: 15px;
+ white-space: pre;
+}
diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.js b/browser/base/content/abouttbupdate/aboutTBUpdate.js
new file mode 100644
index 000000000000..ec070e2cb131
--- /dev/null
+++ b/browser/base/content/abouttbupdate/aboutTBUpdate.js
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, The Tor Project, Inc.
+// See LICENSE for licensing information.
+//
+// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
+
+/* eslint-env mozilla/frame-script */
+
+// aData may contain the following string properties:
+// version
+// releaseDate
+// moreInfoURL
+// releaseNotes
+function onUpdate(aData) {
+ document.getElementById("version-content").textContent = aData.version;
+ if (aData.releaseDate) {
+ document.body.setAttribute("havereleasedate", "true");
+ document.getElementById("releasedate-content").textContent =
+ aData.releaseDate;
+ }
+ if (aData.moreInfoURL) {
+ document.getElementById("infolink").setAttribute("href", aData.moreInfoURL);
+ }
+ document.getElementById("releasenotes-content").textContent =
+ aData.releaseNotes;
+}
+
+RPMSendQuery("FetchUpdateData").then(onUpdate);
diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml b/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
new file mode 100644
index 000000000000..8489cfef5083
--- /dev/null
+++ b/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html [
+ <!ENTITY % htmlDTD
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "DTD/xhtml1-strict.dtd">
+ %htmlDTD;
+ <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
+ %globalDTD;
+ <!ENTITY % tbUpdateDTD SYSTEM "chrome://browser/locale/aboutTBUpdate.dtd">
+ %tbUpdateDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'" />
+ <title>&aboutTBUpdate.changelogTitle;</title>
+ <link rel="stylesheet" type="text/css"
+ href="chrome://browser/content/abouttbupdate/aboutTBUpdate.css"/>
+ <script src="chrome://browser/content/abouttbupdate/aboutTBUpdate.js"
+ type="text/javascript"/>
+</head>
+<body dir="&locale.dir;">
+<div class="two-column-grid">
+ <div class="label-column">&aboutTBUpdate.version;</div>
+ <div id="version-content"/>
+
+ <div class="label-column release-date-cell">&aboutTBUpdate.releaseDate;</div>
+ <div id="releasedate-content" class="release-date-cell"/>
+
+ <div class="more-info-row"/>
+ <div class="more-info-row">&aboutTBUpdate.linkPrefix;<a id="infolink">&aboutTBUpdate.linkLabel;</a>&aboutTBUpdate.linkSuffix;</div>
+
+ <div id="releasenotes-label"
+ class="label-column">&aboutTBUpdate.releaseNotes;</div>
+ <div id="releasenotes-content"></div>
+</div>
+</body>
+</html>
diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js
index 859ebf5eaa3f..91940db44ca4 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|ion)(?:[?#]|$)/i,
+ _secureInternalPages: (AppConstants.TOR_BROWSER_UPDATE ? /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|ion|tor|tbupdate)(?:[?#]|$)/i : /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|ion|tor)(?:[?#]|$)/i),
/**
* Whether the established HTTPS connection is considered "broken".
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 7f370894bf95..f82d484b753c 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -643,6 +643,10 @@ var gInitialPages = [
"about:welcome",
];
+if (AppConstants.TOR_BROWSER_UPDATE) {
+ gInitialPages.push("about:tbupdate");
+}
+
function isInitialPage(url) {
if (!(url instanceof Ci.nsIURI)) {
try {
diff --git a/browser/base/jar.mn b/browser/base/jar.mn
index 7be13da2dd5d..6554f6a5707e 100644
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -33,6 +33,11 @@ browser.jar:
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js)
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
+#ifdef TOR_BROWSER_UPDATE
+ content/browser/abouttbupdate/aboutTBUpdate.xhtml (content/abouttbupdate/aboutTBUpdate.xhtml)
+ content/browser/abouttbupdate/aboutTBUpdate.js (content/abouttbupdate/aboutTBUpdate.js)
+ content/browser/abouttbupdate/aboutTBUpdate.css (content/abouttbupdate/aboutTBUpdate.css)
+#endif
* content/browser/browser.css (content/browser.css)
content/browser/browser.js (content/browser.js)
* content/browser/browser.xhtml (content/browser.xhtml)
diff --git a/browser/components/BrowserContentHandler.jsm b/browser/components/BrowserContentHandler.jsm
index d8e24e641447..9f6c8a33a730 100644
--- a/browser/components/BrowserContentHandler.jsm
+++ b/browser/components/BrowserContentHandler.jsm
@@ -629,6 +629,23 @@ nsBrowserContentHandler.prototype = {
}
}
+ // Retrieve the home page early so we can compare it against about:tor
+ // to decide whether or not we need an override page (second tab) after
+ // an update was applied.
+ var startPage = "";
+ try {
+ var choice = prefb.getIntPref("browser.startup.page");
+ if (choice == 1 || choice == 3) {
+ startPage = HomePage.get();
+ }
+ } catch (e) {
+ Cu.reportError(e);
+ }
+
+ if (startPage == "about:blank") {
+ startPage = "";
+ }
+
var override;
var overridePage = "";
var additionalPage = "";
@@ -674,6 +691,16 @@ nsBrowserContentHandler.prototype = {
// into account because that requires waiting for the session file
// to be read. If a crash occurs after updating, before restarting,
// we may open the startPage in addition to restoring the session.
+ //
+ // Tor Browser: Instead of opening the post-update "override page"
+ // directly, we ensure that about:tor will be opened in a special
+ // mode that notifies the user that their browser was updated.
+ // The about:tor page will provide a link to the override page
+ // where the user can learn more about the update, as well as a
+ // link to the Tor Browser changelog page (about:tbupdate). The
+ // override page URL comes from the openURL attribute within the
+ // updates.xml file or, if no showURL action is present, from the
+ // startup.homepage_override_url pref.
willRestoreSession = SessionStartup.isAutomaticRestoreEnabled();
overridePage = Services.urlFormatter.formatURLPref(
@@ -693,6 +720,20 @@ nsBrowserContentHandler.prototype = {
overridePage = overridePage.replace("%OLD_VERSION%", old_mstone);
overridePage = overridePage.replace("%OLD_TOR_BROWSER_VERSION%",
old_tbversion);
+#ifdef TOR_BROWSER_UPDATE
+ if (overridePage)
+ {
+ prefb.setCharPref("torbrowser.post_update.url", overridePage);
+ prefb.setBoolPref("torbrowser.post_update.shouldNotify", true);
+ // If the user's homepage is about:tor, we will inform them
+ // about the update on that page; otherwise, we arrange to
+ // open about:tor in a secondary tab.
+ if (startPage === "about:tor")
+ overridePage = "";
+ else
+ overridePage = "about:tor";
+ }
+#endif
break;
case OVERRIDE_NEW_BUILD_ID:
if (UpdateManager.readyUpdate) {
@@ -765,20 +806,6 @@ nsBrowserContentHandler.prototype = {
}
}
- var startPage = "";
- try {
- var choice = prefb.getIntPref("browser.startup.page");
- if (choice == 1 || choice == 3) {
- startPage = HomePage.get();
- }
- } catch (e) {
- Cu.reportError(e);
- }
-
- if (startPage == "about:blank") {
- startPage = "";
- }
-
let skipStartPage =
override == OVERRIDE_NEW_PROFILE &&
prefb.getBoolPref("browser.startup.firstrunSkipsHomepage");
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 1f293a5c57f3..3beb2da3ce52 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -749,6 +749,21 @@ let JSWINDOWACTORS = {
},
};
+if (AppConstants.TOR_BROWSER_UPDATE) {
+ JSWINDOWACTORS["AboutTBUpdate"] = {
+ parent: {
+ moduleURI: "resource:///actors/AboutTBUpdateParent.jsm",
+ },
+ child: {
+ moduleURI: "resource:///actors/AboutTBUpdateChild.jsm",
+ events: {
+ DOMWindowCreated: { capture: true },
+ },
+ },
+ matches: ["about:tbupdate"],
+ };
+}
+
(function earlyBlankFirstPaint() {
let startTime = Cu.now();
if (
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
index 5412a65c315f..956e25c818e1 100644
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -128,6 +128,12 @@ static const RedirEntry kRedirMap[] = {
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS},
{"ion", "chrome://browser/content/ion.html",
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT},
+#ifdef TOR_BROWSER_UPDATE
+ {"tbupdate", "chrome://browser/content/abouttbupdate/aboutTBUpdate.xhtml",
+ nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
+ nsIAboutModule::HIDE_FROM_ABOUTABOUT},
+#endif
};
static nsAutoCString GetAboutModuleName(nsIURI* aURI) {
diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf
index 0c9597ff9fb4..a880a161a0f2 100644
--- a/browser/components/about/components.conf
+++ b/browser/components/about/components.conf
@@ -32,6 +32,9 @@ pages = [
'welcomeback',
]
+if defined('TOR_BROWSER_UPDATE'):
+ pages.append('tbupdate')
+
Classes = [
{
'cid': '{7e4bb6ad-2fc4-4dc6-89ef-23e8e5ccf980}',
diff --git a/browser/components/moz.build b/browser/components/moz.build
index 5f8780e01c65..c56811d36a14 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -86,11 +86,14 @@ EXTRA_COMPONENTS += [
]
EXTRA_JS_MODULES += [
- "BrowserContentHandler.jsm",
"BrowserGlue.jsm",
"distribution.js",
]
+EXTRA_PP_JS_MODULES += [
+ "BrowserContentHandler.jsm",
+]
+
BROWSER_CHROME_MANIFESTS += [
"safebrowsing/content/test/browser.ini",
"tests/browser/browser.ini",
diff --git a/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd b/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd
new file mode 100644
index 000000000000..2d1e59b40eaf
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd
@@ -0,0 +1,8 @@
+<!ENTITY aboutTBUpdate.changelogTitle "Tor Browser Changelog">
+<!ENTITY aboutTBUpdate.updated "Tor Browser has been updated.">
+<!ENTITY aboutTBUpdate.linkPrefix "For the most up-to-date information about this release, ">
+<!ENTITY aboutTBUpdate.linkLabel "visit our website">
+<!ENTITY aboutTBUpdate.linkSuffix ".">
+<!ENTITY aboutTBUpdate.version "Version">
+<!ENTITY aboutTBUpdate.releaseDate "Release Date">
+<!ENTITY aboutTBUpdate.releaseNotes "Release Notes">
diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn
index 3b7963c854e1..c6fdccea7d70 100644
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -20,6 +20,9 @@
locale/browser/accounts.properties (%chrome/browser/accounts.properties)
locale/browser/app-extension-fields.properties (%chrome/browser/app-extension-fields.properties)
+#ifdef TOR_BROWSER_UPDATE
+ locale/browser/aboutTBUpdate.dtd (%chrome/browser/aboutTBUpdate.dtd)
+#endif
locale/browser/browser.dtd (%chrome/browser/browser.dtd)
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm
index 50fb4ea8d417..e5111ff83782 100644
--- a/toolkit/modules/RemotePageAccessManager.jsm
+++ b/toolkit/modules/RemotePageAccessManager.jsm
@@ -213,6 +213,11 @@ let RemotePageAccessManager = {
RPMAddMessageListener: ["*"],
RPMRemoveMessageListener: ["*"],
},
+ "about:tbupdate": {
+ RPMSendQuery: [
+ "FetchUpdateData",
+ ],
+ },
},
/**
[View Less]
1
0

[tor-browser/tor-browser-91.0b5-11.0-1] Bug 16285: Exclude ClearKey system for now
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 2d241e5239a547f0c8220ce9fe5d975ca6f7188b
Author: Georg Koppen <gk(a)torproject.org>
Date: Mon May 22 12:44:40 2017 +0000
Bug 16285: Exclude ClearKey system for now
In the past the ClearKey system had not been compiled when specifying
--disable-eme. But that changed and it is even bundled nowadays (see:
Mozilla's bug 1300654). We don't want to ship it right now as the use
case for it is not really visible while the code had security
vulnerabilities in …
[View More]the past.
---
browser/installer/package-manifest.in | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index c1b068c29ed5..0b0b65a6f932 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -460,8 +460,8 @@ bin/libfreebl_64int_3.so
#endif
; media
-@RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
-@RESPATH@/gmp-clearkey/0.1/manifest.json
+;@RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
+;@RESPATH@/gmp-clearkey/0.1/manifest.json
#ifdef MOZ_DMD
; DMD
[View Less]
1
0

[Git][tpo/applications/android-components][android-components-91.0.1-11.0-1] 12 commits: Bug 40005: Modify Default toolbar menu
by Matthew Finkel (@sysrqb) 22 Jul '21
by Matthew Finkel (@sysrqb) 22 Jul '21
22 Jul '21
Matthew Finkel pushed to branch android-components-91.0.1-11.0-1 at The Tor Project / Applications / android-components
Commits:
9130802a by Matthew Finkel at 2021-07-14T17:39:01+02:00
Bug 40005: Modify Default toolbar menu
- - - - -
448c7c3e by Alex Catarineu at 2021-07-14T17:39:03+02:00
Bug 40007: Port external helper app prompting
Together with the corresponding fenix patch, this allows all `startActivity`
that may open external apps to be replaced by `TorUtils.startActivityPrompt`.
- - …
[View More]- - -
1a234718 by Alex Catarineu at 2021-07-14T17:39:05+02:00
Bug 40002: Ensure system download manager is not used
- - - - -
1661b6ef by Alex Catarineu at 2021-07-14T17:39:06+02:00
Bug 40009: Change the default search engines
This matches the search engines from desktop, that is:
DDG as the default, then YouTube, Google, DDGOnion,
Startpage, Twitter, Wikipedia and Yahoo.
- - - - -
0b4838c1 by Alex Catarineu at 2021-07-14T17:39:08+02:00
Modify Addon support
Bug 40011: Hide option for disallowing addons in private mode
Bug 40016: Allow inheriting from AddonCollectionProvider
This will allow implementing our own AddonsProvider in fenix.
- - - - -
01a33c82 by Georg Koppen at 2021-07-14T17:39:09+02:00
Bug 40013: Add option do overwrite timestamp in extension version
- - - - -
81fc3d4b by Alex Catarineu at 2021-07-14T17:39:11+02:00
Bug 40015: Port padlock states for .onion services
- - - - -
096ab357 by Alex Catarineu at 2021-07-14T17:39:13+02:00
Bug 40021: Force telemetry=false in Fennec settings migration
- - - - -
68c62527 by Alex Catarineu at 2021-07-14T17:39:14+02:00
Bug 40022: Migrate Tor security level from Fennec
- - - - -
94924df0 by Matthew Finkel at 2021-07-14T17:39:16+02:00
Modify Tracking Protection configuration
Bug 40020: Disable third-party cookies
Bug 40024: Disable tracking protection by default
- - - - -
d25092c3 by Matthew Finkel at 2021-07-14T17:39:17+02:00
Bug 40023: Stop PrivateNotificationService
- - - - -
5853be27 by Matthew Finkel at 2021-07-14T17:39:19+02:00
Add support for new GeckoView interfaces
Bug 40006: Expose Security Level interface
Bug 40019: Expose spoofEnglish pref
Bug 34439: Isolate Icon loader on Android
- - - - -
30 changed files:
- build.gradle
- components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt
- components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/fetch/GeckoViewFetchClient.kt
- components/browser/icons/src/main/java/mozilla/components/browser/icons/loader/HttpIconLoader.kt
- components/browser/menu/src/main/java/mozilla/components/browser/menu/WebExtensionBrowserMenuBuilder.kt
- + components/browser/search/src/main/assets/searchplugins/ddg-onion.xml
- + components/browser/search/src/main/assets/searchplugins/startpage.xml
- + components/browser/search/src/main/assets/searchplugins/yahoo.xml
- components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt
- components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/SiteSecurityIconView.kt
- components/browser/toolbar/src/main/res/drawable/mozac_ic_site_security.xml
- components/browser/toolbar/src/main/res/values/attrs_browser_toolbar.xml
- components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt
- components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt
- components/concept/fetch/src/main/java/mozilla/components/concept/fetch/Request.kt
- components/concept/toolbar/src/main/java/mozilla/components/concept/toolbar/Toolbar.kt
- components/feature/addons/src/main/java/mozilla/components/feature/addons/amo/AddonCollectionProvider.kt
- components/feature/addons/src/main/res/layout/mozac_feature_addons_fragment_dialog_addon_installed.xml
- components/feature/app-links/build.gradle
- components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksFeature.kt
- components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt
- components/feature/contextmenu/src/main/java/mozilla/components/feature/contextmenu/ContextMenuCandidate.kt
- components/feature/downloads/build.gradle
- components/feature/downloads/src/main/java/mozilla/components/feature/downloads/AbstractFetchDownloadService.kt
- components/feature/downloads/src/main/java/mozilla/components/feature/downloads/DownloadsFeature.kt
- components/feature/privatemode/src/main/java/mozilla/components/feature/privatemode/notification/PrivateNotificationFeature.kt
- components/feature/search/src/main/assets/search/list.json
- components/feature/search/src/main/assets/searchplugins/ddg.xml
- components/feature/toolbar/src/main/java/mozilla/components/feature/toolbar/ToolbarPresenter.kt
- components/support/ktx/src/main/java/mozilla/components/support/ktx/android/content/Context.kt
The diff was not included because it is too large.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/android-components/-/compare…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/android-components/-/compare…
You're receiving this email because of your account on gitlab.torproject.org.
[View Less]
1
0

[tor-launcher/master] Merge remote-tracking branch 'richardgl/40547'
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 474998734f19c7cef3b10abf874d523cd7940260
Merge: ed8c1e7 9bc9139
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Thu Jul 22 18:50:20 2021 +0000
Merge remote-tracking branch 'richardgl/40547'
src/chrome/locale/en-US/network-settings.dtd | 1 +
1 file changed, 1 insertion(+)
1
0

[tor-launcher/master] tor-browser#40547 - added 'Tor Not Connected' string for urlbar TorConnect box
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 9bc9139710184fde5887e4d89b3c0f9ac360e468
Author: Richard Pospesel <richard(a)torproject.org>
Date: Thu Jul 22 13:25:19 2021 +0200
tor-browser#40547 - added 'Tor Not Connected' string for urlbar TorConnect box
---
src/chrome/locale/en-US/network-settings.dtd | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/chrome/locale/en-US/network-settings.dtd b/src/chrome/locale/en-US/network-settings.dtd
index 73d32e0..66c650e 100644
--- a/src/chrome/locale/en-US/network-settings.…
[View More]dtd
+++ b/src/chrome/locale/en-US/network-settings.dtd
@@ -92,4 +92,5 @@
<!ENTITY torConnect.tryAgainMessage "Tor Browser has failed to establish a connection to the Tor Network">
<!ENTITY torConnect.connectingConcise "Connecting…">
<!ENTITY torConnect.connectedConcise "Connected">
+<!ENTITY torConnect.notConnectedConcise "Not Connected">
<!ENTITY torConnect.copyLog "Copy Tor Logs">
[View Less]
1
0

[tor-browser/tor-browser-78.12.0esr-11.0-1] fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
by sysrqb@torproject.org 22 Jul '21
by sysrqb@torproject.org 22 Jul '21
22 Jul '21
commit 73d57c01c2bfe398c02586ae76dab677d843df22
Author: Richard Pospesel <richard(a)torproject.org>
Date: Fri Jul 16 17:32:01 2021 +0200
fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
---
browser/actors/NetErrorParent.jsm | 6 +-
browser/base/content/browser.js | 5 +-
browser/components/BrowserGlue.jsm | 32 +-
browser/components/torconnect/TorConnectParent.jsm | 200 +++++----
.../torconnect/…
[View More]content/aboutTorConnect.js | 466 +++++++++-----------
.../torconnect/content/aboutTorConnect.xhtml | 9 -
.../torconnect/content/torBootstrapUrlbar.js | 195 ++++-----
.../components/torpreferences/content/torPane.js | 8 +-
browser/components/urlbar/UrlbarInput.jsm | 6 +-
browser/modules/TorConnect.jsm | 477 +++++++++++++++++++--
browser/modules/TorProtocolService.jsm | 101 +++--
.../processsingleton/MainProcessSingleton.jsm | 5 +
toolkit/modules/RemotePageAccessManager.jsm | 28 +-
13 files changed, 941 insertions(+), 597 deletions(-)
diff --git a/browser/actors/NetErrorParent.jsm b/browser/actors/NetErrorParent.jsm
index fa3cbf23fcb7..6dce9af5aad0 100644
--- a/browser/actors/NetErrorParent.jsm
+++ b/browser/actors/NetErrorParent.jsm
@@ -17,8 +17,8 @@ const { SessionStore } = ChromeUtils.import(
);
const { HomePage } = ChromeUtils.import("resource:///modules/HomePage.jsm");
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
+const { TorConnect } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
);
const PREF_SSL_IMPACT_ROOTS = [
@@ -324,7 +324,7 @@ class NetErrorParent extends JSWindowActorParent {
}
break;
case "ShouldShowTorConnect":
- return TorProtocolService.shouldShowTorConnect();
+ return TorConnect.shouldShowTorConnect;
}
return undefined;
}
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 916cd69320cb..996ef6dcdd7f 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -77,7 +77,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
TabModalPrompt: "chrome://global/content/tabprompts.jsm",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm",
- TorProtocolService: "resource:///modules/TorProtocolService.jsm",
+ TorConnect: "resource:///modules/TorConnect.jsm",
Translation: "resource:///modules/translation/TranslationParent.jsm",
OnionAliasStore: "resource:///modules/OnionAliasStore.jsm",
UITour: "resource:///modules/UITour.jsm",
@@ -2494,7 +2494,8 @@ var gBrowserInit = {
let uri = window.arguments[0];
let defaultArgs = BrowserHandler.defaultArgs;
- if (TorProtocolService.shouldShowTorConnect()) {
+ if (TorConnect.shouldShowTorConnect) {
+ TorConnect.setURIsToLoad(uri);
return "about:torconnect";
}
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 8735783cee2b..cb77f4d82a3e 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -17,31 +17,6 @@ const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
-// TorProtocolService and TorConnect modules need to be lazily-loaded
-// here because they will trigger generation of the random password used
-// to talk to the tor daemon in tor-launcher. Generating the random
-// password will initialize the cryptographic service ( nsNSSComponent )
-//
-// If this service is init'd before the profile has been setup, it will
-// use the fallback init path which behaves as if security.nocertdb=true
-//
-// We make these module getters so init happens when they are needed
-// (when init'ing the OnionAliasStore). With theze getters, the password
-// generation is triggered in torbutton after the 'profile-after-change'
-// topic (so after the profile is initialized)
-
-ChromeUtils.defineModuleGetter(
- this,
- "TorProtocolService",
- "resource:///modules/TorProtocolService.jsm"
-);
-
-ChromeUtils.defineModuleGetter(
- this,
- "TorConnect",
- "resource:///modules/TorConnect.jsm"
-);
-
ChromeUtils.defineModuleGetter(
this,
"ActorManagerParent",
@@ -2531,14 +2506,17 @@ BrowserGlue.prototype = {
{
task: () => {
- if (TorProtocolService.isBootstrapDone() || !TorProtocolService.ownsTorDaemon) {
+ const { TorConnect, TorConnectTopics } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+ );
+ if (!TorConnect.shouldShowTorConnect) {
// we will take this path when the user is using the legacy tor launcher or
// when Tor Browser didn't launch its own tor.
OnionAliasStore.init();
} else {
// this path is taken when using about:torconnect, we wait to init
// after we are bootstrapped and connected to tor
- const topic = "torconnect:bootstrap-complete";
+ const topic = TorConnectTopics.BootstrapComplete;
let bootstrapObserver = {
observe(aSubject, aTopic, aData) {
if (aTopic === topic) {
diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm
index c34fab76ddbb..3937bf3ebcf8 100644
--- a/browser/components/torconnect/TorConnectParent.jsm
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -3,123 +3,139 @@
var EXPORTED_SYMBOLS = ["TorConnectParent"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
-);
const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
-const { TorLauncherUtil } = ChromeUtils.import(
- "resource://torlauncher/modules/tl-util.jsm"
-);
-
-const { TorConnect } = ChromeUtils.import(
+const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import(
"resource:///modules/TorConnect.jsm"
);
-const kTorProcessReadyTopic = "TorProcessIsReady";
-const kTorProcessExitedTopic = "TorProcessExited";
-const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
-const kTorShowProgressPanelTopic = "TorShowProgressPanel";
-const kTorBootstrapStatusTopic = "TorBootstrapStatus";
-const kTorBootstrapErrorTopic = "TorBootstrapError";
-const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
-
-const gActiveTopics = [
- kTorProcessReadyTopic,
- kTorProcessExitedTopic,
- kTorProcessDidNotStartTopic,
- kTorShowProgressPanelTopic,
- kTorBootstrapStatusTopic,
- kTorBootstrapErrorTopic,
- kTorLogHasWarnOrErrTopic,
- "torconnect:bootstrap-complete",
-];
-
-const gTorLauncherPrefs = {
+const TorLauncherPrefs = Object.freeze({
quickstart: "extensions.torlauncher.quickstart",
-}
+});
+
+/*
+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.gObserver = {
- observe(aSubject, aTopic, aData) {
- const obj = aSubject?.wrappedJSObject;
- if (obj) {
- obj.handled = true;
- }
- self.sendAsyncMessage(aTopic, obj);
- },
- };
- for (const topic of gActiveTopics) {
- Services.obs.addObserver(this.gObserver, topic);
- }
+ this.state = {
+ State: TorConnect.state,
+ ErrorMessage: TorConnect.errorMessage,
+ ErrorDetails: TorConnect.errorDetails,
+ BootstrapProgress: TorConnect.bootstrapProgress,
+ BootstrapStatus: TorConnect.bootstrapStatus,
+ ShowCopyLog: TorConnect.logHasWarningOrError,
+ QuickStartEnabled: Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false),
+ };
- this.quickstartObserver = {
+ // 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) {
- if (aTopic === "nsPref:changed" &&
- aData == gTorLauncherPrefs.quickstart) {
- self.sendAsyncMessage("TorQuickstartPrefChanged", Services.prefs.getBoolPref(gTorLauncherPrefs.quickstart));
+ let obj = aSubject?.wrappedJSObject;
+
+ // update our state struct based on received torconnect topics and forward on
+ // to aboutTorConnect.js
+ switch(aTopic) {
+ case TorConnectTopics.StateChange: {
+ self.state.State = obj.state;
+ // 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: {
+ // tells about:torconnect pages to close themselves
+ // this flag will only be set if an about:torconnect page
+ // reaches the Bootstrapped state, so if a user
+ // navigates to about:torconnect manually after bootstrap, the page
+ // will not auto-close on them
+ self.state.Close = true;
+ 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 "nsPref:changed": {
+ if (aData === TorLauncherPrefs.quickstart) {
+ self.state.QuickStartEnabled = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ }
+ 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.prefs.addObserver(gTorLauncherPrefs.quickstart, this.quickstartObserver);
+ Services.prefs.addObserver(TorLauncherPrefs.quickstart, this.torConnectObserver);
}
willDestroy() {
- for (const topic of gActiveTopics) {
- Services.obs.removeObserver(this.gObserver, topic);
+ // stop observing all of our torconnect:.* topics
+ for (const key in TorConnectTopics) {
+ const topic = TorConnectTopics[key];
+ Services.obs.removeObserver(this.torConnectObserver, topic);
}
- }
-
-
- _OpenTorAdvancedPreferences() {
- const win = this.browsingContext.top.embedderElement.ownerGlobal;
- win.openTrustedLinkIn("about:preferences#tor", "tab");
- }
-
- _TorCopyLog() {
- // Copy tor log messages to the system clipboard.
- const chSvc = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
- Ci.nsIClipboardHelper
- );
- const countObj = { value: 0 };
- chSvc.copyString(TorProtocolService.getLog(countObj));
- const count = countObj.value;
- return TorLauncherUtil.getFormattedLocalizedString(
- "copiedNLogMessagesShort",
- [count],
- 1
- );
+ Services.prefs.removeObserver(TorLauncherPrefs.quickstart, this.torConnectObserver);
}
receiveMessage(message) {
switch (message.name) {
- case "TorBootstrapErrorOccurred":
- return TorProtocolService.torBootstrapErrorOccurred();
- case "TorRetrieveBootstrapStatus":
- return TorProtocolService.retrieveBootstrapStatus();
- case "OpenTorAdvancedPreferences":
- return this._OpenTorAdvancedPreferences();
- case "GetLocalizedBootstrapStatus":
- const { status, keyword } = message.data;
- return TorLauncherUtil.getLocalizedBootstrapStatus(status, keyword);
- case "TorCopyLog":
- return this._TorCopyLog();
- case "TorIsNetworkDisabled":
- return TorProtocolService.isNetworkDisabled();
- case "TorStopBootstrap":
- return TorProtocolService.torStopBootstrap();
- case "TorConnect":
- return TorProtocolService.connect();
- case "GetDirection":
- return Services.locale.isAppLocaleRTL ? "rtl" : "ltr";
- case "GetTorStrings":
- return TorStrings;
- case "TorLogHasWarnOrErr":
- return TorProtocolService.torLogHasWarnOrErr();
+ case "torconnect:set-quickstart":
+ Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, message.data);
+ 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
+ return {
+ TorStrings: TorStrings,
+ TorConnectState: TorConnectState,
+ Direction: Services.locale.isAppLocaleRTL ? "rtl" : "ltr",
+ State: this.state,
+ };
}
return undefined;
}
diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js
index 19fd335ccd13..8b269d2fc82b 100644
--- a/browser/components/torconnect/content/aboutTorConnect.js
+++ b/browser/components/torconnect/content/aboutTorConnect.js
@@ -2,299 +2,258 @@
/* eslint-env mozilla/frame-script */
-const kTorProcessReadyTopic = "TorProcessIsReady";
-const kTorProcessExitedTopic = "TorProcessExited";
-const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
-const kTorBootstrapStatusTopic = "TorBootstrapStatus";
-const kTorBootstrapErrorTopic = "TorBootstrapError";
-const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
-const kTorQuickstartPrefChanged = "TorQuickstartPrefChanged";
-
-const TorLauncherPrefs = {
- quickstart: "extensions.torlauncher.quickstart",
- prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
-}
+// populated in AboutTorConnect.init()
+let TorStrings = {};
+let TorConnectState = {};
class AboutTorConnect {
- log(...args) {
- console.log(...args);
- }
-
- logError(...args) {
- console.error(...args);
- }
+ 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),
+ })
+
+ 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;
- logDebug(...args) {
- console.debug(...args);
+ if (error) {
+ this.elements.title.classList.add("error");
+ } else {
+ this.elements.title.classList.remove("error");
+ }
}
- getElem(id) {
- return document.getElementById(id);
- }
- get elemProgressContent() {
- return this.getElem("progressContent");
- }
- get elemProgressDesc() {
- return this.getElem("connectShortDescText");
- }
- get elemProgressMeter() {
- return this.getElem("progressBackground");
- }
- get elemCopyLogLink() {
- return this.getElem("copyLogLink");
- }
- get elemCopyLogTooltip() {
- return this.getElem("copyLogTooltip");
- }
- get elemCopyLogTooltipText() {
- return this.getElem("copyLogTooltipText");
- }
- get elemQuickstartCheckbox() {
- return this.getElem("quickstartCheckbox");
- }
- get elemQuickstartLabel() {
- return this.getElem("quickstartCheckboxLabel");
- }
- get elemConnectButton() {
- return this.getElem("connectButton");
- }
- get elemAdvancedButton() {
- return this.getElem("advancedButton");
- }
- get elemCancelButton() {
- return this.getElem("cancelButton");
- }
- get elemTextContainer() {
- return this.getElem("text-container");
- }
- get elemTitle() {
- return this.elemTextContainer.getElementsByClassName("title")[0];
+ 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);
+ }
}
- static get STATE_INITIAL() {
- return "STATE_INITIAL";
- }
+ /*
+ These methods update the UI based on the current TorConnect state
+ */
- static get STATE_BOOTSTRAPPING() {
- return "STATE_BOOTSTRAPPING";
- }
+ updateUI(state) {
+ console.log(state);
- static get STATE_BOOTSTRAPPED() {
- return "STATE_BOOTSTRAPPED";
- }
+ // calls update_$state()
+ this[`update_${state.State}`](state);
- static get STATE_BOOTSTRAP_ERROR() {
- return "STATE_BOOTSTRAP_ERROR";
+ if (state.ShowCopyLog) {
+ this.showCopyLog();
+ }
+ this.elements.quickstartCheckbox.checked = state.QuickStartEnabled;
}
- get state() {
- return this._state;
- }
+ /* Per-state updates */
- setInitialUI() {
- this.setTitle(this.torStrings.torConnect.torConnect);
- this.elemProgressDesc.textContent =
- this.torStrings.settings.torPreferencesDescription;
- this.showElem(this.elemConnectButton);
- this.elemConnectButton.focus();
- this.showElem(this.elemAdvancedButton);
- this.hideElem(this.elemCopyLogLink);
- this.hideElem(this.elemCancelButton);
- this.hideElem(this.elemProgressContent);
- this.hideElem(this.elemProgressMeter);
- this.elemTitle.classList.remove("error");
- }
+ update_Initial(state) {
+ const hasError = false;
+ const showProgressbar = false;
- setBootstrappingUI() {
- this.setTitle(this.torStrings.torConnect.torConnecting);
- this.hideElem(this.elemConnectButton);
- this.hideElem(this.elemAdvancedButton);
- this.hideElem(this.elemCopyLogLink);
- this.showElem(this.elemCancelButton);
- this.elemCancelButton.focus();
- this.showElem(this.elemProgressContent);
- this.showElem(this.elemProgressMeter);
- this.elemTitle.classList.remove("error");
+ 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);
}
- setBootstrapErrorUI() {
- this.setTitle(this.torStrings.torConnect.torBootstrapFailed);
- this.elemConnectButton.textContent = this.torStrings.torConnect.tryAgain;
- this.showElem(this.elemConnectButton);
- this.hideElem(this.elemCancelButton);
- this.showElem(this.elemAdvancedButton);
- this.elemAdvancedButton.focus();
- this.showElem(this.elemProgressContent);
- this.hideElem(this.elemProgressMeter);
- this.elemTitle.classList.add("error");
- }
+ update_Configuring(state) {
+ const hasError = state.ErrorMessage != null;
+ const showProgressbar = false;
- set state(state) {
- const oldState = this.state;
- if (oldState === state) {
- return;
- }
- this._state = state;
- switch (this.state) {
- case AboutTorConnect.STATE_INITIAL:
- this.setInitialUI();
- break;
- case AboutTorConnect.STATE_BOOTSTRAPPING:
- this.setBootstrappingUI();
- break;
- case AboutTorConnect.STATE_BOOTSTRAP_ERROR:
- this.setBootstrapErrorUI();
- break;
- case AboutTorConnect.STATE_BOOTSTRAPPED:
- window.close();
- break;
+ 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);
+ this.elements.connectButton.focus();
+ this.show(this.elements.advancedButton);
+ this.hide(this.elements.cancelButton);
}
- async showErrorMessage(aErrorObj) {
- if (aErrorObj && aErrorObj.message) {
- this.setTitle(aErrorObj.message);
- if (aErrorObj.details) {
- this.elemProgressDesc.textContent = aErrorObj.details;
- }
- }
-
- this.showCopyLog();
- this.showElem(this.elemConnectButton);
+ update_AutoConfiguring(state) {
+ // TODO: noop until this state is used
}
- showElem(elem) {
- elem.removeAttribute("hidden");
- }
+ update_Bootstrapping(state) {
+ const hasError = false;
+ const showProgressbar = true;
- hideElem(elem) {
- elem.setAttribute("hidden", "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);
+ this.elements.cancelButton.focus();
}
- async connect() {
- // reset the text to original description
- // in case we are trying again after an error (clears out error text)
- this.elemProgressDesc.textContent =
- this.torStrings.settings.torPreferencesDescription;
+ update_Error(state) {
+ const hasError = true;
+ const showProgressbar = false;
- this.state = AboutTorConnect.STATE_BOOTSTRAPPING;
- const error = await RPMSendQuery("TorConnect");
- if (error) {
- if (error.details) {
- this.showErrorMessage({ message: error.details }, true);
- this.showSaveSettingsError(error.details);
- }
- }
+ 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);
}
- showCopyLog() {
- this.elemCopyLogLink.removeAttribute("hidden");
+ update_FatalError(state) {
+ // TODO: noop until this state is used
}
- async updateBootstrapProgress(status) {
- let labelText = await RPMSendQuery("GetLocalizedBootstrapStatus", {
- status,
- keyword: "TAG",
- });
- let percentComplete = status.PROGRESS ? status.PROGRESS : 0;
- this.elemProgressMeter.style.width = `${percentComplete}%`;
-
- if (await RPMSendQuery("TorBootstrapErrorOccurred")) {
- this.state = AboutTorConnect.STATE_BOOTSTRAP_ERROR;
- return;
- } else if (await RPMSendQuery("TorIsNetworkDisabled")) {
- // If tor network is not connected, let's go to the initial state, even
- // if bootstrap state is greater than 0.
- this.state = AboutTorConnect.STATE_INITIAL;
- return;
- } else if (percentComplete > 0) {
- this.state = AboutTorConnect.STATE_BOOTSTRAPPING;
- }
+ update_Bootstrapped(state) {
+ const hasError = false;
+ const showProgressbar = true;
- // Due to async, status might have changed. Do not override desc if so.
- if (this.state === AboutTorConnect.STATE_BOOTSTRAPPING) {
- this.hideElem(this.elemConnectButton);
+ 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);
+
+ // only close the window if directed
+ if (state.Close) {
+ window.close();
}
}
- stopTorBootstrap() {
- RPMSendAsyncMessage("TorStopBootstrap");
+ 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)
}
- setTitle(title) {
- const titleElement = document.querySelector(".title-text");
- titleElement.textContent = title;
- document.title = title;
- }
+ async initElements(direction, quickstart) {
- async initElements() {
- this.elemAdvancedButton.textContent = this.torStrings.torConnect.torConfigure;
- this.elemAdvancedButton.addEventListener("click", () => {
- RPMSendAsyncMessage("OpenTorAdvancedPreferences");
- });
+ document.documentElement.setAttribute("dir", direction);
- // sets the text content while keping the child elements intact
- this.elemCopyLogLink.childNodes[0].nodeValue =
- this.torStrings.torConnect.copyLog;
- this.elemCopyLogLink.addEventListener("click", async (event) => {
- const copiedMessage = await RPMSendQuery("TorCopyLog");
- aboutTorConnect.elemCopyLogTooltipText.textContent = copiedMessage;
- aboutTorConnect.elemCopyLogTooltip.style.visibility = "visible";
+ // 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 (aboutTorConnect.copyLogTimeoutId) {
- clearTimeout(aboutTorConnect.copyLogTimeoutId);
+ if (this.copyLogTimeoutId) {
+ clearTimeout(this.copyLogTimeoutId);
}
// hide tooltip after X ms
const TOOLTIP_TIMEOUT = 2000;
- aboutTorConnect.copyLogTimeoutId = setTimeout(function() {
- aboutTorConnect.elemCopyLogTooltip.style.visibility = "hidden";
- aboutTorConnect.copyLogTimeoutId = 0;
+ this.copyLogTimeoutId = setTimeout(function() {
+ this.elements.copyLogTooltipText.style.visibility = "hidden";
+ this.copyLogTimeoutId = 0;
}, TOOLTIP_TIMEOUT);
});
+ this.elements.quickstartCheckbox.checked = quickstart
+ this.elements.quickstartCheckbox.addEventListener("change", () => {
+ const quickstart = this.elements.quickstartCheckbox.checked;
+ RPMSendAsyncMessage("torconnect:set-quickstart", quickstart);
+ });
+ this.elements.quickstartLabel.textContent = TorStrings.settings.quickstartCheckbox;
- this.elemQuickstartLabel.textContent = this.torStrings.settings.quickstartCheckbox;
- this.elemQuickstartCheckbox.addEventListener("change", () => {
- const quickstart = this.elemQuickstartCheckbox.checked;
- RPMSetBoolPref(TorLauncherPrefs.quickstart, quickstart);
+ this.elements.connectButton.textContent =
+ TorStrings.torConnect.torConnectButton;
+ this.elements.connectButton.addEventListener("click", () => {
+ this.beginBootstrap();
});
- this.elemQuickstartCheckbox.checked = await RPMGetBoolPref(TorLauncherPrefs.quickstart);
- this.elemConnectButton.textContent =
- this.torStrings.torConnect.torConnectButton;
- this.elemConnectButton.addEventListener("click", () => {
- this.connect();
+ this.elements.advancedButton.textContent = TorStrings.torConnect.torConfigure;
+ this.elements.advancedButton.addEventListener("click", () => {
+ RPMSendAsyncMessage("torconnect:open-tor-preferences");
});
- this.elemCancelButton.textContent = this.torStrings.torConnect.cancel;
- this.elemCancelButton.addEventListener("click", () => {
- this.stopTorBootstrap();
+ this.elements.cancelButton.textContent = TorStrings.torConnect.cancel;
+ this.elements.cancelButton.addEventListener("click", () => {
+ this.cancelBootstrap();
});
}
initObservers() {
- RPMAddMessageListener(kTorBootstrapErrorTopic, ({ data }) => {
- this.showCopyLog();
- this.stopTorBootstrap();
- this.showErrorMessage(data);
- });
- RPMAddMessageListener(kTorLogHasWarnOrErrTopic, () => {
- this.showCopyLog();
- });
- RPMAddMessageListener(kTorProcessDidNotStartTopic, ({ data }) => {
- this.showErrorMessage(data);
- });
- RPMAddMessageListener(kTorBootstrapStatusTopic, ({ data }) => {
- this.updateBootstrapProgress(data);
- });
- RPMAddMessageListener(kTorQuickstartPrefChanged, ({ data }) => {
- // update checkbox with latest quickstart pref value
- this.elemQuickstartCheckbox.checked = data;
- });
- RPMAddMessageListener("torconnect:bootstrap-complete", () => {
- this.state = AboutTorConnect.STATE_BOOTSTRAPPED;
+ // TorConnectParent feeds us state blobs to we use to update our UI
+ RPMAddMessageListener("torconnect:state-change", ({ data }) => {
+ this.updateUI(data);
});
}
@@ -304,34 +263,25 @@ class AboutTorConnect {
// 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.stopTorBootstrap();
+ this.cancelBootstrap();
}
};
}
async init() {
- this.torStrings = await RPMSendQuery("GetTorStrings");
- document.documentElement.setAttribute(
- "dir",
- await RPMSendQuery("GetDirection")
- );
- this.initElements();
+
+ 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();
- this.state = AboutTorConnect.STATE_INITIAL;
-
- // Request the most recent bootstrap status info so that a
- // TorBootstrapStatus notification is generated as soon as possible.
- RPMSendAsyncMessage("TorRetrieveBootstrapStatus");
-
- // quickstart is the user set pref for starting tor automatically
- // prompt_at_startup will be set to false after successful bootstrap, and true on error
- // by tor-launcher, so we want to keep the connect screen up when prompt_at_startup is true
- /// even if quickstart is enabled so user can potentially resolve errors on next launch
- if (await RPMGetBoolPref(TorLauncherPrefs.quickstart) &&
- !await RPMGetBoolPref(TorLauncherPrefs.prompt_at_startup)) {
- this.connect();
- }
+
+ // populate UI based on current state
+ this.updateUI(args.State);
}
}
diff --git a/browser/components/torconnect/content/aboutTorConnect.xhtml b/browser/components/torconnect/content/aboutTorConnect.xhtml
index 0a0721afb7db..595bbdf9a70a 100644
--- a/browser/components/torconnect/content/aboutTorConnect.xhtml
+++ b/browser/components/torconnect/content/aboutTorConnect.xhtml
@@ -19,15 +19,6 @@
</div>
</div>
- <div id="progressContent" hidden="true">
- <div class="tbb-header" pack="center">
- <image class="tbb-logo"/>
- </div>
- <div flex="1">
- <div id="progressDesc"/>
- </div>
- </div>
-
<div id="copyLogContainer">
<span id="copyLogLink" hidden="true">
<div id="copyLogTooltip">
diff --git a/browser/components/torconnect/content/torBootstrapUrlbar.js b/browser/components/torconnect/content/torBootstrapUrlbar.js
index 55a595b2dbab..e4fd6f5ab910 100644
--- a/browser/components/torconnect/content/torBootstrapUrlbar.js
+++ b/browser/components/torconnect/content/torBootstrapUrlbar.js
@@ -2,135 +2,88 @@
"use strict";
- const TorConnectionStatus = {
- invalid: -1,
- offline: 0,
- connecting: 1,
- connected: 2,
- failure: 3,
- };
-var TorBootstrapUrlbar;
+const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+const { TorStrings } = ChromeUtils.import(
+ "resource:///modules/TorStrings.jsm"
+);
-{
- const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
- );
- const { TorLauncherUtil } = ChromeUtils.import(
- "resource://torlauncher/modules/tl-util.jsm"
- );
- const { TorStrings } = ChromeUtils.import(
- "resource:///modules/TorStrings.jsm"
- );
-
- const kTorProcessReadyTopic = "TorProcessIsReady";
- const kTorProcessExitedTopic = "TorProcessExited";
- const kTorProcessDidNotStartTopic = "TorProcessDidNotStart";
- const kTorBootstrapStatusTopic = "TorBootstrapStatus";
- const kTorBootstrapErrorTopic = "TorBootstrapError";
-
- const gActiveTopics = [
- kTorProcessReadyTopic,
- kTorProcessExitedTopic,
- kTorProcessDidNotStartTopic,
- kTorBootstrapStatusTopic,
- kTorBootstrapErrorTopic,
- ];
-
- TorBootstrapUrlbar = {
- _connectionStatus: TorConnectionStatus.invalid,
- get ConnectionStatus() {
- return this._connectionStatus;
+var TorBootstrapUrlbar = {
+ selectors: Object.freeze({
+ torConnect: {
+ box: "hbox#torconnect-box",
+ label: "label#torconnect-label",
},
+ }),
- _torConnectBox : null,
- get TorConnectBox() {
- if (!this._torConnectBox) {
- this._torConnectBox =
- browser.ownerGlobal.document.getElementById("torconnect-box");
- }
- return this._torConnectBox;
- },
+ elements: null,
- _torConnectLabel : null,
- get TorConnectLabel() {
- if (!this._torConnectLabel) {
- this._torConnectLabel =
- browser.ownerGlobal.document.getElementById("torconnect-label");
+ 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.offline;
+ this.elements.inputContainer.setAttribute("torconnect", "offline");
+ break;
}
- return this._torConnectLabel;
- },
-
- _updateConnectionStatus(percentComplete = 0) {
- if (TorProtocolService.ownsTorDaemon &&
- !TorLauncherUtil.useLegacyLauncher) {
- if (TorProtocolService.isNetworkDisabled()) {
- if (TorProtocolService.torBootstrapErrorOccurred()) {
- this._connectionStatus = TorConnectionStatus.failure;
- } else {
- this._connectionStatus = TorConnectionStatus.offline;
- }
- } else if (percentComplete < 100) {
- this._connectionStatus = TorConnectionStatus.connecting;
- } else if (percentComplete === 100) {
- this._connectionStatus = TorConnectionStatus.connected;
- }
+ case TorConnectState.Bootstrapping: {
+ this.elements.torConnectBox.removeAttribute("hidden");
+ this.elements.torConnectLabel.textContent =
+ TorStrings.torConnect.torConnectingConcise;
+ this.elements.inputContainer.setAttribute("torconnect", "connecting");
+ break;
}
- else
- {
- this._connectionStatus = TorConnectionStatus.invalid;
+ 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;
}
-
- switch(this._connectionStatus)
- {
- case TorConnectionStatus.failure:
- case TorConnectionStatus.offline:
- this.TorConnectBox.removeAttribute("hidden");
- this.TorConnectLabel.textContent = TorStrings.torConnect.offline;
- gURLBar._inputContainer.setAttribute("torconnect", "offline");
- break;
- case TorConnectionStatus.connecting:
- this.TorConnectLabel.textContent =
- TorStrings.torConnect.torConnectingConcise;
- gURLBar._inputContainer.setAttribute("torconnect", "connecting");
- break;
- case TorConnectionStatus.connected:
- this.TorConnectLabel.textContent =
- TorStrings.torConnect.torConnectedConcise;
- gURLBar._inputContainer.setAttribute("torconnect", "connected");
- // hide torconnect box after 5 seconds
- let self = this;
- setTimeout(function() {
- self.TorConnectBox.setAttribute("hidden", "true");
- }, 5000);
- break;
+ case TorConnectState.Disabled: {
+ this.elements.torConnectBox.setAttribute("hidden", "true");
+ break;
}
- },
+ default:
+ break;
+ }
+ },
- observe(aSubject, aTopic, aData) {
+ 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,
+ })
+ Services.obs.addObserver(this, TorConnectTopics.StateChange);
+ this.observing = true;
+ this.updateTorConnectBox(TorConnect.state);
+ }
+ },
+
+ uninit: function() {
+ if (this.observing) {
+ Services.obs.removeObserver(this, TorConnectTopics.StateChange);
+ }
+ },
+};
- switch (aTopic) {
- case kTorProcessReadyTopic:
- case kTorProcessExitedTopic:
- case kTorProcessDidNotStartTopic:
- case kTorBootstrapErrorTopic:
- this._updateConnectionStatus();
- break;
- case kTorBootstrapStatusTopic:
- let percentComplete = obj.PROGRESS ? obj.PROGRESS : 0;
- this._updateConnectionStatus(percentComplete);
- break;
- }
- },
- init() {
- for (const topic of gActiveTopics) {
- Services.obs.addObserver(this, topic);
- }
- },
- uninit() {
- for (const topic of gActiveTopics) {
- Services.obs.removeObserver(this, topic);
- }
- },
- };
-}
diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js
index 01609ddda090..59ecdec6d1d9 100644
--- a/browser/components/torpreferences/content/torPane.js
+++ b/browser/components/torpreferences/content/torPane.js
@@ -6,6 +6,10 @@ const { TorProtocolService } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
+const { TorConnect } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+
const {
TorBridgeSource,
TorBridgeSettings,
@@ -188,14 +192,14 @@ const gTorPane = (function() {
this._messageBoxButton = prefpane.querySelector(selectors.messageBox.button);
// wire up connect button
this._messageBoxButton.addEventListener("click", () => {
- TorProtocolService.connect();
+ TorConnect.beginBootstrap();
let win = Services.wm.getMostRecentWindow("navigator:browser");
// switch to existing about:torconnect tab or create a new one
win.switchToTabHavingURI("about:torconnect", true);
});
let populateMessagebox = () => {
- if (TorProtocolService.shouldShowTorConnect()) {
+ if (TorConnect.shouldShowTorConnect) {
// set messagebox style and text
if (TorProtocolService.torBootstrapErrorOccurred()) {
this._messageBox.className = "error";
diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm
index f727c386701c..60b5b9163d67 100644
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -10,8 +10,8 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.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
@@ -24,7 +24,7 @@ function maybeUpdateOpenLocationForTorConnect(openUILinkWhere, currentURI, desti
// we are trying to open in same tab
openUILinkWhere === "current" &&
// only if user still has not bootstrapped
- TorProtocolService.shouldShowTorConnect() &&
+ TorConnect.shouldShowTorConnect &&
// and user is not just navigating to about:torconnect
destinationURI !== "about:torconnect") {
return "tab";
diff --git a/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm
index 3125c84558db..5d2b826cfa10 100644
--- a/browser/modules/TorConnect.jsm
+++ b/browser/modules/TorConnect.jsm
@@ -1,6 +1,6 @@
"use strict";
-var EXPORTED_SYMBOLS = ["TorConnect"];
+var EXPORTED_SYMBOLS = ["TorConnect", "TorConnectTopics", "TorConnectState"];
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm"
@@ -10,53 +10,476 @@ const { BrowserWindowTracker } = ChromeUtils.import(
"resource:///modules/BrowserWindowTracker.jsm"
);
-const { TorProtocolService } = ChromeUtils.import(
+const { TorProtocolService, TorProcessStatus } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
-// TODO: move the bootstrap state management out of each of the individual
-// about:torconnect pages and stick it here
-var TorConnect = (() => {
+const { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+);
+
+/* Browser observer topis */
+const BrowserTopics = Object.freeze({
+ ProfileAfterChange: "profile-after-change",
+});
+
+/* tor-launcher observer topics */
+const TorTopics = Object.freeze({
+ ProcessIsReady: "TorProcessIsReady",
+ BootstrapStatus: "TorBootstrapStatus",
+ BootstrapError: "TorBootstrapError",
+ ProcessExited: "TorProcessExited",
+ LogHasWarnOrErr: "TorLogHasWarnOrErr",
+});
+
+/* Relevant prefs used by tor-launcher */
+const TorLauncherPrefs = Object.freeze({
+ quickstart: "extensions.torlauncher.quickstart",
+ prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
+});
+
+const TorConnectState = Object.freeze({
+ /* Our initial state */
+ Initial: "Initial",
+ /* In-between initial boot and bootstrapping, users can change tor network settings during this state */
+ Configuring: "Configuring",
+ /* Geo-location and setting bridges/etc */
+ AutoConfiguring: "AutoConfiguring",
+ /* Tor is bootstrapping */
+ Bootstrapping: "Bootstrapping",
+ /* Passthrough state back to Configuring or Fatal */
+ Error: "Error",
+ /* An unrecoverable error */
+ FatalError: "FatalError",
+ /* Final state, after successful bootstrap */
+ Bootstrapped: "Bootstrapped",
+ /* If we are using System tor or the legacy Tor-Launcher */
+ Disabled: "Disabled",
+});
+
+/*
+
+ TorConnect State Transitions
+
+ ┌──────────────────────┐
+ │ Disabled │
+ └──────────────────────┘
+ ▲
+ │ legacyOrSystemTor()
+ │
+ ┌──────────────────────┐
+ ┌────────────────────── │ Initial │ ───────────────────────────┐
+ │ └──────────────────────┘ │
+ │ │ │
+ │ │ beginBootstrap() │
+ │ ▼ │
+┌────────────────┐ │ bootstrapComplete() ┌────────────────────────────────────────────────┐ │ beginBootstrap()
+│ Bootstrapped │ ◀──┼────────────────────── │ Bootstrapping │ ◀┼─────────────────┐
+└────────────────┘ │ └────────────────────────────────────────────────┘ │ │
+ │ │ ▲ │ │ │
+ │ │ cancelBootstrap() │ beginBootstrap() └────┼─────────────┐ │
+ │ ▼ │ │ │ │
+ │ beginConfigure() ┌────────────────────────────────────────────────┐ │ │ │
+ └─────────────────────▶ │ │ │ │ │
+ │ │ │ │ │
+ beginConfigure() │ │ │ │ │
+ ┌──────────────────────────▶ │ Configuring │ │ │ │
+ │ │ │ │ │ │
+ │ │ │ │ │ │
+ │ ┌─────────────────────▶ │ │ │ │ │
+ │ │ └────────────────────────────────────────────────┘ │ │ │
+ │ │ │ │ │ │ │
+ │ │ cancelAutoconfigure() │ autoConfigure() │ ┌────┼─────────────┼───┘
+ │ │ ▼ │ │ │ │
+ │ │ ┌──────────────────────┐ │ │ │ │
+ │ └────────────────────── │ AutoConfiguring │ ─┼────────────────────┘ │ │
+ │ └──────────────────────┘ │ │ │
+ │ │ │ │ onError() │
+ │ │ onError() │ onError() │ │
+ │ ▼ ▼ │ │
+ │ ┌────────────────────────────────────────────────┐ │ │
+ └─────────────────────────── │ Error │ ◀┘ │
+ └────────────────────────────────────────────────┘ │
+ │ ▲ onError() │
+ │ onFatalError() └──────────────────┘
+ ▼
+ ┌──────────────────────┐
+ │ FatalError │
+ └──────────────────────┘
+
+*/
+
+
+/* Maps allowed state transitions
+ TorConnectStateTransitions[state] maps to an array of allowed states to transition to
+*/
+const TorConnectStateTransitions =
+ Object.freeze(new Map([
+ [TorConnectState.Initial,
+ [TorConnectState.Disabled,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Configuring,
+ TorConnectState.Error]],
+ [TorConnectState.Configuring,
+ [TorConnectState.AutoConfiguring,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Error]],
+ [TorConnectState.AutoConfiguring,
+ [TorConnectState.Configuring,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Error]],
+ [TorConnectState.Bootstrapping,
+ [TorConnectState.Configuring,
+ TorConnectState.Bootstrapped,
+ TorConnectState.Error]],
+ [TorConnectState.Error,
+ [TorConnectState.Configuring,
+ TorConnectState.FatalError]],
+ // terminal states
+ [TorConnectState.FatalError, []],
+ [TorConnectState.Bootstrapped, []],
+ [TorConnectState.Disabled, []],
+ ]));
+
+/* Topics Notified by the TorConnect module */
+const TorConnectTopics = Object.freeze({
+ StateChange: "torconnect:state-change",
+ BootstrapProgress: "torconnect:bootstrap-progress",
+ BootstrapComplete: "torconnect:bootstrap-complete",
+ BootstrapError: "torconnect:bootstrap-error",
+ FatalError: "torconnect:fatal-error",
+});
+
+const TorConnect = (() => {
let retval = {
- init : function() {
- let topics = [
- "TorBootstrapStatus",
- ];
- for(const topic of topics) {
- Services.obs.addObserver(this, topic);
+ _state: TorConnectState.Initial,
+ _bootstrapProgress: 0,
+ _bootstrapStatus: null,
+ _errorMessage: null,
+ _errorDetails: null,
+ _logHasWarningOrError: false,
+ // init to about:tor as fallback in case setURIsToLoad is somehow never called
+ _urisToLoad: ["about:tor"],
+
+ /* These functions are called after transitioning to a new state */
+ _transitionCallbacks: Object.freeze(new Map([
+ /* Initial is never transitioned to */
+ [TorConnectState.Initial, null],
+ /* Configuring */
+ [TorConnectState.Configuring, (self) => {
+ // TODO move this to the transition function
+ if (this._state === TorConnectState.Bootstrapping) {
+ TorProtocolService.torStopBootstrap();
+ }
+ }],
+ /* AutoConfiguring */
+ [TorConnectState.AutoConfiguring, (self) => {
+
+ }],
+ /* Bootstrapping */
+ [TorConnectState.Bootstrapping, (self) => {
+ let error = TorProtocolService.connect();
+ if (error) {
+ self.onError(error.message, error.details);
+ } else {
+ self._errorMessage = self._errorDetails = null;
+ }
+ }],
+ /* Bootstrapped */
+ [TorConnectState.Bootstrapped, (self) => {
+ // open home page(s) in new tabs
+ const win = BrowserWindowTracker.getTopWindow()
+
+ let location="tab";
+ for (const uri of self._urisToLoad) {
+ win.openTrustedLinkIn(uri, location);
+ // open subsequent tabs behind first tab
+ location = "tabshifted";
+ }
+ Services.obs.notifyObservers(null, TorConnectTopics.BootstrapComplete);
+ }],
+ /* Error */
+ [TorConnectState.Error, (self, errorMessage, errorDetails, fatal) => {
+ self._errorMessage = errorMessage;
+ self._errorDetails = errorDetails;
+
+ Services.obs.notifyObservers({message: errorMessage, details: errorDetails}, TorConnectTopics.BootstrapError);
+ if (fatal) {
+ self.onFatalError();
+ } else {
+ self.beginConfigure();
+ }
+ }],
+ /* FatalError */
+ [TorConnectState.FatalError, (self) => {
+ Services.obs.notifyObservers(null, TorConnectTopics.FatalError);
+ }],
+ /* Disabled */
+ [TorConnectState.Disabled, (self) => {
+
+ }],
+ ])),
+
+ _changeState: function(newState, ...args) {
+ const oldState = this._state;
+
+ // ensure this is a valid state transition
+ if (!TorConnectStateTransitions.get(oldState)?.includes(newState)) {
+ throw Error(`TorConnect: Attempted invalid state transition from ${oldState} to ${newState}`);
}
+
+ console.log(`TorConnect: transitioning state from ${oldState} to ${newState}`);
+
+ // call our transition function and forward any args
+ this._transitionCallbacks.get(newState)(this, ...args);
+
+ // finally, set our new state
+ this._state = newState;
+
+ Services.obs.notifyObservers({state: newState}, TorConnectTopics.StateChange);
+ },
+
+ // init should be called on app-startup in MainProcessingSingleton.jsm
+ init : function() {
+ console.log("TorConnect: Init");
+
+ // delay remaining init until after profile-after-change
+ Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
},
observe: function(subject, topic, data) {
+ console.log(`TorConnect: observed ${topic}`);
+
switch(topic) {
- case "TorBootstrapStatus":
- const obj = subject?.wrappedJSObject;
- if (obj?.PROGRESS === 100) {
- // open home page(s) in new tabs
- const win = BrowserWindowTracker.getTopWindow()
- const urls = Services.prefs.getStringPref("browser.startup.homepage").split('|');
-
- let location="tab";
- for(const url of urls) {
- win.openTrustedLinkIn(url, location);
- // open subsequent tabs behind first tab
- location = "tabshifted";
+
+ /* Determine which state to move to from Initial */
+ case BrowserTopics.ProfileAfterChange: {
+ if (TorLauncherUtil.useLegacyLauncher || !TorProtocolService.ownsTorDaemon) {
+ // Disabled
+ this.legacyOrSystemTor();
+ } else {
+ // register the Tor topics we always care about
+ for (const topicKey in TorTopics) {
+ const topic = TorTopics[topicKey];
+ Services.obs.addObserver(this, topic);
+ console.log(`TorConnect: observing topic '${topic}'`);
}
- Services.obs.notifyObservers(null, "torconnect:bootstrap-complete");
+ if (TorProtocolService.torProcessStatus == TorProcessStatus.Running) {
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this.beginBootstrap();
+ } else {
+ // Configuring
+ this.beginConfigure();
+ }
+ }
}
+
+ Services.obs.removeObserver(this, topic);
break;
+ }
+ /* Transition out of Initial if Tor daemon wasn't running yet in BrowserTopics.ProfileAfterChange */
+ case TorTopics.ProcessIsReady: {
+ if (this.state === TorConnectState.Initial)
+ {
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this.beginBootstrap();
+ } else {
+ // Configuring
+ this.beginConfigure();
+ }
+ }
+ break;
+ }
+ /* Updates our bootstrap status */
+ case TorTopics.BootstrapStatus: {
+ if (this._state != TorConnectState.Bootstrapping) {
+ console.log(`TorConnect: observed ${TorTopics.BootstrapStatus} topic while in state TorConnectState.${this._state}`);
+ break;
+ }
+
+ const obj = subject?.wrappedJSObject;
+ if (obj) {
+ this._bootstrapProgress= obj.PROGRESS;
+ this._bootstrapStatus = TorLauncherUtil.getLocalizedBootstrapStatus(obj, "TAG");
+
+ console.log(`TorConnect: Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`);
+ Services.obs.notifyObservers({
+ progress: this._bootstrapProgress,
+ status: this._bootstrapStatus,
+ hasWarnings: this._logHasWarningOrError
+ }, TorConnectTopics.BootstrapProgress);
+
+ if (this._bootstrapProgress === 100) {
+ this.bootstrapComplete();
+ }
+ }
+ break;
+ }
+ /* Handle bootstrap error*/
+ case TorTopics.BootstrapError: {
+ const obj = subject?.wrappedJSObject;
+ TorProtocolService.torStopBootstrap();
+ this.onError(obj.message, obj.details);
+ break;
+ }
+ case TorTopics.LogHasWarnOrErr: {
+ this._logHasWarningOrError = true;
+ break;
+ }
default:
// ignore
break;
}
},
- shouldShowTorConnect : function() {
- return TorProtocolService.shouldShowTorConnect();
+ /*
+ Various getters
+ */
+
+ get shouldShowTorConnect() {
+ // TorBrowser must control the daemon
+ return (TorProtocolService.ownsTorDaemon &&
+ // and we're not using the legacy launcher
+ !TorLauncherUtil.useLegacyLauncher &&
+ // legacy checks, TODO: maybe this should be in terms of our own state?
+ (TorProtocolService.isNetworkDisabled() || !TorProtocolService.isBootstrapDone()));
+ },
+
+ get shouldQuickStart() {
+ // quickstart must be enabled
+ return Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false) &&
+ // and the previous bootstrap attempt must have succeeded
+ !Services.prefs.getBoolPref(TorLauncherPrefs.prompt_at_startup, true);
+ },
+
+ get state() {
+ return this._state;
+ },
+
+ get bootstrapProgress() {
+ return this._bootstrapProgress;
+ },
+
+ get bootstrapStatus() {
+ return this._bootstrapStatus;
+ },
+
+ get errorMessage() {
+ return this._errorMessage;
+ },
+
+ get errorDetails() {
+ return this._errorDetails;
+ },
+
+ get logHasWarningOrError() {
+ return this._logHasWarningOrError;
+ },
+
+ /*
+ These functions tell TorConnect to transition states
+ */
+
+ legacyOrSystemTor: function() {
+ console.log("TorConnect: legacyOrSystemTor()");
+ this._changeState(TorConnectState.Disabled);
+ },
+
+ beginBootstrap: function() {
+ console.log("TorConnect: beginBootstrap()");
+ this._changeState(TorConnectState.Bootstrapping);
+ },
+
+ beginConfigure: function() {
+ console.log("TorConnect: beginConfigure()");
+ this._changeState(TorConnectState.Configuring);
+ },
+
+ autoConfigure: function() {
+ console.log("TorConnect: autoConfigure()");
+ // TODO: implement
+ throw Error("TorConnect: not implemented");
+ },
+
+ cancelAutoConfigure: function() {
+ console.log("TorConnect: cancelAutoConfigure()");
+ // TODO: implement
+ throw Error("TorConnect: not implemented");
+ },
+
+ cancelBootstrap: function() {
+ console.log("TorConnect: cancelBootstrap()");
+ this._changeState(TorConnectState.Configuring);
+ },
+
+ bootstrapComplete: function() {
+ console.log("TorConnect: bootstrapComplete()");
+ this._changeState(TorConnectState.Bootstrapped);
+ },
+
+ onError: function(message, details) {
+ console.log("TorConnect: onError()");
+ this._changeState(TorConnectState.Error, message, details, false);
+ },
+
+ onFatalError: function() {
+ console.log("TorConnect: onFatalError()");
+ // TODO: implement
+ throw Error("TorConnect: not implemented");
+ },
+
+ /*
+ Further external commands and helper methods
+ */
+ openTorPreferences: function() {
+ const win = BrowserWindowTracker.getTopWindow()
+ win.openTrustedLinkIn("about:preferences#tor", "tab");
+ },
+
+ copyTorLogs: function() {
+ // Copy tor log messages to the system clipboard.
+ const chSvc = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
+ Ci.nsIClipboardHelper
+ );
+ const countObj = { value: 0 };
+ chSvc.copyString(TorProtocolService.getLog(countObj));
+ const count = countObj.value;
+ return TorLauncherUtil.getFormattedLocalizedString(
+ "copiedNLogMessagesShort",
+ [count],
+ 1
+ );
+ },
+
+ // called from browser.js on browser startup, passed in either the user's homepage(s)
+ // or uris passed via command-line
+ setURIsToLoad: function(uriVariant) {
+ // convert the object we get from browser.js
+ let uris = ((v) => {
+ if (v instanceof Ci.nsIArray) {
+ // Transform the nsIArray of nsISupportsString's into a JS Array of
+ // JS strings.
+ return Array.from(
+ v.enumerate(Ci.nsISupportsString),
+ supportStr => supportStr.data
+ );
+ } else if (v instanceof Ci.nsISupportsString) {
+ return [v.data];
+ } else if (typeof v === "string") {
+ return v.split("|");
+ }
+ // about:tor as safe fallback
+ return ["about:tor"];
+ })(uriVariant);
+
+ console.log(`TorConnect: will load after bootstrap => ${uris.join(", ")}`);
+ this._urisToLoad = uris;
},
};
retval.init();
return retval;
-})(); /* TorConnect */
\ No newline at end of file
+})(); /* TorConnect */
diff --git a/browser/modules/TorProtocolService.jsm b/browser/modules/TorProtocolService.jsm
index fc7f2c884aa2..e6c78b9a0eb1 100644
--- a/browser/modules/TorProtocolService.jsm
+++ b/browser/modules/TorProtocolService.jsm
@@ -2,26 +2,59 @@
"use strict";
-var EXPORTED_SYMBOLS = ["TorProtocolService"];
+var EXPORTED_SYMBOLS = ["TorProtocolService", "TorProcessStatus"];
-const { TorLauncherUtil } = ChromeUtils.import(
- "resource://torlauncher/modules/tl-util.jsm"
+const { Services } = ChromeUtils.import(
+ "resource://gre/modules/Services.jsm"
);
-var TorProtocolService = {
- _tlps: Cc["@torproject.org/torlauncher-protocol-service;1"].getService(
- Ci.nsISupports
- ).wrappedJSObject,
+// see tl-process.js
+const TorProcessStatus = Object.freeze({
+ Unknown: 0,
+ Starting: 1,
+ Running: 2,
+ Exited: 3,
+});
+
+/* Browser observer topis */
+const BrowserTopics = Object.freeze({
+ ProfileAfterChange: "profile-after-change",
+});
- _tlproc: Cc["@torproject.org/torlauncher-process-service;1"].getService(
- Ci.nsISupports
- ).wrappedJSObject,
+var TorProtocolService = {
+ _TorLauncherUtil: function() {
+ let { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+ );
+ return TorLauncherUtil;
+ }(),
+ _TorLauncherProtocolService: null,
+ _TorProcessService: null,
// maintain a map of tor settings set by Tor Browser so that we don't
// repeatedly set the same key/values over and over
// this map contains string keys to primitive or array values
_settingsCache: new Map(),
+ init() {
+ Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
+ },
+
+ observe(subject, topic, data) {
+ if (topic === BrowserTopics.ProfileAfterChange) {
+ // we have to delay init'ing this or else the crypto service inits too early without a profile
+ // which breaks the password manager
+ this._TorLauncherProtocolService = Cc["@torproject.org/torlauncher-protocol-service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject;
+ this._TorProcessService = Cc["@torproject.org/torlauncher-process-service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject,
+
+ Services.obs.removeObserver(this, topic);
+ }
+ },
+
_typeof(aValue) {
switch (typeof aValue) {
case "boolean":
@@ -124,7 +157,7 @@ var TorProtocolService = {
}
let errorObject = {};
- if (!this._tlps.TorSetConfWithReply(settingsObject, errorObject)) {
+ if (!this._TorLauncherProtocolService.TorSetConfWithReply(settingsObject, errorObject)) {
throw new Error(errorObject.details);
}
@@ -137,8 +170,8 @@ var TorProtocolService = {
_readSetting(aSetting) {
this._assertValidSettingKey(aSetting);
- let reply = this._tlps.TorGetConf(aSetting);
- if (this._tlps.TorCommandSucceeded(reply)) {
+ let reply = this._TorLauncherProtocolService.TorGetConf(aSetting);
+ if (this._TorLauncherProtocolService.TorCommandSucceeded(reply)) {
return reply.lineArray;
}
throw new Error(reply.lineArray.join("\n"));
@@ -207,22 +240,22 @@ var TorProtocolService = {
getLog(countObj) {
countObj = countObj || { value: 0 };
- let torLog = this._tlps.TorGetLog(countObj);
+ let torLog = this._TorLauncherProtocolService.TorGetLog(countObj);
return torLog;
},
// true if we launched and control tor, false if using system tor
get ownsTorDaemon() {
- return TorLauncherUtil.shouldStartAndOwnTor;
+ return this._TorLauncherUtil.shouldStartAndOwnTor;
},
// Assumes `ownsTorDaemon` is true
isNetworkDisabled() {
- const reply = TorProtocolService._tlps.TorGetConfBool(
+ const reply = TorProtocolService._TorLauncherProtocolService.TorGetConfBool(
"DisableNetwork",
true
);
- if (TorProtocolService._tlps.TorCommandSucceeded(reply)) {
+ if (TorProtocolService._TorLauncherProtocolService.TorCommandSucceeded(reply)) {
return reply.retVal;
}
return true;
@@ -232,22 +265,22 @@ var TorProtocolService = {
let settings = {};
settings.DisableNetwork = false;
let errorObject = {};
- if (!this._tlps.TorSetConfWithReply(settings, errorObject)) {
+ if (!this._TorLauncherProtocolService.TorSetConfWithReply(settings, errorObject)) {
throw new Error(errorObject.details);
}
},
sendCommand(cmd) {
- return this._tlps.TorSendCommand(cmd);
+ return this._TorLauncherProtocolService.TorSendCommand(cmd);
},
retrieveBootstrapStatus() {
- return this._tlps.TorRetrieveBootstrapStatus();
+ return this._TorLauncherProtocolService.TorRetrieveBootstrapStatus();
},
_GetSaveSettingsErrorMessage(aDetails) {
try {
- return TorLauncherUtil.getSaveSettingsErrorMessage(aDetails);
+ return this._TorLauncherUtil.getSaveSettingsErrorMessage(aDetails);
} catch (e) {
console.log("GetSaveSettingsErrorMessage error", e);
return "Unexpected Error";
@@ -258,7 +291,7 @@ var TorProtocolService = {
let result = false;
const error = {};
try {
- result = this._tlps.TorSetConfWithReply(settings, error);
+ result = this._TorLauncherProtocolService.TorSetConfWithReply(settings, error);
} catch (e) {
console.log("TorSetConfWithReply error", e);
error.details = this._GetSaveSettingsErrorMessage(e.message);
@@ -267,23 +300,15 @@ var TorProtocolService = {
},
isBootstrapDone() {
- return this._tlproc.mIsBootstrapDone;
+ return this._TorProcessService.mIsBootstrapDone;
},
clearBootstrapError() {
- return this._tlproc.TorClearBootstrapError();
- },
-
- shouldShowTorConnect() {
- return (
- this.ownsTorDaemon &&
- !TorLauncherUtil.useLegacyLauncher &&
- (this.isNetworkDisabled() || !this.isBootstrapDone())
- );
+ return this._TorProcessService.TorClearBootstrapError();
},
torBootstrapErrorOccurred() {
- return this._tlproc.TorBootstrapErrorOccurred;
+ return this._TorProcessService.TorBootstrapErrorOccurred;
},
// Resolves to null if ok, or an error otherwise
@@ -306,7 +331,7 @@ var TorProtocolService = {
},
torLogHasWarnOrErr() {
- return this._tlps.TorLogHasWarnOrErr;
+ return this._TorLauncherProtocolService.TorLogHasWarnOrErr;
},
torStopBootstrap() {
@@ -327,4 +352,12 @@ var TorProtocolService = {
}
this.retrieveBootstrapStatus();
},
+
+ get torProcessStatus() {
+ if (this._TorProcessService) {
+ return this._TorProcessService.TorProcessStatus;
+ }
+ return TorProcessStatus.Unknown;
+ },
};
+TorProtocolService.init();
\ No newline at end of file
diff --git a/toolkit/components/processsingleton/MainProcessSingleton.jsm b/toolkit/components/processsingleton/MainProcessSingleton.jsm
index db1e2dc8f568..ea9288dccbb3 100644
--- a/toolkit/components/processsingleton/MainProcessSingleton.jsm
+++ b/toolkit/components/processsingleton/MainProcessSingleton.jsm
@@ -24,6 +24,11 @@ MainProcessSingleton.prototype = {
null
);
+ ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm",
+ null
+ );
+
// Load this script early so that console.* is initialized
// before other frame scripts.
Services.mm.loadFrameScript(
diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm
index 0927391c2ba7..54230e1175ec 100644
--- a/toolkit/modules/RemotePageAccessManager.jsm
+++ b/toolkit/modules/RemotePageAccessManager.jsm
@@ -181,28 +181,18 @@ let RemotePageAccessManager = {
RPMRemoveMessageListener: ["*"],
},
"about:torconnect": {
- RPMAddMessageListener: ["*"],
+ RPMAddMessageListener: [
+ "torconnect:state-change",
+ ],
RPMSendAsyncMessage: [
- "OpenTorAdvancedPreferences",
- "TorRetrieveBootstrapStatus",
- "TorStopBootstrap",
+ "torconnect:open-tor-preferences",
+ "torconnect:begin-bootstrap",
+ "torconnect:cancel-bootstrap",
+ "torconnect:set-quickstart",
],
RPMSendQuery: [
- "GetDirection",
- "GetLocalizedBootstrapStatus",
- "GetTorStrings",
- "TorBootstrapErrorOccurred",
- "TorConnect",
- "TorCopyLog",
- "TorIsNetworkDisabled",
- "TorLogHasWarnOrErr",
- ],
- RPMGetBoolPref: [
- "extensions.torlauncher.quickstart",
- "extensions.torlauncher.prompt_at_startup",
- ],
- RPMSetBoolPref: [
- "extensions.torlauncher.quickstart",
+ "torconnect:get-init-args",
+ "torconnect:copy-tor-logs",
],
},
},
[View Less]
1
0