commit 88dec4535bc8e81dc7fa66495f0a9a78ce7a2988
parent c066854822a1004258ae85aa2d9a5a65cb660592
Author: Pier Angelo Vendrame <pierov@torproject.org>
Date: Mon, 13 Mar 2023 11:16:32 +0100
TB 41668: Tweaks to the Base Browser updater for Tor Browser
This commit was once part of "Bug 4234: Use the Firefox Update Process
for Tor Browser.".
However, some parts of it were not needed for Base Browser and some
derivative browsers.
Therefore, we extracted from that commit the parts for Tor Browser
legacy, and we add them back to the patch set with this commit.
Diffstat:
12 files changed, 211 insertions(+), 19 deletions(-)
diff --git a/browser/components/BrowserContentHandler.sys.mjs b/browser/components/BrowserContentHandler.sys.mjs
@@ -46,7 +46,7 @@ ChromeUtils.defineLazyGetter(lazy, "gWindowsAlertsService", () => {
});
const FORK_VERSION_PREF =
- "browser.startup.homepage_override.basebrowser.version";
+ "browser.startup.homepage_override.torbrowser.version";
// One-time startup homepage override configurations
const ONCE_DOMAINS = new Set(["mozilla.org", "firefox.com"]);
diff --git a/config/createprecomplete.py b/config/createprecomplete.py
@@ -8,10 +8,18 @@
import os
+# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
+# we should remove all lines in this file that contain:
+# TorBrowser/Data
+
def get_build_entries(root_path):
"""Iterates through the root_path, creating a list for each file and
directory. Excludes any file paths ending with channel-prefs.js.
+ To support Tor Browser updates, excludes:
+ TorBrowser/Data/Browser/profiles.ini
+ TorBrowser/Data/Browser/profile.default/bookmarks.html
+ TorBrowser/Data/Tor/torrc
"""
rel_file_path_set = set()
rel_dir_path_set = set()
@@ -28,6 +36,10 @@ def get_build_entries(root_path):
or "/UpdateSettings.framework/" in rel_path_file
or rel_path_file.startswith("UpdateSettings.framework/")
or "distribution/" in rel_path_file
+ or rel_path_file == "TorBrowser/Data/Browser/profiles.ini"
+ or rel_path_file
+ == "TorBrowser/Data/Browser/profile.default/bookmarks.html"
+ or rel_path_file == "TorBrowser/Data/Tor/torrc"
):
rel_file_path_set.add(rel_path_file)
diff --git a/toolkit/components/urlformatter/URLFormatter.sys.mjs b/toolkit/components/urlformatter/URLFormatter.sys.mjs
@@ -137,6 +137,13 @@ nsURLFormatterService.prototype = {
BB_VERSION() {
return AppConstants.BASE_BROWSER_VERSION;
},
+ BB_VERSION_FOR_URLS() {
+ let version = AppConstants.BASE_BROWSER_VERSION;
+ if (/^[0-9a\.]+$/.test(version)) {
+ version = version.replaceAll(".", "");
+ }
+ return version;
+ },
},
formatURL: function uf_formatURL(aFormat) {
diff --git a/toolkit/mozapps/extensions/AddonManager.sys.mjs b/toolkit/mozapps/extensions/AddonManager.sys.mjs
@@ -39,7 +39,7 @@ const PREF_GLEAN_PING_ADDONS_UPDATED_IDLE_TIMEOUT_MS =
"extensions.gleanPingAddons.updated.idleTimeout";
const PREF_GLEAN_PING_ADDONS_UPDATED_TESTING =
"extensions.gleanPingAddons.updated.testing";
-const PREF_EM_LAST_FORK_VERSION = "extensions.lastBaseBrowserVersion";
+const PREF_EM_LAST_FORK_VERSION = "extensions.lastTorBrowserVersion";
const PREF_MIN_WEBEXT_PLATFORM_VERSION =
"extensions.webExtensionsMinPlatformVersion";
diff --git a/toolkit/mozapps/update/UpdateService.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs
@@ -22,6 +22,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs",
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
+ TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
UpdateLog: "resource://gre/modules/UpdateLog.sys.mjs",
UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs",
WindowsRegistry: "resource://gre/modules/WindowsRegistry.sys.mjs",
@@ -243,6 +244,7 @@ const SERVICE_ERRORS = [
// Custom update error codes
const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
const NETWORK_ERROR_OFFLINE = 111;
+const PROXY_SERVER_CONNECTION_REFUSED = 2152398920;
// Error codes should be < 1000. Errors above 1000 represent http status codes
const HTTP_ERROR_OFFSET = 1000;
@@ -365,6 +367,15 @@ export function testResetIsBackgroundTaskMode() {
resetIsBackgroundTaskMode();
}
+async function _shouldRegisterBootstrapObserver() {
+ try {
+ const provider = await lazy.TorProviderBuilder.build();
+ return !provider.isBootstrapDone && provider.ownsTorDaemon;
+ } catch {
+ return false;
+ }
+}
+
/**
* Changes `nsIApplicationUpdateService.currentState` and causes
* `nsIApplicationUpdateService.stateTransition` to resolve.
@@ -2808,6 +2819,9 @@ export class UpdateService {
case "network:offline-status-changed":
await this._offlineStatusChanged(data);
break;
+ case "torconnect:bootstrap-complete":
+ this._bootstrapComplete();
+ break;
case "quit-application":
Services.obs.removeObserver(this, topic);
@@ -3421,6 +3435,35 @@ export class UpdateService {
await this._attemptResume();
}
+ _registerBootstrapObserver() {
+ if (this._registeredBootstrapObserver) {
+ LOG(
+ "UpdateService:_registerBootstrapObserver - observer already registered"
+ );
+ return;
+ }
+
+ LOG(
+ "UpdateService:_registerBootstrapObserver - waiting for tor bootstrap " +
+ "to be complete, then forcing another check"
+ );
+
+ Services.obs.addObserver(this, "torconnect:bootstrap-complete");
+ this._registeredBootstrapObserver = true;
+ }
+
+ _bootstrapComplete() {
+ Services.obs.removeObserver(this, "torconnect:bootstrap-complete");
+ this._registeredBootstrapObserver = false;
+
+ LOG(
+ "UpdateService:_bootstrapComplete - bootstrapping complete, forcing " +
+ "another background check"
+ );
+
+ this._attemptResume();
+ }
+
/**
* See nsIUpdateService.idl
*/
@@ -3454,6 +3497,14 @@ export class UpdateService {
AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_OFFLINE);
}
return;
+ } else if (
+ update.errorCode === PROXY_SERVER_CONNECTION_REFUSED &&
+ (await _shouldRegisterBootstrapObserver())
+ ) {
+ // Register boostrap observer to try again, but only when we own the
+ // tor process.
+ this._registerBootstrapObserver();
+ return;
}
// Send the error code to telemetry
@@ -6909,6 +6960,7 @@ class Downloader {
var state = this._patch.state;
var shouldShowPrompt = false;
var shouldRegisterOnlineObserver = false;
+ var shouldRegisterBootstrapObserver = false;
var shouldRetrySoon = false;
var deleteActiveUpdate = false;
let migratedToReadyUpdate = false;
@@ -7039,7 +7091,23 @@ class Downloader {
);
shouldRegisterOnlineObserver = true;
deleteActiveUpdate = false;
-
+ } else if (
+ status === PROXY_SERVER_CONNECTION_REFUSED &&
+ (await _shouldRegisterBootstrapObserver())
+ ) {
+ // Register a bootstrap observer to try again.
+ // The bootstrap observer will continue the incremental download by
+ // calling downloadUpdate on the active update which continues
+ // downloading the file from where it was.
+ LOG(
+ "Downloader:onStopRequest - not bootstrapped, register bootstrap observer: true"
+ );
+ AUSTLMY.pingDownloadCode(
+ this.isCompleteUpdate,
+ AUSTLMY.DWNLD_RETRY_OFFLINE
+ );
+ shouldRegisterBootstrapObserver = true;
+ deleteActiveUpdate = false;
// Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED,
// NS_ERROR_NET_RESET and NS_ERROR_DOCUMENT_NOT_CACHED can be returned
// when disconnecting the internet while a download of a MAR is in
@@ -7162,7 +7230,11 @@ class Downloader {
// Only notify listeners about the stopped state if we
// aren't handling an internal retry.
- if (!shouldRetrySoon && !shouldRegisterOnlineObserver) {
+ if (
+ !shouldRetrySoon &&
+ !shouldRegisterOnlineObserver &&
+ !shouldRegisterBootstrapObserver
+ ) {
this.updateService.forEachDownloadListener(listener => {
listener.onStopRequest(request, status);
});
@@ -7358,6 +7430,9 @@ class Downloader {
if (shouldRegisterOnlineObserver) {
LOG("Downloader:onStopRequest - Registering online observer");
this.updateService._registerOnlineObserver();
+ } else if (shouldRegisterBootstrapObserver) {
+ LOG("Downloader:onStopRequest - Registering bootstrap observer");
+ this.updateService._registerBootstrapObserver();
} else if (shouldRetrySoon) {
LOG("Downloader:onStopRequest - Retrying soon");
this.updateService._consecutiveSocketErrors++;
diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp
@@ -2794,11 +2794,11 @@ static bool IsServiceSpecificErrorCode(int errorCode) {
static int CopyInstallDirToDestDir() {
// These files should not be copied over to the updated app
#ifdef XP_WIN
-# define SKIPLIST_COUNT 3
+# define SKIPLIST_COUNT 5
#elif XP_MACOSX
# define SKIPLIST_COUNT 0
#else
-# define SKIPLIST_COUNT 2
+# define SKIPLIST_COUNT 4
#endif
copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
#ifndef XP_MACOSX
@@ -2809,6 +2809,21 @@ static int CopyInstallDirToDestDir() {
# endif
#endif
+ // Remove the following block if we move the profile outside the Browser
+ // directory.
+#if defined(BASE_BROWSER_UPDATE) && !defined(XP_MACOSX)
+# ifdef XP_WIN
+ skiplist.append(SKIPLIST_COUNT - 2, gInstallDirPath,
+ NS_T("TorBrowser/Data/Browser/profile.default/parent.lock"));
+# else
+ skiplist.append(SKIPLIST_COUNT - 2, gInstallDirPath,
+ NS_T("TorBrowser/Data/Browser/profile.default/.parentlock"));
+# endif
+
+ skiplist.append(SKIPLIST_COUNT - 1, gInstallDirPath,
+ NS_T("TorBrowser/Data/Tor/lock"));
+#endif
+
return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist);
}
@@ -3230,7 +3245,7 @@ int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv
#endif
if (argc > kCallbackIndex) {
-#if defined(XP_WIN)
+#if defined(XP_WIN) && !defined(TOR_BROWSER)
if (gSucceeded) {
LOG(("Launching Windows post update process"));
if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) {
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
@@ -3586,7 +3586,7 @@ static bool CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
nsAutoCString buf;
nsAutoCString forkVersion(BASE_BROWSER_VERSION_QUOTED);
- rv = parser.GetString("Compatibility", "LastBaseBrowserVersion", buf);
+ rv = parser.GetString("Compatibility", "LastTorBrowserVersion", buf);
if (NS_FAILED(rv) || !forkVersion.Equals(buf)) return false;
rv = parser.GetString("Compatibility", "LastOSABI", buf);
@@ -3670,7 +3670,7 @@ static void WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
nsAutoCString forkVersion(BASE_BROWSER_VERSION_QUOTED);
static const char kForkVersionHeader[] =
- NS_LINEBREAK "LastBaseBrowserVersion=";
+ NS_LINEBREAK "LastTorBrowserVersion=";
PR_Write(fd, kForkVersionHeader, sizeof(kForkVersionHeader) - 1);
PR_Write(fd, forkVersion.get(), forkVersion.Length());
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
@@ -987,18 +987,19 @@ nsresult nsXREDirProvider::GetUpdateRootDir(nsIFile** aResult,
// UpdateInfo directory under the user data directory.
# if defined(ANDROID)
# error "The Base Browser updater is not supported on Android."
-# elif defined(XP_MACOSX)
- rv = GetUserDataDirectory(getter_AddRefs(updRoot), false);
+# endif
+ nsCOMPtr<nsIFile> dataDir;
+ rv = GetUserDataDirectoryHome(getter_AddRefs(dataDir), false);
NS_ENSURE_SUCCESS(rv, rv);
-# else
- bool isPortable = true;
- rv = GetIsPortableMode(&isPortable);
+ rv = dataDir->GetParent(getter_AddRefs(updRoot));
NS_ENSURE_SUCCESS(rv, rv);
- if (isPortable) {
- rv = GetUserDataDirectoryHome(getter_AddRefs(updRoot), false);
- } else {
- rv = GetUserDataDirectory(getter_AddRefs(updRoot), true);
- }
+# if !defined(XP_MACOSX)
+ // For Tor Browser, the profile directory is TorBrowser/Data/Browser.
+ // Updates used to be in TorBrowser/updateInfo, so go up two directories.
+ // If we switch to data directory outside also on Windows and on Linux, we
+ // should remove this block.
+ dataDir = updRoot;
+ rv = dataDir->GetParent(getter_AddRefs(updRoot));
NS_ENSURE_SUCCESS(rv, rv);
# endif
rv = updRoot->AppendNative("UpdateInfo"_ns);
diff --git a/tools/update-packaging/common.sh b/tools/update-packaging/common.sh
@@ -8,6 +8,10 @@
# Author: Darin Fisher
#
+# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
+# we should remove all lines in this file that contain:
+# TorBrowser/Data
+
# -----------------------------------------------------------------------------
QUIET=0
@@ -170,6 +174,10 @@ append_remove_instructions() {
# List all files in the current directory, stripping leading "./"
# Pass a variable name and it will be filled as an array.
+# To support Tor Browser updates, skip the following files:
+# TorBrowser/Data/Browser/profiles.ini
+# TorBrowser/Data/Browser/profile.default/bookmarks.html
+# TorBrowser/Data/Tor/torrc
list_files() {
count=0
temp_filelist=$(mktemp)
@@ -180,6 +188,11 @@ list_files() {
| sed 's/\.\/\(.*\)/\1/' \
| sort -r > "${temp_filelist}"
while read file; do
+ if [ "$file" = "TorBrowser/Data/Browser/profiles.ini" -o \
+ "$file" = "TorBrowser/Data/Browser/profile.default/bookmarks.html" -o \
+ "$file" = "TorBrowser/Data/Tor/torrc" ]; then
+ continue;
+ fi
eval "${1}[$count]=\"$file\""
(( count++ ))
done < "${temp_filelist}"
diff --git a/tools/update-packaging/make_full_update.sh b/tools/update-packaging/make_full_update.sh
@@ -81,6 +81,21 @@ notice "Adding type instruction to update manifests"
notice " type complete"
echo "type \"complete\"" >> "$updatemanifestv3"
+# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
+# we should remove the following lines:
+# If removal of any old, existing directories is desired, emit the appropriate
+# rmrfdir commands.
+notice ""
+notice "Adding directory removal instructions to update manifests"
+for dir_to_remove in $directories_to_remove; do
+ # rmrfdir requires a trailing slash; if slash is missing, add one.
+ if ! [[ "$dir_to_remove" =~ /$ ]]; then
+ dir_to_remove="${dir_to_remove}/"
+ fi
+ echo "rmrfdir \"$dir_to_remove\"" >> "$updatemanifestv3"
+done
+# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
notice ""
notice "Adding file add instructions to update manifests"
num_files=${#files[*]}
diff --git a/tools/update-packaging/make_incremental_update.sh b/tools/update-packaging/make_incremental_update.sh
@@ -79,6 +79,8 @@ if [ $# = 0 ]; then
fi
requested_forced_updates='Contents/MacOS/firefox'
+directories_to_remove=""
+extra_files_to_remove=""
while getopts "hqf:" flag
do
@@ -114,6 +116,28 @@ workdir="$(mktemp -d)"
updatemanifestv3="$workdir/updatev3.manifest"
archivefiles="updatev3.manifest"
+# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
+# we should remove the following lines:
+# If the NoScript extension has changed between
+# releases, add it to the "force updates" list.
+ext_path='TorBrowser/Data/Browser/profile.default/extensions'
+if [ -d "$newdir/$ext_path" ]; then
+ noscript='{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi'
+
+ # NoScript is a packed extension, so we simply compare the old and the new
+ # .xpi files.
+ noscript_path="$ext_path/$noscript"
+ diff -a "$olddir/$noscript_path" "$newdir/$noscript_path" > /dev/null
+ rc=$?
+ if [ $rc -gt 1 ]; then
+ notice "Unexpected exit $rc from $noscript_path diff command"
+ exit 2
+ elif [ $rc -eq 1 ]; then
+ requested_forced_updates="$requested_forced_updates $noscript_path"
+ fi
+fi
+# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
mkdir -p "$workdir"
# Generate a list of all files in the target directory.
@@ -151,6 +175,22 @@ notice "Adding type instruction to update manifests"
notice " type partial"
echo "type \"partial\"" >> $updatemanifestv3
+# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
+# we should remove the following lines:
+# If removal of any old, existing directories is desired, emit the appropriate
+# rmrfdir commands.
+notice ""
+notice "Adding directory removal instructions to update manifests"
+for dir_to_remove in $directories_to_remove; do
+ # rmrfdir requires a trailing slash, so add one if missing.
+ if ! [[ "$dir_to_remove" =~ /$ ]]; then
+ dir_to_remove="${dir_to_remove}/"
+ fi
+ echo "rmrfdir \"$dir_to_remove\"" >> "$updatemanifestv3"
+done
+# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
+
notice ""
notice "Adding file patch and add instructions to update manifests"
@@ -286,6 +326,14 @@ notice ""
notice "Adding file and directory remove instructions from file 'removed-files'"
append_remove_instructions "$newdir" "$updatemanifestv3"
+# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
+# we should remove the following lines:
+for f in $extra_files_to_remove; do
+ notice " remove \"$f\""
+ echo "remove \"$f\"" >> "$updatemanifestv3"
+done
+# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
notice ""
notice "Adding directory remove instructions for directories that no longer exist"
num_olddirs=${#olddirs[*]}
diff --git a/widget/gtk/WidgetUtilsGtk.cpp b/widget/gtk/WidgetUtilsGtk.cpp
@@ -160,6 +160,12 @@ void SetLastPointerDownEvent(GdkEvent* aEvent) {
bool IsRunningUnderSnap() { return !!GetSnapInstanceName(); }
bool IsRunningUnderFlatpak() {
+ // tor-browser#42293: Don't disable updater when run by torbrowser-launcher
+ // flatpak
+ const char* torbrowserLauncher = g_getenv("TORBROWSER_LAUNCHER");
+ if (torbrowserLauncher) {
+ return false;
+ }
// https://gitlab.gnome.org/GNOME/gtk/-/blob/4300a5c609306ce77cbc8a3580c19201dccd8d13/gdk/gdk.c#L472
static bool sRunning = [] {
return g_file_test("/.flatpak-info", G_FILE_TEST_EXISTS);